HiveBrain v1.2.0
Get Started
← Back to all entries
snippetrustMajor

How to allow optional trailing commas in macros?

Submitted by: @import:stackoverflow-api··
0
Viewed 0 times
macroshowtrailingcommasallowoptional

Problem

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

Solution

Make the comma optional

As DK. points out, the trailing comma can be made optional.
Rust 1.32

You can use the ? macro repeater to write this and disallow multiple trailing commas:
($Name:ident { $($Variant:ident),* $(,)? }) => {
// ^^^^^

Previous versions

This allows multiple trailing commas:
($Name:ident { $($Variant:ident), $(,) }) => {
// ^^^^^

Handle both cases

Or 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.

Code Snippets

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() {}

Context

Stack Overflow Q#43143327, score: 99

Revisions (0)

No revisions yet.