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}