123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990 |
- //! Durka's `unborrow!` macro.
- /// Explicitly precompute a method's arguments before the call so that borrowck sees them the same
- /// way that trans does.
- ///
- /// Examples
- /// =======
- ///
- /// ```
- /// # #[macro_use] extern crate unborrow;
- /// # fn main() {
- /// let mut v = vec![1, 2, 3];
- ///
- /// // this line would cause an error because borrowck consider `v` borrowed by `reserve`
- /// // during its parameter list
- /// // v.reserve(v.capacity()); //~ERROR cannot borrow `v`
- /// // but wrap the call in unborrow!() and it works!
- /// unborrow!(v.reserve(v.capacity()));
- /// assert!(v.capacity() >= 6);
- /// assert_eq!(v, [1, 2, 3]);
- ///
- /// // similar to the above, both v.len()-1 and v[0]+41 require borrowing `v` and we can't
- /// // do that while borrowck thinks is is mutably borrowed by `insert`
- /// // v.insert(v.len() - 1, v[0] + 41); //~ERROR cannot borrow `v`
- /// // but wrap the call in unborrow!() and it works!
- /// unborrow!(v.insert(v.len() - 1, v[0] + 41));
- /// assert_eq!(v, [1, 2, 42, 3]);
- ///
- /// // it also works for nested objects!
- /// struct Wrapper { v: Vec<i32> }
- /// let mut w = Wrapper { v: vec![1, 2, 3] };
- /// unborrow!(w.v.reserve(w.v.capacity()));
- ///
- /// // ...and with free functions! (the first argument is assumed to be the mutable borrow)
- /// use std::mem;
- /// unborrow!(mem::replace(&mut v, v.clone()));
- ///
- /// # }
- /// ```
- macro_rules! unborrow {
- // =========================================================================================================
- // PRIVATE RULES
- // This rule fires when we have parsed all the arguments.
- // It just falls through to output stage.
- // (FIXME could fold the output rule into this one to reduce recursion)
- (@parse () -> ($names:tt $lets:tt) $($thru:tt)*) => {
- unborrow!(@out $names $lets $($thru)*)
- };
- // Parse an argument and continue parsing
- // This is the key rule, assigning a name for the argument and generating the let statement.
- (@parse ($arg:expr, $($rest:tt)*) -> ([$($names:ident),*] [$($lets:stmt);*]) $($thru:tt)*) => {
- unborrow!(@parse ($($rest)*) -> ([$($names,)* arg] [$($lets;)* let arg = $arg]) $($thru)*)
- // ^ ^
- // Right here an ident is created out of thin air using hygiene.
- // Every time the macro recurses, we get a new syntax context, so "arg" is actually a new identifier!
- };
- // Output stage for free functions.
- // Assembles the let statements and variable names into a block which computes the arguments,
- // calls the method, and returns its result.
- (@out [$($names:ident),*] [$($lets:stmt);*] ($($meth:ident)::+) $arg1:expr) => {{
- $($lets;)*
- $($meth)::+($arg1, $($names),*)
- }};
- // Output stage for object methods.
- (@out [$($names:ident),*] [$($lets:stmt);*] $($obj:ident).+) => {{
- $($lets;)*
- $($obj).+($($names),*)
- }};
- // =========================================================================================================
- // PUBLIC RULES
- // Macro entry point for object methods.
- ($($obj:ident).+ ($($args:expr),*)) => {
- unborrow!(@parse ($($args,)*) -> ([] []) $($obj).+)
- // | | | ^ info about the method call, saved for later
- // | | ^ generated let statements
- // | ^ generated argument names
- // ^ arguments to be parsed
- };
- // Macro entry point for free functions.
- ($($meth:ident)::+ ($arg1:expr, $($args:expr),*)) => {
- unborrow!(@parse ($($args,)*) -> ([] []) ($($meth)::+) $arg1)
- };
- }
|