How to match a struct instantiation with macro_rules

343 Views Asked by At

Since this took me a while to figure out, I may as well share how I fixed it.

I was trying to wrap every item on a struct with some function, in my case Arc::new(Mutex::new(item)) with macro_rules

My initial attempt was many variations on this:

macro_rules! decl_sr {
    (
        $name:ident {
            $( $it:ident : $value:expr) ,*
        }
    ) => {
        $name {
            $( $it: Arc::new(Mutex::new( $value )) ),*
        }
    };
}

And the idea was to use it like this:

let mut value = decl_sr!{
    StructName {
        field_1: Value1::from_function_call(parameter1, parameter2),
        // -- snip
        field_n: ValueN::from_function_call(parameter1, parameter2),
    }
}

So it actually resulted in this:

let mut value = decl_sr!{
    StructName {
        field_1: Arc::new(Mutex::new(Value1::from_function_call(parameter1, parameter2))),
        // -- snip
        field_n: Arc::new(Mutex::new(ValueN::from_function_call(parameter1, parameter2))),
    }
}
1

There are 1 best solutions below

0
On

The correct answer was this:

    macro_rules! decl_sr {
        (
            $name:ident {
                $( $it:ident : $value:expr, )*
            }
        ) => {
            $name {
                $( $it: Arc::new(Mutex::new( $value )) ),*
            }
        };

With the comma (',') inside the repetition pattern.

Otherwise it would throw the classic macro error no rules expected token '}'. -Z macro-backtrace and trace_macros!(true); didn't help at all.

The only thing that tipped me off was this other question, but it wasn't exactly about this.

I may have picked too loose/bad fragment specifiers, feel free to correct me/suggest better options in the comments. Most of the time trying to make this works was thinking they were the problem, not the comma so I was glad it worked at all.