unborrow.rs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. //! Durka's `unborrow!` macro.
  2. /// Explicitly precompute a method's arguments before the call so that borrowck sees them the same
  3. /// way that trans does.
  4. ///
  5. /// Examples
  6. /// =======
  7. ///
  8. /// ```
  9. /// # #[macro_use] extern crate unborrow;
  10. /// # fn main() {
  11. /// let mut v = vec![1, 2, 3];
  12. ///
  13. /// // this line would cause an error because borrowck consider `v` borrowed by `reserve`
  14. /// // during its parameter list
  15. /// // v.reserve(v.capacity()); //~ERROR cannot borrow `v`
  16. /// // but wrap the call in unborrow!() and it works!
  17. /// unborrow!(v.reserve(v.capacity()));
  18. /// assert!(v.capacity() >= 6);
  19. /// assert_eq!(v, [1, 2, 3]);
  20. ///
  21. /// // similar to the above, both v.len()-1 and v[0]+41 require borrowing `v` and we can't
  22. /// // do that while borrowck thinks is is mutably borrowed by `insert`
  23. /// // v.insert(v.len() - 1, v[0] + 41); //~ERROR cannot borrow `v`
  24. /// // but wrap the call in unborrow!() and it works!
  25. /// unborrow!(v.insert(v.len() - 1, v[0] + 41));
  26. /// assert_eq!(v, [1, 2, 42, 3]);
  27. ///
  28. /// // it also works for nested objects!
  29. /// struct Wrapper { v: Vec<i32> }
  30. /// let mut w = Wrapper { v: vec![1, 2, 3] };
  31. /// unborrow!(w.v.reserve(w.v.capacity()));
  32. ///
  33. /// // ...and with free functions! (the first argument is assumed to be the mutable borrow)
  34. /// use std::mem;
  35. /// unborrow!(mem::replace(&mut v, v.clone()));
  36. ///
  37. /// # }
  38. /// ```
  39. macro_rules! unborrow {
  40. // =========================================================================================================
  41. // PRIVATE RULES
  42. // This rule fires when we have parsed all the arguments.
  43. // It just falls through to output stage.
  44. // (FIXME could fold the output rule into this one to reduce recursion)
  45. (@parse () -> ($names:tt $lets:tt) $($thru:tt)*) => {
  46. unborrow!(@out $names $lets $($thru)*)
  47. };
  48. // Parse an argument and continue parsing
  49. // This is the key rule, assigning a name for the argument and generating the let statement.
  50. (@parse ($arg:expr, $($rest:tt)*) -> ([$($names:ident),*] [$($lets:stmt);*]) $($thru:tt)*) => {
  51. unborrow!(@parse ($($rest)*) -> ([$($names,)* arg] [$($lets;)* let arg = $arg]) $($thru)*)
  52. // ^ ^
  53. // Right here an ident is created out of thin air using hygiene.
  54. // Every time the macro recurses, we get a new syntax context, so "arg" is actually a new identifier!
  55. };
  56. // Output stage for free functions.
  57. // Assembles the let statements and variable names into a block which computes the arguments,
  58. // calls the method, and returns its result.
  59. (@out [$($names:ident),*] [$($lets:stmt);*] ($($meth:ident)::+) $arg1:expr) => {{
  60. $($lets;)*
  61. $($meth)::+($arg1, $($names),*)
  62. }};
  63. // Output stage for object methods.
  64. (@out [$($names:ident),*] [$($lets:stmt);*] $($obj:ident).+) => {{
  65. $($lets;)*
  66. $($obj).+($($names),*)
  67. }};
  68. // =========================================================================================================
  69. // PUBLIC RULES
  70. // Macro entry point for object methods.
  71. ($($obj:ident).+ ($($args:expr),*)) => {
  72. unborrow!(@parse ($($args,)*) -> ([] []) $($obj).+)
  73. // | | | ^ info about the method call, saved for later
  74. // | | ^ generated let statements
  75. // | ^ generated argument names
  76. // ^ arguments to be parsed
  77. };
  78. // Macro entry point for free functions.
  79. ($($meth:ident)::+ ($arg1:expr, $($args:expr),*)) => {
  80. unborrow!(@parse ($($args,)*) -> ([] []) ($($meth)::+) $arg1)
  81. };
  82. }