1use std::cell::RefCell;
35use std::collections::HashMap;
36use std::error::Error;
37use std::fmt::Display;
38
39#[derive(Debug)]
40struct InvalidCommandError {
41 reason: InvalidCommandReasons
42}
43
44impl InvalidCommandError {
45 pub fn new(reason: InvalidCommandReasons) -> InvalidCommandError {
46 InvalidCommandError { reason }
47 }
48}
49
50impl Display for InvalidCommandError {
51 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
52 match &self.reason {
53 InvalidCommandReasons::Unexpected(s) => {
54 write!(f, "Invalid command, unexpected token '{}'", s)
55 },
56 InvalidCommandReasons::Duplicate(s) => {
57 write!(f, "Invalid command, duplicate token '{}'", s)
58 },
59 InvalidCommandReasons::Missing => {
60 write!(f, "Invalid command, missing argument")
61 }
62 }
63 }
64}
65
66impl Error for InvalidCommandError {
67
68}
69
70#[derive(Debug)]
71enum InvalidCommandReasons {
72 Unexpected(String),
73 Missing,
74 Duplicate(String),
75}
76
77#[derive(Clone, Debug)]
78enum ArgTypes {
79 Param(bool),
80 Input,
81 Short(char),
82 None
83}
84
85#[derive(Clone, Debug)]
98pub struct Arg {
99 name: String,
100 arg_type: ArgTypes,
101 expecting: bool,
102}
103
104impl Arg {
105 pub fn new() -> Arg {
112
113 Arg { name: String::new(), arg_type: ArgTypes::None, expecting: false}
114 }
115
116 pub fn param(self, name: &str) -> Arg {
125 Arg { name: String::from(name), arg_type: ArgTypes::Param(false), expecting: false }
126 }
127
128 pub fn input(self, name: &str) -> Arg {
136 Arg { name: String::from(name), arg_type: ArgTypes::Input, expecting: true }
137 }
138
139 pub fn flag(self, name: &str) -> Arg {
147 Arg { name: String::from(name), arg_type: self.arg_type, expecting: false }
148 }
149
150 pub fn short(self, ch: char) -> Arg {
158 Arg { name: self.name, arg_type: ArgTypes::Short(ch), expecting: self.expecting }
159 }
160
161 fn set_used(&mut self, used: bool) {
162 self.arg_type = ArgTypes::Param(used);
163 }
164}
165
166pub struct Parser {
179 args: RefCell<Vec<Arg>>,
180}
181
182impl Parser {
183
184 pub fn new() -> Parser {
191 Parser { args: RefCell::new(vec![]) }
192 }
193
194 pub fn add_arg(&self, arg: Arg) {
204 self.args.borrow_mut().push(arg);
205 }
206
207 pub fn add_args(&self, mut args: Vec<Arg>) {
220 self.args.borrow_mut().append(&mut args);
221 }
222
223 pub fn args(&self) -> Vec<Arg> {
230 self.args.borrow().clone()
231 }
232
233 pub fn len(&self) -> usize {
240 self.args.borrow().len()
241 }
242
243 fn get_err(&self, reason: InvalidCommandReasons) -> Result<HashMap<String, Option<String>>, Box<dyn Error>> {
244 return Err(Box::new(InvalidCommandError::new(reason)))
245 }
246
247 pub fn parse(&self, args: &mut impl Iterator<Item = String>) -> Result<HashMap<String, Option<String>>, Box<dyn Error>> {
269 let mut hashmap: HashMap<String, Option<String>> = HashMap::new();
270 let mut prev_arg: Option<Box<Arg>> = None;
271 let mut args = args.peekable();
272 let mut parser_args = self.args.clone().take();
273
274 while let Some(c_arg) = args.next() {
275 if c_arg.starts_with("-") {
276 if prev_arg.is_some() {
278 return self.get_err(InvalidCommandReasons::Unexpected(c_arg));
279 }
280
281 if c_arg.starts_with("--") {
282 let mut found = false;
284 for arg in &parser_args {
285 if c_arg.ends_with(&arg.name) && c_arg.len() == arg.name.len() + 2 {
286 found = true;
287 if arg.expecting {
288 prev_arg = Some(Box::new(arg.clone()));
289 } else {
290 match hashmap.insert(arg.name.clone(), None) {
291 Some(_) => return self.get_err(InvalidCommandReasons::Duplicate(c_arg)),
292 None => {},
293 };
294 prev_arg = None;
295 }
296 }
297 }
298 if !found {
299 return self.get_err(InvalidCommandReasons::Unexpected(c_arg));
300 }
301 } else {
302 let mut found = false;
304 for arg in &parser_args {
305 if let ArgTypes::Short(c) = arg.arg_type {
306 if c_arg.ends_with(c) && c_arg.len() == 2 {
307 found = true;
308 if arg.expecting {
309 prev_arg = Some(Box::new(arg.clone()));
310 } else {
311 match hashmap.insert(arg.name.clone(), None) {
312 Some(_) => return self.get_err(InvalidCommandReasons::Duplicate(c_arg)),
313 None => {},
314 };
315 prev_arg = None;
316 }
317 }
318 }
319 }
320 if !found {
321 return self.get_err(InvalidCommandReasons::Unexpected(c_arg));
322 }
323 }
324 } else {
325 if prev_arg.is_none() {
327 let mut found = false;
329 for arg in &mut parser_args {
330 if let ArgTypes::Param(used) = arg.arg_type {
331 if used {
332 continue;
333 }
334
335 match hashmap.insert(arg.name.clone(), Some(c_arg.clone())) {
336 Some (_) => return self.get_err(InvalidCommandReasons::Duplicate(c_arg)),
337 None => {}
338 };
339 arg.set_used(true);
340 prev_arg = None;
341 found = true;
342 break;
343 }
344 }
345
346 if !found {
347 return self.get_err(InvalidCommandReasons::Unexpected(c_arg));
348 }
349 } else {
350 match hashmap.insert(prev_arg.unwrap().name, Some(c_arg.clone())) {
351 Some (_) => return self.get_err(InvalidCommandReasons::Duplicate(c_arg)),
352 None => {}
353 }
354 prev_arg = None;
355 }
356 };
357
358 if args.peek().is_none() && prev_arg.is_some() {
359 return self.get_err(InvalidCommandReasons::Missing);
360 }
361 }
362
363 for arg in parser_args {
364 if let ArgTypes::Param(false) = arg.arg_type {
365 return self.get_err(InvalidCommandReasons::Missing);
366 }
367 }
368
369 Ok(hashmap)
370 }
371}
372
373
374
375#[cfg(test)]
377mod tests {
378 use super::*;
379
380 #[test]
381 fn create_arg() {
382 let default = Arg::new().input("default");
383 assert_eq!(default.name, "default");
384 assert_eq!(default.expecting, true);
385
386 let short = Arg::new().input("short").short('s');
387 assert_eq!(short.name, "short");
388 if let ArgTypes::Short(c) = short.arg_type {
389 assert_eq!(c, 's');
390 } else {
391 assert!(false);
392 }
393 assert_eq!(short.expecting, true);
394
395 let flag = Arg::new().flag("flag").short( 'f');
396 assert_eq!(flag.expecting, false);
397 if let ArgTypes::Short(c) = flag.arg_type {
398 assert_eq!(c, 'f');
399 } else {
400 assert!(false);
401 }
402 assert_eq!(flag.name, "flag");
403
404 let mut param = Arg::new().param("param");
405 assert_eq!(param.expecting, false);
406 if let ArgTypes::Param(used) = param.arg_type {
407 assert!(!used);
408 } else {
409 assert!(false);
410 }
411 assert_eq!(param.name, "param");
412
413 param.set_used(true);
414 if let ArgTypes::Param(used) = param.arg_type {
415 assert!(used);
416 } else {
417 assert!(false);
418 }
419 }
420
421 #[test]
422 fn append_args() {
423 let default = Arg::new().input("default");
424 let short = Arg::new().input("short").short('s');
425 let flag = Arg::new().flag("flag").short( 'f');
426
427 let parser = Parser::new();
428 parser.add_arg(default);
429 assert_eq!(parser.len(), 1);
430 parser.add_args(vec![short, flag]);
431 assert_eq!(parser.len(), 3);
432 assert_eq!(parser.args()[2].name, "flag");
433 }
434
435 #[test]
436 fn test_parse_err() {
437 let default = Arg::new().input("default");
438 let short = Arg::new().input("short").short('s');
439 let flag = Arg::new().flag("flag").short( 'f');
440 let param1 = Arg::new().param("p1");
441 let param2 = Arg::new().param("p2");
442
443 let parser = Parser::new();
444 parser.add_args(vec![default, short, flag, param1, param2]);
445
446 let mut cmd = "--short short_inp -s s_inp p1 p2"
448 .split_whitespace()
449 .map(|s| { String::from(s) });
450
451 let res = parser.parse(&mut cmd);
452 assert!(res.is_err());
453
454 let mut cmd = "--default -f p1 p2"
456 .split_whitespace()
457 .map(|s| { String::from(s) });
458
459 let res = parser.parse(&mut cmd);
460 assert!(res.is_err());
461
462 let mut cmd = "p1 p2 -f dsjfhkjuh"
464 .split_whitespace()
465 .map(|s| { String::from(s) });
466
467 let res = parser.parse(&mut cmd);
468 assert!(res.is_err());
469
470 let mut cmd = "p1 p2 --default"
472 .split_whitespace()
473 .map(|s| { String::from(s) });
474
475 let res = parser.parse(&mut cmd);
476 assert!(res.is_err());
477
478 let mut cmd = "p1 -f"
480 .split_whitespace()
481 .map(|s| { String::from(s) });
482
483 let res = parser.parse(&mut cmd);
484 assert!(res.is_err());
485
486 let mut cmd = "p1 p2 --doesntexist"
488 .split_whitespace()
489 .map(|s| { String::from(s) });
490
491 let res = parser.parse(&mut cmd);
492 assert!(res.is_err());
493
494 }
495
496 #[test]
497 pub fn test_parse_success() {
498 let default = Arg::new().input("default");
499 let short = Arg::new().input("short").short('s');
500 let flag = Arg::new().flag("flag").short( 'f');
501 let param1 = Arg::new().param("file");
502 let param2 = Arg::new().param("path");
503
504 let parser = Parser::new();
505 parser.add_args(vec![default, short, flag, param1, param2]);
506
507 let mut cmd = "--default def_arg filename -s s_arg -f pathname"
508 .split_whitespace()
509 .map(|s| { String::from(s) });
510
511 let res = parser.parse(&mut cmd);
512 assert!(res.is_ok());
513
514 let res = res.unwrap();
515 assert_eq!(res.len(), 5);
516 assert!(res.contains_key("default"));
517 assert_eq!(res.get("default").unwrap(), &Some(String::from("def_arg")));
518 assert!(res.contains_key("short"));
519 assert_eq!(res.get("short").unwrap(), &Some(String::from("s_arg")));
520 assert!(res.contains_key("flag"));
521 assert_eq!(res.get("flag").unwrap(), &None);
522 assert!(res.contains_key("file"));
523 assert_eq!(res.get("file").unwrap(), &Some(String::from("filename")));
524 assert!(res.contains_key("path"));
525 assert_eq!(res.get("path").unwrap(), &Some(String::from("pathname")));
526 }
527}