Disambiguate variable argument list with one specific argument pattern in macro_rules

37 Views Asked by At

I want my macro to accept a function call and match all arguments but if an argument it's a closure I want to handle it differently. As I'm new to Rust macros I'm not even sure of its limitations.

Some examples of what it should accept:

// one arg
my_macro!(test_fn(|a, b| {}));
// last arg
my_macro!(test_fn(42, |a, b| {}));
// middle arg
my_macro!(test_fn(42, |a, b| {}, "foo"));

In the closure argument case I need to access the inputs of the closure, capture variables and output a new closure.

So after researching a bit, I came up with this kind of approach:

macro_rules! map_if_closure {
    ( $capture:ident, |$( $args:ident ),*| $body:expr ) => {
        |$($args)*| {
            // do stuff
            println!("{} got captured", stringify!(capture));
            $body
        }
    };
    ( $capture:ident, $arg:expr ) => { $arg };
}

#[macro_export]
macro_rules! my_macro {
    ( $func:ident($( $args:expr ),*) ) => {
        let to_capture = 42;
        $func($(map_if_closure!(to_capture, $args)),*);
    };
}

Unfortunately, this will not work because forwarding a matched fragment from my_macro will be opaque to map_if_closure as described here. I cannot then match the arguments as the macro will see it as a single token.

Note: I know the pattern for closures is not complete but for now it's enough.

0

There are 0 best solutions below