I have a list of identifier and I want to invoke a macro for each pair of identifiers from that list. For example, if I have a
, b
and c
, I would like to generate this:
println!("{} <-> {}", a, a);
println!("{} <-> {}", a, b);
println!("{} <-> {}", a, c);
println!("{} <-> {}", b, a);
println!("{} <-> {}", b, b);
println!("{} <-> {}", b, c);
println!("{} <-> {}", c, a);
println!("{} <-> {}", c, b);
println!("{} <-> {}", c, c);
Of course, this is a dummy example. In my real code, the identifiers are types and I want to generate impl
blocks or something like that.
My goal is to list each identifier only once. In my real code, I have around 12 identifier and don't want to manually write down all 12² = 144 pairs. So I thought that a macro might help me. I know that it can be solved with the all powerful procedural macros, but I hoped that it's also possible with declarative macros (macro_rules!
).
I tried what I thought was the intuitive way to handle this (two nested "loops") (Playground):
macro_rules! print_all_pairs {
($($x:ident)*) => {
$(
$(
println!("{} <-> {}", $x, $x); // `$x, $x` feels awkward...
)*
)*
}
}
let a = 'a';
let b = 'b';
let c = 'c';
print_all_pairs!(a b c);
However, this results in this error:
error: attempted to repeat an expression containing no syntax variables matched as repeating at this depth
--> src/main.rs:4:14
|
4 | $(
| ______________^
5 | | println!("{} <-> {}", $x, $x);
6 | | )*
| |_____________^
I guess it makes kind of sense, so I tried something else (Playground):
macro_rules! print_all_pairs {
($($x:ident)*) => {
print_all_pairs!(@inner $($x)*; $($x)*);
};
(@inner $($x:ident)*; $($y:ident)*) => {
$(
$(
println!("{} <-> {}", $x, $y);
)*
)*
};
}
But this results in the same error as above!
Is this possible with declarative macros at all?