ridiculous_fish
ridiculous_fish

Reputation: 18591

How to introduce Rust enum variants with a macro?

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?

Upvotes: 2

Views: 2511

Answers (1)

Marty
Marty

Reputation: 1107

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]
}

Upvotes: 3

Related Questions