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
pub type Result<T> = ::std::result::Result<T, Error>;
use opts::Kind;
use std::{error, fmt};

#[derive(Debug, PartialEq, Eq, Clone)]
/// An error dealing with an option
pub enum Error {
    /// An unimplemented but valid option
    Unimplemented(Kind, &'static str),
    /// An unknown (and unsupported) option
    Unknown(Kind, String),
    /// An error parsing a numeric option
    ParseInt(std::num::ParseIntError),
    /// The directory flag is specified, but the target is not a directory.
    NotDirectory(String),
    /// Two or more mutually exclusive options have been selected.
    ConflictingOption(&'static str),
}

pub trait Unimplemented {
    /// Kind of option; used for reporting errors
    const KIND: Kind;
    /// Slice of valid but as yet unimplemented options
    const UNIMPLEMENTED: &'static [&'static str];

    /// check if a flag is valid but unimplemented
    fn check_if_implemented(flag: &str) -> Result<()> {
        for s in Self::UNIMPLEMENTED {
            if flag == *s {
                return Err(Error::Unimplemented(Self::KIND, *s));
            }
        }
        Ok(())
    }
    /// helper function; an invalid flag key
    fn unknown<T>(flag: String) -> Result<T> { Err(Error::Unknown(Self::KIND, flag)) }
}

impl From<std::num::ParseIntError> for Error {
    fn from(err: std::num::ParseIntError) -> Self { Error::ParseInt(err) }
}
impl error::Error for Error {}

impl fmt::Display for Kind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Kind::BasicOption => write!(f, "basic option"),
            Kind::CFlag => write!(f, "conversion flag"),
            Kind::IFlag => write!(f, "iflag"),
            Kind::OFlag => write!(f, "oflag"),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::Unknown(kind, arg) => write!(f, "unknown {} option \"{}\"", kind, arg),
            Error::Unimplemented(kind, arg) => write!(f, "unimplemented {} option \"{}\"", kind, arg),
            Error::ParseInt(err) => err.fmt(f),
            Error::NotDirectory(s) => write!(
                f,
                "flag 'directory' was specified for path {}, but it was not a directory",
                s
            ),
            Error::ConflictingOption(s) => write!(f, "conflicting options: {}", s),
        }
    }
}