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.
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),*])
}
};
}