Using Rust's enum as a bi-directional lookup table

1.8k views Asked by At

I am writing code that interacts with the NetworkManager over D-Bus and I want to use an enum using as key-value like scheme.

For example, I want once to use the value 0 as the digit zero and in different context to use the string Unknown of this enum:

pub enum NetworkManagerState {
    Unknown = 0,
    Asleep = 10,
    Disconnected = 20,
    Disconnecting = 30,
    Connecting = 40,
    ConnectedLocal = 50,
    ConnectedSite = 60,
    ConnectedGlobal = 70,
}

What is the cleanest, most idiomatic way of doing so? Is there a way to define a tuple based enum that each entry looks like that (ConnectedSite, 60u32, "Connected") and use each tuple attribute upon context.

1

There are 1 answers

0
eddy On BEST ANSWER
  1. To cast an enum to int you can use as i32.
  2. To cast an i32 to your enum you could use the enum_primitive crate:

cargo.toml:

[dependencies]
enum_primitive = "*"

main.rs:

#[macro_use]
extern crate enum_primitive;
use enum_primitive::FromPrimitive;

enum_from_primitive! {
#[derive(Debug, PartialEq)]
pub enum NetworkManagerState {
    Unknown = 0,
    Asleep = 10,
    Disconnected = 20,
    Disconnecting = 30,
    Connecting = 40,
    ConnectedLocal = 50,
    ConnectedSite = 60,
    ConnectedGlobal = 70,
}
}

impl From<i32> for NetworkManagerState {
    fn from(val: i32) -> NetworkManagerState {
        NetworkManagerState::from_i32(val).expect("passed Value does not match an enum value!")
    }
}
impl From<NetworkManagerState> for i32 {
    fn from(val: NetworkManagerState) -> i32 {
        val as i32
    }
}


fn main() {
    let value_i32 = 40;
    let value_enum = NetworkManagerState::Connecting;

    // enum to i32
    println!("{:?}", value_enum as i32);

    // i32 to enum
    println!("{:?}", NetworkManagerState::from_i32(value_i32).unwrap());

    // using from trait
    let y: i32 = NetworkManagerState::Connecting.into();
    println!("{:?}", y);

    // using from trait
    let x: NetworkManagerState = 40.into();
    println!("{:?}", x);
}

using the from trait you could make your functions accepting everything that can be converted to your enum:

fn fancy_function<T: Into<NetworkManagerState>>(value: T) {
    let internal: NetworkManagerState = value.into();
    println!("{:?}", internal);
}

...

fancy_function(60);
fancy_function(NetworkManagerState::Asleep);