Here's a synthetic example of what I want:
macro_rules! define_enum { ($Name:ident { $($Variant:ident),* }) => { pub enum $Name { None, $($Variant),*, } } } define_enum!(Foo { A, B });
This code compiles, but if add a comma to it:
define_enum!(Foo { A, B, }); // ^
The compilation fails. I can fix it with:
($Name:ident { $($Variant:ident,)* }) // ^
but then define_enum!(Foo { A, B });
fails,
How should I write a macro to handle both cases:
define_enum!(Foo { A, B }); define_enum!(Foo { A, B, });
You can handle both cases by... handling both cases:
macro_rules! define_enum { ($Name:ident { $($Variant:ident,)* }) => { pub enum $Name { None, $($Variant),*, } }; ($Name:ident { $($Variant:ident),* }) => { define_enum!($Name { $($Variant,)* }); }; } define_enum!(Foo1 { A, B }); define_enum!(Foo2 { A, B, }); fn main() {}
We've moved the main implementation to the version that expects the trailing comma. We then added a second clause that matches the case with the missing comma and rewrites it to the version with a comma.
DK. points out an alternative, making the trailing comma itself optional.
This avoids the need to delegate from one implementation to the other.
You can use the ?
macro repeater to write this and disallow multiple trailing commas:
($Name:ident { $($Variant:ident),* $(,)? }) => { // ^^^^^
This allows multiple trailing commas:
($Name:ident { $($Variant:ident),* $(,)* }) => { // ^^^^^
Change the line
($Name:ident { $($Variant:ident),* }) => {
to
($Name:ident { $($Variant:ident),* $(,)? }) => {
to add an optional comma at the end. This works in stable Rust / 2018 edition. This syntax also works for other separators like a semicolon.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With