Jack Stodart
Jack Stodart

Reputation: 13

In Rust can you associate a constant value to each enum variant and then collect those values at compile time?

Let's say I have an enum, and I want to somehow annotate or associate each variant with a &str. E.g.:

enum MyEnum {
    A, // "foo"
    B(String), // "bar"
    C(i32) // "baz"
}

I would also like to collect these &str's into an array like

const arr:[&'static str; 3] = ["foo", "bar", "baz"];

Is there a nice way to do this automatically at compile time? Rather than having to write out the constant array separately? Perhaps with macros?

A const fn would answer the first part, but I believe it requires #![feature(const_if_match)], and I would prefer using stable Rust if possible. I'm also not sure it answered the second part. I also considered attribute macros, but I don't know how (or whether) you can collect these attributes together at compile time.

Upvotes: 1

Views: 516

Answers (1)

PitaJ
PitaJ

Reputation: 15012

You can achieve this with a declarative macro:

macro_rules! str_variants {
    { enum $enum_name:ident {
        $(
        #[str = $variant_str:literal]
        $variant_name:ident $variant_fields:tt
        ),* $(,)*
    } } => {
        enum $enum_name {
            $(
                $variant_name $variant_fields,
            )*
        }

        impl $enum_name {
            const ARR: &[&'static str] = &[
                $(
                    $variant_str,
                )*
            ];
        }
    }
}

str_variants! { enum MyEnum {
    #[str = "foo"]
    A(),
    #[str = "bar"]
    B(String),
    #[str = "baz"]
    C(i32)
} }

fn main() {
    dbg!(MyEnum::ARR);

// [src/main.rs:34] MyEnum::ARR = [
//     "foo",
//     "bar",
//     "baz",
// ]
}

You just need to use an extra pair of parens with unit variants.

playground

Upvotes: 0

Related Questions