Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Type System Tricks for the Real World

Type System Tricks for the Real World

Have you ever looked at some of the more exotic capabilities of Rust's type system and wondered “why”? Why on earth would I ever want a zero sized type? How do I efficiently implement a deeply recursive type? Just what do monomorphization and type erasure actually mean?

In this talk we'll look at some real world examples from inside Diesel to answer these questions and more. You'll come away from this talk with a stronger understanding of how to use Rust's generics, traits, and exotically sized types.

0f674817f8c6e149518f0a4b4ad3d560?s=128

Sean Griffin

August 19, 2017
Tweet

Transcript

  1. Type System Tricks for the Real World

  2. fn main() { break rust; // Can you read this

    color scheme? }
  3. Who am I? • Sean Griffin • 10x Hacker Ninja

    Guru at Shopify • Rails Committer • Maintainer of Active Record • Creator of Diesel • Bikeshed co-host
  4. None
  5. None
  6. Programming is full of trade-offs

  7. Haskell • Pros • Expressive type system • Cons •

    No control over data layout
  8. C • Pros • Tight control over data layout •

    Cons • "type" system
  9. None
  10. Rust's Fireflower

  11. Rust's Fireflower

  12. Rust's Fireflower

  13. pub struct HashSet<K> { map: HashMap<K, ()> } impl<K: Hash

    + Eq> HashSet<K> { pub fn insert(&mut self, value: K) { self.map.insert(value, ()); } pub fn contains(&self, value: &K) -> bool { self.map.contains_key(value) } }
  14. class Set def initialize @hash = {} end def insert(value)

    @hash[value] = true end def contains(value) @hash.key?(value) end end
  15. char

  16. struct Foo { bar: char, }

  17. struct Foo { bar: char, baz: char, }

  18. enum Foo { Bar(char), }

  19. enum Foo { Bar(char), Baz, }

  20. struct Baz;

  21. enum Foo { Bar(char), Baz, }

  22. enum Foo { Bar(char), Baz(u64), }

  23. enum ListString { Cons { head: char, tail: ListString, },

    Nil, }
  24. enum ListString { Cons { head: char, tail: ListString, },

    Nil, }
  25. enum ListString { Cons { head: char, tail: ListString, },

    Nil, }
  26. enum ListString { Cons { head: char, tail: ListString, },

    Nil, }
  27. enum ListString { Cons { head: char, tail: ListString, },

    Nil, }
  28. error[E0072]: recursive type `ListString` has infinite size --> src/main.rs:1:1 |

    1 | enum ListString { | ^^^^^^^^^^^^^^^ recursive type has infinite size ... 4 | tail: ListString, | ---------------- recursive without indirection | = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ListString` representable
  29. enum ListString { Cons { head: char, tail: ListString, },

    Nil, }
  30. enum ListString { Cons { head: char, tail: Box<ListString>, },

    Nil, }
  31. pub struct Cons<Tail> { head: char, tail: Tail, } pub

    struct Nil;
  32. struct Pizza<Topping> { topping: Topping }

  33. struct Pinapple; struct Pizza<Topping> { topping: Topping } size_of::<Pizza<Pinapple>>()

  34. struct Pinapple; struct Pizza<Topping> { topping: Topping } size_of::<Pizza<Pinapple>>() //

    => Error: // Pineapple doesn't go on pizza, Steve. Fite me.
  35. struct Pizza<Topping> { topping: Topping } size_of::<Pizza<u8>>()

  36. pub struct Cons<Tail> { head: char, tail: Tail, } pub

    struct Nil;
  37. Nil

  38. Cons<Nil>

  39. Cons<Cons<Nil>>

  40. Cons<Cons<Cons<Nil>> >

  41. pub struct Cons<Tail> { head: char, tail: Tail, } pub

    struct Nil;
  42. This isn't without tradeoffs

  43. fn do_stuff_with_string(s: ListString) { // doing stuff! }

  44. fn do_stuff_with_string<T: ListString>(s: T) { // doing stuff! }

  45. fn string_contains_a(s: ListString) -> bool { match s { Cons

    { head: 'a', .. } => true, Cons { tail, .. } => string_contains_a(tail), Nil => false, } }
  46. fn string_contains_a<T: ListString>(s: T) -> bool { match s.unpack() {

    Some(('a', _)) => true, Some((_, tail)) => string_contains_a(tail), None => false, } }
  47. None
  48. trait Robot { fn username(&self) -> &str; } fn say_hi<T:

    Robot>(robot: &T) { println!("Hi, {}", robot.username()); }
  49. struct Bors; impl Robot for Bors { fn username(&self) ->

    &str { "@bors" } }
  50. struct Bors; impl Robot for Bors { fn username(&self) ->

    &str { "@bors" } } struct Alex; impl Robot for Alex { fn username(&self) -> &str { "@alexcrichton" } }
  51. struct Bors; impl Robot for Bors { fn username(&self) ->

    &str { "@bors" } } struct Alex; impl Robot for Alex { fn username(&self) -> &str { "@alexcrichton" } }
  52. struct Bors; fn Robot_username_Bors(_: &Bors) -> &str { "@bors" }

    struct Alex; impl Robot for Alex { fn username(&self) -> &str { "@alexcrichton" } }
  53. struct Bors; fn Robot_username_Bors(_: &Bors) -> &str { "@bors" }

    struct Alex; impl Robot for Alex { fn username(&self) -> &str { "@alexcrichton" } }
  54. struct Bors; fn Robot_username_Bors(_: &Bors) -> &str { "@bors" }

    struct Alex; fn Robot_username_Alex(_: &Alex) -> &str { "@alexcrichton" }
  55. fn say_hi<T: Robot>(robot: &T) { println!("Hi, {}", robot.username()); }

  56. fn say_hi_Bors(bors: &Bors) { println!("Hi, {}", Robot_username_Bors(bors)); } fn say_hi_Alex(alex:

    &Alex) { println!("Hi, {}", Robot_username_Alex(alex)); }
  57. fn say_hi_Bors(bors: &Bors) { println!("Hi, {}", Robot_username_Bors(bors)); } fn say_hi_Alex(alex:

    &Alex) { println!("Hi, {}", Robot_username_Alex(alex)); }
  58. fn say_hi_Bors(_: &Bors) { println!("Hi, {}", "@bors"); } fn say_hi_Alex(alex:

    &Alex) { println!("Hi, {}", Robot_username_Alex(alex)); }
  59. fn say_hi_Bors(_: &Bors) { println!("Hi, {}", "@bors"); } fn say_hi_Alex(alex:

    &Alex) { println!("Hi, {}", Robot_username_Alex(alex)); }
  60. fn say_hi_Bors(_: &Bors) { println!("Hi, {}", "@bors"); } fn say_hi_Alex(_:

    &Alex) { println!("Hi, {}", "@alexcrichton"); }
  61. fn say_hi(robot: &Robot) { println!("Hi, {}", robot.username()); }

  62. None
  63. A real world example

  64. #[test] fn complex_queries_with_no_data_have_no_size() { assert_eq!(0, mem::size_of_val(&users.as_query())); assert_eq!(0, mem::size_of_val(&users.select(id).as_query())); assert_eq!(0, mem::size_of_val(

    &users.inner_join(posts).filter(name.eq(title)) )); }
  65. List of things you can do with a 0-size type

  66. users.find(1)

  67. SelectStatement< users::table, DefaultSelectClause, NoDistinctClause, WhereClause< Eq< users::id, Bound<Integer, i32>, >,

    >, NoOrderClause, NoLimitClause, NoOffsetClause, NoGroupByClause, >
  68. SelectStatement< users::table, DefaultSelectClause, NoDistinctClause, WhereClause< Eq< users::id, Bound<Integer, i32>, >,

    >, >
  69. SelectStatement { select: DefaultSelectClause, from: users::table, distinct: NoDistinctClause, where_clause: WhereClause(Eq

    { left: users::id, right: Bound::new(1), }), }
  70. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); self.distinct.walk_ast(out)?;

    self.select.walk_ast(&self.from, out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }
  71. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); self.distinct.walk_ast(out)?;

    self.select.walk_ast(&self.from, out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }
  72. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); self.distinct.walk_ast(out)?;

    self.select.walk_ast(&self.from, out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }
  73. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); NoDistinctClause::walk_ast(out)?;

    self.select.walk_ast(&self.from, out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }
  74. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); Ok(())?;

    self.select.walk_ast(&self.from, out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }
  75. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); self.select.walk_ast(&self.from,

    out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }
  76. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); self.select.walk_ast(&self.from,

    out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }
  77. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); DefaultSelectClause::walk_ast(&self.from,

    out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }
  78. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); self.from.default_selection()

    .walk_ast(out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }
  79. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); self.from.default_selection()

    .walk_ast(out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }
  80. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); (users::id,

    users::name) .walk_ast(out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }
  81. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); (users::id,

    users::name) .walk_ast(out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }
  82. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); if

    0 != 0 { out.push_sql(", "); } users::id.walk_ast(out)?; if 1 != 0 { out.push_sql(", "); } users::name.walk_ast(out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?;
  83. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); if

    0 != 0 { out.push_sql(", "); } users::id.walk_ast(out)?; if 1 != 0 { out.push_sql(", "); } users::name.walk_ast(out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?;
  84. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); if

    false { out.push_sql(", "); } users::id.walk_ast(out)?; if 1 != 0 { out.push_sql(", "); } users::name.walk_ast(out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?;
  85. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); if

    false { out.push_sql(", "); } users::id.walk_ast(out)?; if 1 != 0 { out.push_sql(", "); } users::name.walk_ast(out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?;
  86. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); users::id.walk_ast(out)?;

    if 1 != 0 { out.push_sql(", "); } users::name.walk_ast(out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }
  87. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); users::id.walk_ast(out)?;

    if 1 != 0 { out.push_sql(", "); } users::name.walk_ast(out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }
  88. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); users::id.walk_ast(out)?;

    if true { out.push_sql(", "); } users::name.walk_ast(out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }
  89. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); users::id.walk_ast(out)?;

    if true { out.push_sql(", "); } users::name.walk_ast(out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }
  90. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); users::id.walk_ast(out)?;

    out.push_sql(", "); users::name.walk_ast(out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }
  91. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); users::id.walk_ast(out)?;

    out.push_sql(", "); users::name.walk_ast(out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }
  92. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); users::table.walk_ast(out)?;

    out.push_sql("."); out.push_identifier("id"); out.push_sql(", "); users::name.walk_ast(out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }
  93. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); users::table.walk_ast(out)?;

    out.push_sql("."); out.push_identifier("id"); out.push_sql(", "); users::name.walk_ast(out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }
  94. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); out.push_identifier("users");

    out.push_sql("."); out.push_identifier("id"); out.push_sql(", "); users::name.walk_ast(out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }
  95. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); out.push_sql("\"");

    out.push_sql(&"users".replace('"', "\"\"")); out.push_sql("\""); out.push_sql("."); out.push_identifier("id"); out.push_sql(", "); users::name.walk_ast(out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?;
  96. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); out.push_sql("\"");

    out.push_sql(&"users".replace('"', "\"\"")); out.push_sql("\""); out.push_sql("."); out.push_identifier("id"); out.push_sql(", "); users::name.walk_ast(out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?;
  97. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); out.push_sql("\"");

    out.push_sql("users"); out.push_sql("\""); out.push_sql("."); out.push_identifier("id"); out.push_sql(", "); users::name.walk_ast(out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?;
  98. out.push_sql("SELECT "); out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql("."); out.push_identifier("id"); out.push_sql(", "); users::name.walk_ast(out)?;

    out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(())
  99. out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql("."); out.push_sql("\""); out.push_sql(&"id".replace('"', "\"\"")); out.push_sql("\""); out.push_sql(", ");

    users::name.walk_ast(out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?;
  100. out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql("."); out.push_sql("\""); out.push_sql(&"id".replace('"', "\"\"")); out.push_sql("\""); out.push_sql(", ");

    users::name.walk_ast(out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?;
  101. out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql("."); out.push_sql("\""); out.push_sql("id"); out.push_sql("\""); out.push_sql(", "); users::name.walk_ast(out)?;

    out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?;
  102. out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql("."); out.push_sql("\""); out.push_sql("id"); out.push_sql("\""); out.push_sql(", "); users::name.walk_ast(out)?;

    out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?;
  103. out.push_sql("\""); out.push_sql("."); out.push_sql("\""); out.push_sql("id"); out.push_sql("\""); out.push_sql(", "); users::name.walk_ast(out)?; out.push_sql(" FROM

    "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }
  104. out.push_sql("\""); out.push_sql("id"); out.push_sql("\""); out.push_sql(", "); users::name.walk_ast(out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?;

    self.where_clause.walk_ast(out)?; Ok(()) }
  105. out.push_sql("id"); out.push_sql("\""); out.push_sql(", "); users::name.walk_ast(out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?;

    Ok(()) }
  106. out.push_sql("id"); out.push_sql("\""); out.push_sql(", "); users::table.walk_ast(out)?; out.push_sql("."); out.push_identifier("name"); out.push_sql(" FROM ");

    self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }
  107. out.push_sql("id"); out.push_sql("\""); out.push_sql(", "); users::table.walk_ast(out)?; out.push_sql("."); out.push_identifier("name"); out.push_sql(" FROM ");

    self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }
  108. out.push_sql("id"); out.push_sql("\""); out.push_sql(", "); out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql("."); out.push_identifier("name"); out.push_sql("

    FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(())
  109. out.push_sql("id"); out.push_sql("\""); out.push_sql(", "); out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql("."); out.push_identifier("name"); out.push_sql("

    FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(())
  110. out.push_sql("id"); out.push_sql("\""); out.push_sql(", "); out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql("."); out.push_sql("\""); out.push_sql("name");

    out.push_sql("\""); out.push_sql(" FROM "); self.from.walk_ast(out)?;
  111. out.push_sql("id"); out.push_sql("\""); out.push_sql(", "); out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql("."); out.push_sql("\""); out.push_sql("name");

    out.push_sql("\""); out.push_sql(" FROM "); self.from.walk_ast(out)?;
  112. out.push_sql(", "); out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql("."); out.push_sql("\""); out.push_sql("name"); out.push_sql("\""); out.push_sql("

    FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(())
  113. out.push_sql("users"); out.push_sql("\""); out.push_sql("."); out.push_sql("\""); out.push_sql("name"); out.push_sql("\""); out.push_sql(" FROM "); self.from.walk_ast(out)?;

    self.where_clause.walk_ast(out)?; Ok(()) }
  114. out.push_sql("."); out.push_sql("\""); out.push_sql("name"); out.push_sql("\""); out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(())

    }
  115. out.push_sql("name"); out.push_sql("\""); out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }

  116. out.push_sql("name"); out.push_sql("\""); out.push_sql(" FROM "); out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); self.where_clause.walk_ast(out)?; Ok(())

    }
  117. out.push_sql("name"); out.push_sql("\""); out.push_sql(" FROM "); out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); self.where_clause.walk_ast(out)?; Ok(())

    }
  118. out.push_sql("name"); out.push_sql("\""); out.push_sql(" FROM "); out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql(" WHERE

    "); self.where_clause.0.walk_ast(out)?; Ok(()) }
  119. out.push_sql("name"); out.push_sql("\""); out.push_sql(" FROM "); out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql(" WHERE

    "); self.where_clause.0.walk_ast(out)?; Ok(()) }
  120. out.push_sql("name"); out.push_sql("\""); out.push_sql(" FROM "); out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql(" WHERE

    "); self.where_clause.0.left.walk_ast(out)?; out.push_sql(" = "); self.where_clause.0.right.walk_ast(out)?; Ok(()) }
  121. out.push_sql("name"); out.push_sql("\""); out.push_sql(" FROM "); out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql(" WHERE

    "); self.where_clause.0.left.walk_ast(out)?; out.push_sql(" = "); self.where_clause.0.right.walk_ast(out)?; Ok(()) }
  122. out.push_sql(" FROM "); out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql(" WHERE "); self.where_clause.0.left.walk_ast(out)?;

    out.push_sql(" = "); self.where_clause.0.right.walk_ast(out)?; Ok(()) }
  123. out.push_sql("users"); out.push_sql("\""); out.push_sql(" WHERE "); self.where_clause.0.left.walk_ast(out)?; out.push_sql(" = "); self.where_clause.0.right.walk_ast(out)?;

    Ok(()) }
  124. out.push_sql(" WHERE "); self.where_clause.0.left.walk_ast(out)?; out.push_sql(" = "); self.where_clause.0.right.walk_ast(out)?; Ok(()) }

  125. out.push_sql(" WHERE "); users::table.walk_ast(out)?; out.push_sql("."); out.push_identifier("id"); out.push_sql(" = "); self.where_clause.0.right.walk_ast(out)?;

    Ok(()) }
  126. out.push_sql(" WHERE "); users::table.walk_ast(out)?; out.push_sql("."); out.push_identifier("id"); out.push_sql(" = "); self.where_clause.0.right.walk_ast(out)?;

    Ok(()) }
  127. out.push_sql(" WHERE "); out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql("."); out.push_identifier("id"); out.push_sql(" =

    "); self.where_clause.0.right.walk_ast(out)?; Ok(()) }
  128. out.push_sql(" WHERE "); out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql("."); out.push_identifier("id"); out.push_sql(" =

    "); self.where_clause.0.right.walk_ast(out)?; Ok(()) }
  129. out.push_sql(" WHERE "); out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql("."); out.push_sql("\""); out.push_sql("id"); out.push_sql("\"");

    out.push_sql(" = "); self.where_clause.0.right.walk_ast(out)?; Ok(()) }
  130. out.push_sql(" WHERE "); out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql("."); out.push_sql("\""); out.push_sql("id"); out.push_sql("\"");

    out.push_sql(" = "); self.where_clause.0.right.walk_ast(out)?; Ok(()) }
  131. out.push_sql(" WHERE "); out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql("."); out.push_sql("\""); out.push_sql("id"); out.push_sql("\"");

    out.push_sql(" = "); out.push_bind_param( &self.where_clause.0.right.item)?; Ok(())
  132. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); self.distinct.walk_ast(out)?;

    self.select.walk_ast(&self.from, out)?; out.push_sql(" FROM "); self.from.walk_ast(out)?; self.where_clause.walk_ast(out)?; Ok(()) }
  133. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); out.push_sql("\"");

    out.push_sql("users"); out.push_sql("\""); out.push_sql("."); out.push_sql("\""); out.push_sql("id"); out.push_sql("\""); out.push_sql(", "); out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql("."); out.push_sql("\""); out.push_sql("name"); out.push_sql("\""); out.push_sql(" FROM "); out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql(" WHERE "); out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql("."); out.push_sql("\""); out.push_sql("id"); out.push_sql("\""); out.push_sql(" = "); out.push_bind_param(&self.where_clause.0.right.item, out)?; Ok(()) }
  134. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { out.push_sql("SELECT "); out.push_sql("\"");

    out.push_sql("users"); out.push_sql("\""); out.push_sql("."); out.push_sql("\""); out.push_sql("id"); out.push_sql("\"");
  135. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { if let AstPass::ToSql(ref

    mut builder) = out { builder.push_sql("SELECT "); } out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql("."); out.push_sql("\""); out.push_sql("id"); out.push_sql("\"");
  136. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { let AstPass::ToSql(ref mut

    builder) = out; builder.push_sql("SELECT "); out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql("."); out.push_sql("\""); out.push_sql("id"); out.push_sql("\"");
  137. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { let AstPass::ToSql(ref mut

    builder) = out; builder.push_sql("SELECT "); out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql("."); out.push_sql("\""); out.push_sql("id"); out.push_sql("\"");
  138. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { let AstPass::ToSql(ref mut

    builder) = out; builder.sql.push_str("SELECT "); out.push_sql("\""); out.push_sql("users"); out.push_sql("\""); out.push_sql("."); out.push_sql("\""); out.push_sql("id"); out.push_sql("\"");
  139. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { let AstPass::CollectBinds {

    collector, metadata_lookup } = out; collector.push_bound_value( &self.where_clause.0.right.value, metadata_lookup, )?; Ok(()) }
  140. fn walk_ast(&self, out: AstPass) -> QueryResult<()> { Ok(()) }

  141. These optimizations are what let us build zero cost abstractions

  142. pub struct HashSet<K> { map: HashMap<K, ()> } impl<K: Hash

    + Eq> HashSet<K> { pub fn insert(&mut self, value: K) { self.map.insert(value, ()); } pub fn contains(&self, value: &K) -> bool { self.map.contains_key(value) } }
  143. pub struct HashSet<K> { map: HashMap<K, ()> } impl<K: Hash

    + Eq> HashSet<K> { pub fn insert(&mut self, value: K) { self.map.insert(value, ()); } pub fn contains(&self, value: &K) -> bool { self.map.contains_key(value) } }
  144. None
  145. Please ask me questions now

  146. Contact • twitter: @sgrif • github: @sgrif • podcast: bikeshed.fm