In a macro, let's suppose I wanted to match the following input:
foo! {
x<T: Debug + Add<T>> where T: Display
}
And produce something like so:
fn x<T: Debug + Add<T>>() where T: Display {}
I could try the following:
macro_rules! foo {
($name:ident<$($gen:tt)*> where $($wh:tt)*) => {
fn $name<$($gen)*>() where $($wh)* {}
}
}
But that unfortunately fails.
Say that I add a space between the two >
s to make sure that it's not parsing as >>
and instead as > >
. Now it complains that
Compiling playground v0.0.1 (/playground)
error: local ambiguity: multiple parsing options: built-in NTs tt ('gen') or 1 other option.
--> src/lib.rs:9:24
|
9 | foo!(x<T: Debug + Add<T> > where T: Display);
| ^
Which isn't any better.
Then I learned, that I could instead use something like the following to match without the +
s separating them:
macro_rules! foo {
($name:ident<$($gen:ident$(: $cons:path)?)*> where $($lhs:ty : $rhs:path)*) => {
fn $name<$($gen $(:$cons)?)*>() where $($lhs: $rhs)* {}
}
}
foo!(x<T: Debug> where T: Display);
foo!(y<T: Add<T>> where T: Display);
But, as can be seen in the example, we must drop the + Add<T>
or the + Debug
. This is because we cannot use +
as a separator in a repetition ($($x:ident)+*
would match a*
and a b*
but not a+b
) and using a simple ty
doesn't work. ...not to mention that a path
or ty
can't be followed by a +
.
I could try to expand the entire generics syntax using a convoluted macro, but that seems cumbersome and a bit of a rabbit hole.
Therefore I'm fresh out of ideas and was wondering what other people have done to solve this issue, if anyone else has even tried to match on generics before.
Thanks!