Monster (String) Ids

I was porting my Pokedex from Java to Rust:

let charizard = Species {
    id: "charmeleon",
    forms: vec![Form {
        id: "charmeleon",

        types: Dual(Fire, Flying),
        gender_ratio: Male(0.875),
        base_stats: Stats { hp: 58, atk: 64, def: 58, spa: 80, spd: 65, spe: 80 },
        color: Red,
        abilities: Abilities {
            primary: "blaze",
            secondary: None,
            hidden: Some("solar-power"),
        },
        height: Metres(1.1),
        weight: Kilograms(19.0),
        egg_groups: vec![Dragon, Monster],
        body_style: TailedBiped,
        
        exp_yield: 142,
        hatch_time: 4,
        catch_rate: 45,
        friendship: 70,
        stat_yield: Stats { hp: 0, atk: 0, def: 0, spa: 1, spd: 0, spe: 1 },

        leveling_rate: LevelRate,
        learnset: Learnset,
    }],
    evolutions: vec!["charizard"],
    precursors: Some("charmander"),
};

This code relies a bit heavily on string IDs. Does Rust offer any nicer alternatives to this? I'd rather not use a 721 element enum either, for obvious reasons :smiley: .

What's wrong with strings? Are you looking for something like Ruby's symbol literals? Are you looking for GUID/UUIDs? Some other ID system?

I believe all string literals inside a crate are interned in the compiler, so the string data won't be duplicated in the final binary if you're worried about bloat.

Well, yeah, I was looking for something like symbols. But I guess deduplication in the binary is enough. Thanks!

Edit: And I guess it's much the same in practice.

I'd rather not use a 721 element enum either, for obvious reasons :smiley: .

What are your obvious reasons against the enum? An enum listing all Pokemon will be more type-safe and could also be a nice index in itself. The only downside I can see is that you can't expand it at runtime.

An enum with the 721 names as elements (like enum Names {charmander, charmeleon, charizard}) can be represented as an u16 (2^16 = 65,536 slots should be enough, you can enforce it with #[repr(u16)]). Internally, it'll be mapped like 1 => charmander, 2 => charmeleon, ….

To get the names (and maybe also the indexes) from the enum, you'd write some methods that match over all elements – but you can use a small macro for that! Have a look at this. (Btw, abilities could be an enum as well.)

3 Likes

Well, my main reason was expanding at runtime, because in my original I had dynamic modpack loading for fakemons (which on second thought isn't a very obvious reason). And I thought it'd be fun to right some kind of mod system in rust :smiley:

My other reason was that this would be much easier to maintain, because after building the core I can just drop in dylibs for each new game, rather than patching enums and adding data to the program itself.

Or, maybe I could make a macro which reads in Pokemon files from a data directory in the project root and parses it into an enum of each Pokemon. (I'd add an evil grin here but I can't find the emoticon for it on Discourse.)