I have an enum
with over 100 variants. and I have to get each of its variants from a string. Something like this.
enum VeryLongEnum {
A,
B,
C,
D,
E,
}
impl From<&'static str > for VeryLongEnum {
fn from(s: &'static str) -> VeryLongEnum {
match s {
"A" => VeryLongEnum::A,
"B" => VeryLongEnum::B,
"C" => VeryLongEnum::C,
"D" => VeryLongEnum::D,
"E" => VeryLongEnum::E,
}
}
}
But I don't want to write all the variants one by one, it's crazy.
I'm trying to create a mini macro to simplify this, I did something like this.
macro_rules! from_str {
( $s:expr ) => {{
let t: VeryLongEnum = VeryLongEnum::$s;
t
}};
}
to use like this.
let variant = "A";
let en = from_str!(variant);
But I'm having an error which says expected a identifier
.
I understand that identifiers and expresions are different types of token trees, but the question is how can I "force" this to generate the enum variant with the literal?
let variant = "A"; let en = from_str!(variant);
variant
is a string that exists at runtime, you cannot pass it to a macro like that.
An alternative is to define a macro that defines the enum as well as the string conversion. This macro can use the stringify!
macro in Rust to convert at identifier to a static string that can be passed to pattern match. Since the conversion is fallible, you should define a TryFrom
instead of From
(or FromStr
which allows you to call "A".parse()
).
macro_rules! go {
($($ident:ident)+) => {
#[derive(Debug)]
enum VeryLongEnum {
$($ident,)+
}
impl TryFrom<&'static str> for VeryLongEnum {
type Error = &'static str;
fn try_from(s: &'static str) -> Result<VeryLongEnum, &'static str> {
match s {
$(stringify!($ident) => Ok(VeryLongEnum::$ident),)+
_ => Err("Invalid String")
}
}
}
}
}
go! { A B C D E }
fn main() {
let _ = dbg!(VeryLongEnum::try_from("A"));
let _ = dbg!(VeryLongEnum::try_from("E"));
let _ = dbg!(VeryLongEnum::try_from("F"));
}
Output:
[src/main.rs:24] VeryLongEnum::try_from("A") = Ok(
A,
)
[src/main.rs:25] VeryLongEnum::try_from("E") = Ok(
E,
)
[src/main.rs:26] VeryLongEnum::try_from("F") = Err(
"Invalid String",
)