1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use std::env;
use std::fmt;
use std::str::FromStr;

pub use ctflag_derive::*;

#[derive(Debug, Clone)]
pub enum FlagError {
    ParseError(ParseErrorStruct),
    MissingValue(String),
    UnrecognizedArg(String),
}

#[derive(Clone, Debug)]
pub struct ParseErrorStruct {
    pub type_str: &'static str,
    pub input: String,
    pub src: FromArgError,
}

pub type Result<T> = std::result::Result<T, FlagError>;

pub trait Flags: Sized {
    fn from_args(args: env::Args) -> Result<(Self, Vec<String>)>;
    fn description() -> String;
}

#[derive(Clone, Debug)]
pub struct FromArgError {
    msg: Option<String>,
}

pub type FromArgResult<T> = std::result::Result<T, FromArgError>;

pub trait FromArg: Sized {
    fn from_arg(value: &str) -> FromArgResult<Self>;
}

pub fn bool_from_arg(s: Option<&str>) -> FromArgResult<bool> {
    match s {
        Some(s) => s.parse::<bool>().map_err(|_| FromArgError::new()),
        None => Ok(true),
    }
}

pub fn option_from_arg<T: FromArg>(s: &str) -> FromArgResult<Option<T>> {
    <T as FromArg>::from_arg(s).map(Some)
}

impl<T> FromArg for T
where
    T: FromStr,
{
    fn from_arg(s: &str) -> FromArgResult<T> {
        <T as FromStr>::from_str(s).map_err(|_| FromArgError::new())
    }
}

impl fmt::Display for FlagError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            FlagError::ParseError(err) => {
                write!(
                    f,
                    "failed to parse \"{}\" as {} type",
                    &err.input, err.type_str
                )?;
                if let Some(msg) = &err.src.msg {
                    write!(f, ": {}", msg)?;
                }
            }
            FlagError::MissingValue(arg) => {
                write!(f, "missing value for argument \"{}\"", arg)?;
            }
            FlagError::UnrecognizedArg(arg) => {
                write!(f, "unrecognized argument \"{}\"", arg)?;
            }
        }
        Ok(())
    }
}

impl FromArgError {
    pub fn new() -> Self {
        FromArgError { msg: None }
    }

    pub fn with_message<T>(msg: T) -> Self
    where
        T: fmt::Display,
    {
        FromArgError {
            msg: Some(format!("{}", msg)),
        }
    }
}