Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use enums in structopt?

I'd like to make StructOpt work with enums such that every time a user passes -d sunday it'd parsed as a Day::Sunday:

#[macro_use]
extern crate structopt;

use std::path::PathBuf;
use structopt::StructOpt;

// My enum
enum Day {
    Sunday, Monday
}

#[derive(Debug, StructOpt)]
#[structopt(name = "example", about = "An example of StructOpt usage.")]
struct Opt {
    /// Set speed
    #[structopt(short = "s", long = "speed", default_value = "42")]
    speed: f64,
    /// Input file
    #[structopt(parse(from_os_str))]
    input: PathBuf,
    /// Day of the week
    #[structopt(short = "d", long = "day", default_value = Day::Monday)]
    day: Day,
}

fn main() {
    let opt = Opt::from_args();
    println!("{:?}", opt);
}

My current best solution is to use Option<String> as a type and pass a custom parse_day():

fn parse_day(day: &str) -> Result<Day, ParseError> {
    match day {
        "sunday" => Ok(Day::Sunday),
        _ => Ok(Day::Monday)
    }
    Err("Could not parse a day")
}
like image 365
H. Desane Avatar asked Feb 14 '19 09:02

H. Desane


2 Answers

Struct-opt accepts any type which implements FromStr, which is not far away from your parse_day function:

use std::str::FromStr;

// any error type implementing Display is acceptable.
type ParseError = &'static str;

impl FromStr for Day {
    type Err = ParseError;
    fn from_str(day: &str) -> Result<Self, Self::Err> {
        match day {
            "sunday" => Ok(Day::Sunday),
            "monday" => Ok(Day::Monday),
            _ => Err("Could not parse a day"),
        }
    }
}

Additionally, the default_value should be a string, which will be interpreted into a Day using from_str.

#[structopt(short = "d", long = "day", default_value = "monday")]
day: Day,
like image 97
kennytm Avatar answered Sep 18 '22 08:09

kennytm


@kennytm's approach works, but the arg_enum! macro is a more concise way of doing it, as demonstrated in this example from structopt:

arg_enum! {
    #[derive(Debug)]
    enum Day {
        Sunday,
        Monday
    }
}

#[derive(StructOpt, Debug)]
struct Opt {
    /// Important argument.
    #[structopt(possible_values = &Day::variants(), case_insensitive = true)]
    i: Day,
}

fn main() {
    let opt = Opt::from_args();
    println!("{:?}", opt);
}

This will let you parse weekdays as Sunday or sunday.

like image 31
almel Avatar answered Sep 21 '22 08:09

almel