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