1
votes

I would like to use a Rust macro to introduce enum variants alongside "bespoke" ones. As a simple illustration:

macro_rules! make_beta {
    () => {Beta}
}

enum Greek {
    Alpha,
    make_beta! ()
}

My real goal is to have a family:

macro_rules! make_variants {
    ($($N:literal)+) => {
        $(
            Array$N([u8; $N]),
        )+
    }
}

enum Stuff {
    Empty,
    Something,
    make_variants! { 1 2 3 4 5 6 7 8 }
}

which has Array1 through Array8 in addition to "bespoke" variants. Unfortunately neither of these compiles: it complains about the exclamation mark example.

How can I introduce enum variants with a macro?

1
Rust macros are not like C/C++ macros that can be used anywhere. They can only be used in certain situations, and enum variants are not included. So the compiler complains about ! being unexpected because it doesn't expect a macro invocation in that position. (See the Rust reference for more details.)Frxstrem
Another reason why this won't work is that you can't build a new identifier with Array$N in a macro.Sven Marnach
I don't really know your use case, but the smallvec crate may be useful.Sven Marnach

1 Answers

1
votes

Instead of defining the macro inside the enum, you could define the enum inside a macro like this:

macro_rules! enum_variants {
    ($name:ident {$($vals:tt)*} [$($tag:ident : $N:literal)+]) => {
        enum $name {
            $($vals)*
            $($tag([u8; $N])),+,
        }
    }
}

enum_variants! { Stuff {
        Empty,
        Something(i32),
    }
    [A1:1 A2:2 A3:3 A4:4 A5:5 A6:6 A7:7 A8:8]
}

fn main() {
    let x = Stuff::A3;
    let y = Stuff::Something(3);
}

UDPATE: Using the paste crate as mentioned by Frxstrem in the comments:

macro_rules! enum_variants {
    ($name:ident {$($vals:tt)*} [$($N:literal)+]) => {
        paste::item!{
            enum $name {
                $($vals)*
                $([<Array $N>]([u8; $N])),+,
            }
        }
    }
}

enum_variants! { Stuff {
        Empty,
        Something(i32),
    }
    [1 2 3 4 5 6 7 8]
}