Generate an enum from array of strings at compile time

Hi everyone! I'm not sure how to use macros for the problem that I have. There is a list string literals (all known at compile-time):

static WORDS: &[&str] = &[
  "FOO",
  "BAR",
  ...
];

I would like to get two things out of this without just typing all of these out explicitly:

  1. An enum with the items each corresponding to an entry in WORDS, i.e.
enum WordEnum {
  Foo,
  Bar,
  ...
};

AFAIK this should be possible with the macros but I'm not really comfortable with them yet and I can't figure out how to do that. I guess that might probably be easier the other way around (having an enum first and then using stringify! in combination with something to create strings) and that would be fine, too.

  1. A the mapping from WORDS to WordEnum. I know this one is quite easy to do in the runtime, probably with lazy_static! or maybe with const fn in the unstable channel, but I'm curious if this can work with macros + phf_map!. The result might look like this:
static WORD_TO_ENUM: phf::Map<&'static str, WordEnum> = phf_map! {
    "FOO" => WordEnum::Foo,
    "BAR" => WordEnum::Bar,
    ...
};

Is there any way to iterate through const array or enum items in a macro?

1 Like

Strum is a good full featured solution for that:

Though, you could probably do what you need with a simple macro rules macro without adding another dependency. I'll try that real quick and post it here if I get it to work. :slight_smile:

1 Like

Here you go I got a macro that would do what you're looking for:

Usage

It does rely on including an extra dependency, paste, but paste is tiny and has no dependencies of its own.

The macro will let you go from string to macro and from macro to string:

string_enum!{
    enum Options {
        Op1,
        Op2,
    }
}

fn main() {
    let test = Options::Op1;
    let test_string: &str = test.as_ref();
    dbg!(test_string);
    
    let string_op = "Op2";
    let option: Result<Options, ParseOptionsError> = string_op.parse();
    dbg!(option);
}
2 Likes

Oh, this looks really cool, thank you very much for the help!

Rust macros are indeed not very easy but I guess I should dive deeper into this topic, it looks quite neat! Thanks again!

1 Like

No problem, glad I could help!

I have some fun solving little Rust puzzles. :slight_smile:

Quick Q: is there any way to modify the strings so that they are not literally the same "FOO" <-> KeywordEnum::Foo? I guess I would need something like a procedural macro to replace/act on strnigify macro output, right?

Here you go :slight_smile: :

Yeah, the paste crate has the option to transform identifiers to uppercase or lowercase and I already needed it to dynamically create the error type struct, so that worked out nicely.

1 Like