rust_command_opt/
opt.rs

1use std::collections::HashMap;
2use std::env;
3
4/// # Opt
5/// main struct.
6///
7/// ### normal usage:
8/// ```
9/// use rust_command_opt::opt::Opt;
10///
11/// fn main() {
12///     let opt = Opt::init();
13///     if let Some(value) = opt.get_opt_short("-a") {
14///         println!("{}", value.one());
15///     }
16/// }
17///
18/// ```
19pub struct Opt {
20    pub opts: HashMap<String, OptValue>,
21}
22
23impl Opt {
24    /// Init with command args.
25    pub fn init() -> Opt {
26        let mut args: Vec<String> = env::args().collect();
27        args.remove(0);
28        Opt::with(args)
29    }
30
31    /// Init with you custom args.
32    /// (Usually used in test)
33    pub fn with(args: Vec<String>) -> Opt {
34        let mut map: HashMap<String, OptValue> = HashMap::default();
35        let mut last_opt = "".to_string();
36        for v in args {
37            if let Some(s) = v.get(0..1) {
38                if s == "-" {
39                    match v.parse::<f32>() {
40                        Ok(_) => {
41                            match map.get_mut(&last_opt) {
42                                Some(find) => match find {
43                                    OptValue::One(one) => {
44                                        if one == "" {
45                                            map.insert(last_opt.clone(), OptValue::One(v));
46                                        } else {
47                                            let mut vecv = vec![one.clone()];
48                                            vecv.push(v.clone());
49                                            map.insert(last_opt.clone(), OptValue::Many(vecv));
50                                        }
51                                    }
52                                    OptValue::Many(many) => {
53                                        many.push(v);
54                                    }
55                                },
56                                None => {
57                                    map.insert(last_opt.clone(), OptValue::One(v));
58                                }
59                            };
60                        }
61                        Err(_) => {
62                            last_opt = v.clone();
63                            map.insert(v, OptValue::One("".to_string()));
64                        }
65                    }
66                } else {
67                    match map.get_mut(&last_opt) {
68                        Some(find) => {
69                            match find {
70                                OptValue::One(one) => {
71                                    if one == "" {
72                                        map.insert(last_opt.clone(), OptValue::One(v));
73                                    } else {
74                                        let mut vecv = vec![one.clone()];
75                                        vecv.push(v.clone());
76                                        map.insert(last_opt.clone(), OptValue::Many(vecv));
77                                    }
78                                }
79                                OptValue::Many(many) => {
80                                    many.push(v);
81                                }
82                            };
83                        }
84                        None => {
85                            map.insert(last_opt.clone(), OptValue::One(v));
86                        }
87                    }
88                }
89            }
90        }
91        Opt { opts: map }
92    }
93
94    /// Basic get opt method.
95    /// ### usage:
96    /// ```
97    /// use rust_command_opt::opt::Opt;
98    ///
99    /// let opt = Opt::init();
100    /// if let Some(value) = opt.get_opt(Opt::one("-a")) {
101    ///     println!("{}", value.one());
102    /// }
103    ///
104    /// ```
105    pub fn get_opt(&self, op_name: OptOption) -> Option<OptValue> {
106        match op_name {
107            OptOption::One(one) => match self.opts.get(&one.to_string()) {
108                Some(real) => Some(real.clone()),
109                None => None,
110            },
111            OptOption::ShortLong(short, long) => {
112                if let Some(find_short) = self.opts.get(short) {
113                    Some(find_short.clone())
114                } else {
115                    if let Some(find_long) = self.opts.get(long) {
116                        Some(find_long.clone())
117                    } else {
118                        None
119                    }
120                }
121            }
122        }
123    }
124
125    /// Only use short option, and have a default value.
126    /// ### usage
127    /// ```
128    /// use rust_command_opt::opt::Opt;
129    ///
130    /// let opt = Opt::init();
131    /// let value = opt.get_opt_short_with_default("-a", "default_value").one();
132    /// ```
133    pub fn get_opt_short_with_default(&self, name: &str, default: &str) -> OptValue {
134        if let Some(v) = self.get_opt(OptOption::One(name)) {
135            if v.one() == "" {
136                OptValue::One(default.to_string())
137            } else {
138                v
139            }
140        } else {
141            OptValue::One(default.to_string())
142        }
143    }
144
145    /// Use short and full option, and have a default value.
146    /// ### usage
147    /// ```
148    /// use rust_command_opt::opt::Opt;
149    ///
150    /// let opt = Opt::init();
151    /// let value = opt.get_opt_normal_with_default("-a", "--all", "default_value").one();
152    /// ```
153    pub fn get_opt_normal_with_default(&self, short: &str, long: &str, default: &str) -> OptValue {
154        if let Some(v) = self.get_opt(Opt::normal(short, long)) {
155            if v.one() == "" {
156                OptValue::One(default.to_string())
157            } else {
158                v
159            }
160        } else {
161            OptValue::One(default.to_string())
162        }
163    }
164
165    /// Only use short option.
166    /// ```
167    /// use rust_command_opt::opt::Opt;
168    ///
169    /// let opt = Opt::init();
170    /// if let Some(value) = opt.get_opt_short("-a") {
171    ///     println!("{}", value.one());
172    /// }
173    /// ```
174    pub fn get_opt_short(&self, name: &str) -> Option<OptValue> {
175        self.get_opt(OptOption::One(name))
176    }
177
178    /// Only use short option.
179    /// ```
180    /// use rust_command_opt::opt::Opt;
181    ///
182    /// let opt = Opt::init();
183    /// if let Some(value) = opt.get_opt_normal("-a", "--all") {
184    ///     println!("{}", value.one());
185    /// }
186    /// ```
187    pub fn get_opt_normal(&self, short: &str, long: &str) -> Option<OptValue> {
188        self.get_opt(Opt::normal(short, long))
189    }
190
191    /// Make short option
192    pub fn one(short: &str) -> OptOption {
193        OptOption::One(short)
194    }
195
196    /// Make short and full option
197    pub fn normal<'a>(short: &'a str, long: &'a str) -> OptOption<'a> {
198        OptOption::ShortLong(short, long)
199    }
200}
201
202/// Contains value
203///
204/// ### Many
205/// Many value in one option.
206///
207/// **like:**
208/// `you_program -p a b c d`
209///
210/// ### One
211/// Only one value in one option.
212///
213/// **like:**
214/// `you_program -p a`
215#[derive(Clone)]
216pub enum OptValue {
217    Many(Vec<String>),
218    One(String),
219}
220
221impl OptValue {
222    /// Get one value in `OptValue`.
223    ///
224    /// if only one value in `OptValue`, you get it.
225    /// or you will get the first.
226    pub fn one(&self) -> String {
227        match self {
228            OptValue::One(one) => one.to_string(),
229            OptValue::Many(many) => many[0].to_string(),
230        }
231    }
232
233    /// Get many value in `OptValue`.
234    ///
235    /// if only one value in `OptValue`, you will also get a vector.
236    /// or you will get the vector.
237    pub fn many(&self) -> Vec<String> {
238        match self {
239            OptValue::One(one) => vec![one.to_string()],
240            OptValue::Many(many) => many.clone(),
241        }
242    }
243}
244
245pub enum OptOption<'a> {
246    One(&'a str),
247    ShortLong(&'a str, &'a str),
248}