How to concat two variables to create an identifier in a declarative macro?

758 views Asked by At

I want to write a macro to support parameterized tests, and got the following code from AI, but got errors on one line:

#[macro_export]
macro_rules! parameterize {
    ($name:ident, $params:pat, {$($test_name:ident : ($($args:expr),*)),*}, $test_body:block) => {
        $(
            fn $name_\$test_name() {   //<========= this line
                let $params = ($($args),*);
                $test_body
            }
        )*
     };
}

parameterize! {
     should_be_added,
     (expected, a, b),
     {
         positive: (3, 1, 2),
         zero: (0, 0, 0),
         negative: (-5, -2, -3),
         large_numbers: (999999, 444444, 555555)
     },
     {
         println!("a={}, b={}, expected={}", a, b, expected);
     }
}

fn main() {
   positive();
   negative();
}

If I change fn $name_\$test_name() to fn $test_name() , it works well.

So I want to know how to concatenate the two variables $name $test_name to output one string. For example, if $name is foo and $test_name is bar, how to output foo_bar?

1

There are 1 answers

0
Peter Hall On BEST ANSWER

There is a crate called paste, that provides a macro for concatenating tokens inside declarative macros.

To use it, wrap your entire result in the paste! macro, and then you can concatenate tokens by placing them between [< and >] with spaces to separate.

use paste::paste;

#[macro_export]
macro_rules! parameterize {
    ($name:ident, $params:pat, {$($test_name:ident : ($($args:expr),*)),*}, $test_body:block) => {
        paste! {
            $(
                fn [<$name _ $test_name>]() { // <- special syntax used by paste!
                    let $params = ($($args),*);
                    $test_body
                }
            )*
        }
     };
}

Using the remainder of the code you've provided, this would generate functions should_be_added_positive and should_be_added_negative.