How to (best) map from enum

I've currently got the following code, which does work:

use colored::{ColoredString, Colorize};

#[repr(u8)]
#[derive(Copy, Clone, PartialEq, Debug)]
enum BubbleColor {
    None = 0,
    Red = 1,
    Green = 2,
    Blue = 3,
    Yellow = 4,
    Purple = 5,
    Orange = 6,
    Pink = 7,
}

impl From<u8> for BubbleColor {
    fn from(value: u8) -> Self {
        match value {
            1 => BubbleColor::Red,
            2 => BubbleColor::Green,
            3 => BubbleColor::Blue,
            4 => BubbleColor::Yellow,
            5 => BubbleColor::Purple,
            6 => BubbleColor::Orange,
            7 => BubbleColor::Pink,
            _ => BubbleColor::None,
        }
    }
}

impl BubbleColor {
    fn to_colored_string(&self) -> ColoredString {
        match self {
            BubbleColor::None => " ".bold().white(),
            BubbleColor::Red => "R".bold().red(),
            BubbleColor::Green => "G".bold().green(),
            BubbleColor::Blue => "B".bold().blue(),
            BubbleColor::Yellow => "Y".bold().yellow(),
            BubbleColor::Purple => "P".bold().magenta(),
            BubbleColor::Orange => "O".bold().truecolor(255, 165, 0), // Orange color
            BubbleColor::Pink => "K".bold().truecolor(255, 192, 203), // Pink color
        }
    }
}

But it feels a bit unsatisfying, because I come from Python and from that perspective this looks clunky and slow.

I'm also working with copilot, and I've tried 'correcting' this code a couple of time, but copilot keeps changing it back.

So I'm wondering, am I wrong? Is this actually a good pattern in Rust?

(I'm building a game with the intention to train AI on it, hence my caring about performance more than I usually would.)

((My natural inclination is that the enum is stored as a u8 under the hood, so converting to/from u8 should be trivial. And that the options of ColoredString should be stored in an array, with index-lookup being used to map from BubbleColor to ColoredString.))

Clunky, maybe, You can use 3rd party crate like num_enum to generate the code for you but it's same code all the way down.

But slow, definitely not! impl From<u8> for BubbleColor compiles to 4 lines of assembly and is quite possibly inlined. Don't judge Rust code's runtime performance from Python's perspective. It just don't work that way. Alway benchmark the code yourself.

5 Likes

Thanks!

Nice to learn about Compiler Explorer and

unsafe {
            std::hint::unreachable_unchecked()
        }

too :slight_smile:

1 Like

Well, don't actually use unreachable_unchecked unless you identified it really is the bottleneck :sweat_smile: (which is unlikely). It's dangerous and I put there just for demonstration purpose only.

2 Likes

Your to_colored_string can be written tersely by indexing into an array by self as usize (or does it have to be self as u8 as usize?)

I wish we’d get a standard FromRepr derive because if feels so silly to write a full match for what is literally just an identity function with a range check.

2 Likes