Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enum to &str / &str to Enum

Tags:

enums

rust

Wondering if there's a "proper" way of converting an Enum to a &str and back.

The problem I'm trying to solve:

In the clap crate, args/subcommands are defined and identified by &strs. (Which I'm assuming don't fully take advantage of the type checker.) I'd like to pass a Command Enum to my application instead of a &str which would be verified by the type-checker and also save me from typing (typo-ing?) strings all over the place.

This is what I came up with from searching StackOverflow and std:

use std::str::FromStr;

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Command {
    EatCake,
    MakeCake,
}

impl FromStr for Command {
    type Err = ();

    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
        match s.to_ascii_lowercase().as_str() {
            "eat-cake" => Ok(Self::EatCake),
            "make-cake" => Ok(Self::MakeCake),
            _ => Err(()),
        }
    }
}

impl<'a> From<Command> for &'a str {
    fn from(c: Command) -> Self {
        match c {
            Command::EatCake => "eat-cake",
            Command::MakeCake => "make-cake",
        }
    }
}

fn main() {
    let command_from_str: Command = "eat-cake".to_owned().parse().unwrap();
    let str_from_command: &str = command_from_str.into();

    assert_eq!(command_from_str, Command::EatCake);
    assert_eq!(str_from_command, "eat-cake");
}

And here's a working playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b5e9ac450fd6a79b855306e96d4707fa

Here's an abridged version of what I'm running in clap.

let matches = App::new("cake")
    .setting(AppSettings::SubcommandRequiredElseHelp)
    // ...
    .subcommand(
        SubCommand::with_name(Command::MakeCake.into())
            // ...
    )
    .subcommand(
        SubCommand::with_name(Command::EatCake.into())
            // ...
    )
    .get_matches();

It seems to work, but I'm not sure if I'm missing something / a bigger picture.

Related:

  • How to use an internal library Enum for Clap Args
  • How do I return an error within match statement while implementing from_str in rust?

Thanks!

like image 320
tnahs Avatar asked Jul 24 '26 02:07

tnahs


1 Answers

The strum crate may save you some work. Using strum I was able to get the simple main() you have to work without any additional From implementations.

use strum_macros::{Display, EnumString, IntoStaticStr};

#[derive(Debug, Clone, Copy, PartialEq)]
#[derive(Display, EnumString, IntoStaticStr)]  // strum macros.
pub enum Command {
    #[strum(serialize = "eat-cake")]
    EatCake,
    
    #[strum(serialize = "make-cake")]
    MakeCake,
}
fn main() {
    let command_from_str: Command = "eat-cake".to_owned().parse().unwrap();
    let str_from_command: &str    = command_from_str.into();

    assert_eq!(command_from_str, Command::EatCake);
    assert_eq!(str_from_command, "eat-cake");
}
like image 89
Todd Avatar answered Jul 26 '26 17:07

Todd



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!