Is there a way to adjust the macro below, in order to detect when the last argument of the macro call is a closure? The code below works, but it's using a semicolon to disambiguate, and that doesn't look right.
Could the closure argument be identified specifically at invocation, e.g. closure: || { ... }
?
macro_rules! invoke_me {
($func_name:ident, $($arg:expr),*; || $closure:expr ) => {{
println!("{}({})", stringify!($func_name), stringify!($($arg),*));
println!("With closure");
let result: Result<(),String> = $closure;
result
}};
($func_name:ident, $($arg:expr),*) => {{
println!("{}({})", stringify!($func_name), stringify!($($arg),*));
println!("No closure");
Ok::<(),String>(())
}};
}
fn main() {
invoke_me!(foo, 1, 2, 3).unwrap();
invoke_me!(foo, 1, 2, 3; || {
println!("Ok from closure");
Ok(())
}).unwrap();
let _ = invoke_me!(foo, 1, 2, 3; || {
println!("Error from closure");
Err("Error".to_string())
});
}
Using the idea from How to separate last expression in repeated expressions in a Rust macro? (see ChrisB's comment), I got this to work:
macro_rules! invoke_me {
($func_name:expr, $($rest:tt)+) => {
invoke_me!(@transpose $func_name, [ ] $($rest)+)
};
(@transpose $func_name:expr, [ $($args:expr)*] || $closure:expr) => {{
println!("{}({})", stringify!($func_name), stringify!($($args),*));
println!("With closure");
let result: Result<(),String> = $closure;
result
}};
(@transpose $func_name:expr, [$($temp:expr)*] $arg:expr , $($rest:tt)+) => {
invoke_me!(@transpose $func_name, [$($temp)* $arg] $($rest)+)
};
(@transpose $func_name:expr, [$($args:expr)*] $last_arg:expr) => {{
println!("{}({})", stringify!($func_name), stringify!($($args),*, $last_arg));
println!("No closure");
Ok::<(),String>(())
}}
}
fn main() {
invoke_me!(foo, 1, 2, 3).unwrap();
invoke_me!(foo, 1, 2, 3, || {
println!("Ok from closure");
Ok(())
}).unwrap();
let _ = invoke_me!(foo, 1, 2, 3, || {
println!("Error from closure");
Err("Error".to_string())
});
}
Although this is possible, it would probably be a better idea to just keep the semicolon, as this is slow.