Skip to content

Instantly share code, notes, and snippets.

@durka
Forked from anonymous/playground.rs
Last active January 6, 2016 04:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save durka/375c277cc7df3a4608da to your computer and use it in GitHub Desktop.
Save durka/375c277cc7df3a4608da to your computer and use it in GitHub Desktop.
Macro for pre-computing method arguments to avoid borrowck errors
/// Precompute a method's arguments before the call so that borrowck sees
/// them the same way that trans does.
macro_rules! unborrow {
// this rule fires when we have parsed all the arguments
// fall through to output stage
(@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!
};
(@out [$($names:ident),*] [$($lets:stmt);*] $obj:ident $meth:ident) => {{
$($lets;)*
$obj.$meth($($names),*)
}};
// macro entry point
($obj:ident . $meth:ident ($($args:expr),*)) => {
unborrow!(@parse ($($args,)*) -> ([] []) $obj $meth)
// | | | ^ info about the method call, saved for later
// | | ^ generated let statements
// | ^ generated argument names
// ^ arguments to be parsed
}
}
fn main() {
let mut v = vec![1, 2, 3];
// v.reserve(v.capacity());
unborrow!(v.reserve(v.capacity()));
println!("{} {:?}", v.capacity(), v);
// v.insert(v.len() - 1, v[0] + 41);
unborrow!(v.insert(v.len() - 1, v[0] + 41));
println!("{:?}", v);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment