Reputation: 2024
I would like to auto-generate the default case for repeating match statements like the following:
enum A {Foo, Bar, Foobar(B) }
enum B {Baz}
use A::*;
use B::*;
match x {
Foo => { /*...*/ },
Bar => { /*...*/ },
Foobar(Baz) => { /*...*/ }
_ => consume([Foo, Bar, Foobar(Baz)])
}
All three elements are both valid as patterns as well as expressions in the given context. I have, therefore, tried the following macro rule:
macro_rules! match_default {
($x:expr, $($pattern:pat_param => $action:block),+) => {
match $x {
$($pattern => $action),+
_ => consume([$($pattern),*])
}
};
}
which gives me the error
error: expected expression, found pattern
Foo
On the other hand, when I replace pat_param
with expr
, the error is
error: arbitrary expressions aren't allowed in patterns
Is what I am trying to achieve not possible using rusts macro_rules!
system? I am OK with spelling out the actual type inside the macro ($x it will always be a variant of enum A
), but so far I have had no success.
Upvotes: 0
Views: 47
Reputation: 15094
The solution is to pass the original input twice into an internal macro. This allows us to treat it once as patterns and the second time as expressions.
macro_rules! match_default {
($x:expr, $($body:tt)*) => {
// once for patterns, again for exprs
match_default!(@inner $x, [[ $($body)* ]], [[ $($body)* ]])
};
(@inner $x:expr, [[ $($pattern:pat_param => $action:block),+ ]], [[ $($pattern_expr:expr => $_action_expr:block),+ ]]) => {
match $x {
$($pattern => $action),+
_ => consume([$($pattern_expr),*])
}
};
}
Upvotes: 2