How do I get an enum as a string?
RustRust Problem Overview
I have an enum with many values and I'd like to write the name of one of its values to a stream:
enum Foo {
Bar = 0x00,
Baz = 0x01,
Qux = 0x02,
// ...
Quux = 0xFF,
}
I can derive Debug
and do
writer.write(format!("I am {:?}", Foo::Quux).as_bytes())
which will output e.g. I am Quux
. That's fine, except that
- I want to do this for user-facing output, so
Debug
isn't appropriate - It would be very helpful to get the enum as a string (rather than writing directly to a stream), because then I can incorporate its length into some wonky formatting calculations I want to do.
Rust Solutions
Solution 1 - Rust
Probably the easiest way would be to implement Display
by calling into Debug
:
impl fmt::Display for Foo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
// or, alternatively:
// fmt::Debug::fmt(self, f)
}
}
Then you can use to_string()
to get a String
representation:
let s: String = Foo::Quux.to_string();
If you have many enums which you want to print, you can write a trivial macro to generate the above implementation of Display
for each of them.
Unfortunately, in Rust reflective programming is somewhat difficult. There is no standard way, for example, to get a list of all variants of a C-like enum. Almost always you have to abstract the boilerplate with custom-written macros (or finding something on crates.io). Maybe this will change in future if someone would write an RFC and it would get accepted.
Solution 2 - Rust
Since the names of enum variants are fixed, you don't need to allocate a String
, a &'static str
will suffice. A macro can remove the boilerplate:
macro_rules! enum_str {
(enum $name:ident {
$($variant:ident = $val:expr),*,
}) => {
enum $name {
$($variant = $val),*
}
impl $name {
fn name(&self) -> &'static str {
match self {
$($name::$variant => stringify!($variant)),*
}
}
}
};
}
enum_str! {
enum Foo {
Bar = 0x00,
Baz = 0x01,
Qux = 0x02,
//...
Quux = 0xFF,
}
}
fn main() {
assert_eq!(Foo::Baz.name(), "Baz");
}
Even better, you can derive these with a crate like strum_macros.
In strum 0.10, you can use AsStaticRef
/ AsStaticStr
to do the exact same code:
extern crate strum; // 0.10.0
#[macro_use]
extern crate strum_macros; // 0.10.0
use strum::AsStaticRef;
#[derive(AsStaticStr)]
enum Foo {
Bar = 0x00,
Baz = 0x01,
Qux = 0x02,
//...
Quux = 0xFF,
}
fn main() {
assert_eq!(Foo::Baz.as_static(), "Baz");
}
In strum 0.9, the string slice's lifetime is not 'static
in this case:
#[macro_use]
extern crate strum_macros; // 0.9.0
#[derive(AsRefStr)]
enum Foo {
Bar = 0x00,
Baz = 0x01,
Qux = 0x02,
//...
Quux = 0xFF,
}
fn main() {
assert_eq!(Foo::Baz.as_ref(), "Baz");
}