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
/// Stores the options so our programs knows what to do.
///
/// Normaly you obtain this struct as a result of parsing the command line
/// arguments passed to the program.
///
/// In this program we have only three different flags that can be activated.
/// We store this information with three `bool`s. The remaining command line
/// arguments after the parsing are stored in a new `Vec<String>` named
/// `Options::rest`.
pub struct Options {
    /// Whether the `--version` flag was activated or not.
    pub version: bool,

    /// Whether the `--encode` flag was activated or not.
    pub encode: bool,

    /// Whether the `--decode` flag was activated or not.
    pub decode: bool,

    /// If the `--output` option was set, here is the program's output filename
    /// stored. Otherwise `None`.
    pub output: Option<String>,

    /// The remaining command line arguments that weren't parsed.
    pub rest: Vec<String>,
}

impl Options {
    /// Create a new `Options` struct with default values. It isn't intended to
    /// create it this way, but with `from_args`.
    fn new() -> Self {
        Options {
            version: false,
            encode: false,
            decode: false,
            output: None,
            rest: Vec::new(),
        }
    }

    /// Takes a vector of `String` and creates a `Options` struct.
    ///
    /// Usually you want to parse `std::env::args()` to detect when the
    /// different command line flags were activated. Note that normally the
    /// first element to appear in `std::env::args()` is the executable name,
    /// so you should skip it.
    ///
    /// # Examples
    ///
    /// ```
    /// use kripher::options::Options;
    /// use std::env;
    ///
    /// let args = env::args().skip(1);
    /// let o = Options::from_args(args);
    ///
    /// if o.version {
    ///     println!("The --version flag was active.")
    /// }
    /// ```
    pub fn from_args<A: Iterator<Item=String>>(args: A) -> Options {
        let mut options = Options::new();
        let mut has_output = false;

        for argument in args {
            if has_output && options.output.is_none() {
                options.output = Some(argument);
                continue;
            }

            match &argument[..] {
                "-v" | "--version" => options.version = true,
                "-e" | "--encode" => options.encode = true,
                "-d" | "--decode" => options.decode = true,
                "-o" | "--output" => has_output = true,
                _ => options.rest.push(argument),
            }
        }

        options
    }
}