flag_parser/
lib.rs

1//! #Flag Parser
2//! Argument parsing for command line flags.
3//!
4//! ## Usage
5//!
6//! ```Rust
7//! let input = "-a -b -c -d --long-flag-a --long-flag-b --long-flag-c";
8//! let flags = flag_parser::get_flags(input);
9//! // flags = ["a", "b", "c", "d", "long-flag-a", "long-flag-b", "long-flag-c"]
10//!
11//! flags.contains("a") // true
12//! ```
13
14use std::collections::HashSet;
15
16/// Returns a vector with all flags in a given input
17///
18/// It assumes that all characters in the input are
19/// convertable to a single u8 integer like ASCII.
20pub fn get_flags(input: &str) -> Vec<&str> {
21    let mut found_flags: HashSet<&str> = HashSet::new();
22    input.split_whitespace()
23        .filter(|word| word.starts_with("-"))
24        .for_each(|word| {
25            if word.starts_with("--") { found_flags.insert(&word[2..]); } else {
26                word[1..].as_bytes()
27                    .iter()
28                    .enumerate()
29                    .for_each(|(i, _)| {
30                        found_flags.insert(&word[i + 1..i + 2]);
31                    })
32            }
33        });
34
35    found_flags.into_iter().collect()
36}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41
42    #[test]
43    fn short_flags() {
44        let input = "-a -b -c -d";
45        let flags = get_flags(input);
46
47        assert_eq!(flags.len(), 4);
48        assert!(flags.contains(&"a"));
49        assert!(flags.contains(&"b"));
50        assert!(flags.contains(&"c"));
51        assert!(flags.contains(&"d"));
52        assert!(!flags.contains(&"e"));
53    }
54
55    #[test]
56    fn multiple_short_flags() {
57        let input = "-abcdabcd";
58        let flags = get_flags(input);
59
60        assert_eq!(flags.len(), 4);
61        assert!(flags.contains(&"a"));
62        assert!(flags.contains(&"b"));
63        assert!(flags.contains(&"c"));
64        assert!(flags.contains(&"d"));
65        assert!(!flags.contains(&"e"));
66    }
67
68    #[test]
69    fn long_flags() {
70        let input = "--long-flag-a --long-flag-b --long-flag-c";
71        let flags = get_flags(input);
72
73        assert_eq!(flags.len(), 3);
74        assert!(flags.contains(&"long-flag-a"));
75        assert!(flags.contains(&"long-flag-b"));
76        assert!(flags.contains(&"long-flag-c"));
77        assert!(!flags.contains(&"long-flag-d"));
78    }
79
80    #[test]
81    fn long_and_short_flags() {
82        let input = "-a -b -c -d --long-flag-a --long-flag-b --long-flag-c";
83        let flags = get_flags(input);
84
85        assert_eq!(flags.len(), 7);
86        assert!(flags.contains(&"a"));
87        assert!(flags.contains(&"b"));
88        assert!(flags.contains(&"c"));
89        assert!(flags.contains(&"d"));
90        assert!(!flags.contains(&"e"));
91        assert!(flags.contains(&"long-flag-a"));
92        assert!(flags.contains(&"long-flag-b"));
93        assert!(flags.contains(&"long-flag-c"));
94        assert!(!flags.contains(&"long-flag-d"));
95    }
96
97    #[test]
98    fn long_and_multiple_short_flags() {
99        let input = "-abcd --long-flag-a --long-flag-b --long-flag-c";
100        let flags = get_flags(input);
101
102        assert_eq!(flags.len(), 7);
103        assert!(flags.contains(&"a"));
104        assert!(flags.contains(&"b"));
105        assert!(flags.contains(&"c"));
106        assert!(flags.contains(&"d"));
107        assert!(!flags.contains(&"e"));
108        assert!(flags.contains(&"long-flag-a"));
109        assert!(flags.contains(&"long-flag-b"));
110        assert!(flags.contains(&"long-flag-c"));
111        assert!(!flags.contains(&"long-flag-d"));
112    }
113}