1use multimap::MultiMap;
2
3pub struct Arguments {
5 arg_map: MultiMap<String, Option<String>>,
6}
7
8impl Arguments {
9 pub fn parse<S: AsRef<str>>(args: &[S]) -> Arguments {
18 let mut arg_map = MultiMap::new();
19 for (key, val) in args.iter().map(|s| s.as_ref()).zip(
20 args.iter()
21 .map(|s| s.as_ref())
22 .skip(1)
23 .chain(std::iter::once("")),
24 ) {
25 if let Some(stripped) = key.strip_prefix('-') {
26 arg_map.insert(
27 stripped.to_string(),
28 if val.is_empty() || val.starts_with('-') {
29 None
30 } else {
31 Some(val.to_string())
32 },
33 );
34 }
35 }
36 Arguments { arg_map }
37 }
38
39 pub fn contains(&self, key: &str) -> bool {
45 self.arg_map.contains_key(key)
46 }
47
48 pub fn contains_val(&self, key: &str) -> bool {
55 self.arg_map
56 .get_vec(key)
57 .and_then(|vals| vals.iter().find(|&val| val.is_some()))
58 .is_some()
59 }
60
61 pub fn is_empty(&self) -> bool {
63 self.arg_map.is_empty()
64 }
65
66 pub fn get(&self, key: &str) -> Option<Option<&str>> {
72 Some(self.arg_map.get(key)?.as_ref().map(String::as_ref))
73 }
74
75 pub fn get_vec(&self, key: &str) -> Option<&Vec<Option<String>>> {
81 self.arg_map.get_vec(key)
82 }
83
84 pub fn len(&self) -> usize {
86 self.arg_map.len()
87 }
88}
89
90#[cfg(test)]
91mod test {
92 use super::Arguments;
93
94 #[test]
95 fn empty() {
96 let args = Arguments::parse::<String>(&[]);
97 assert!(args.is_empty());
98 assert_eq!(args.len(), 0);
99 }
100
101 #[test]
102 fn no_arg() {
103 let args = Arguments::parse(&["arg"]);
104 assert!(args.is_empty());
105 assert_eq!(args.len(), 0);
106 }
107
108 #[test]
109 fn one_empty() {
110 let args = Arguments::parse(&["-key"]);
111 assert!(!args.is_empty());
112 assert_eq!(args.len(), 1);
113 assert!(args.contains("key"));
114 assert!(!args.contains_val("key"));
115 assert!(args.get("key").is_some());
116 assert_eq!(args.get_vec("key").unwrap().len(), 1);
117 }
118
119 #[test]
120 fn one_key() {
121 let args = Arguments::parse(&["-key", "val"]);
122 assert!(!args.is_empty());
123 assert_eq!(args.len(), 1);
124 assert!(args.contains("key"));
125 assert!(args.contains_val("key"));
126 assert!(args.get("key").is_some());
127 assert_eq!(args.get("key").unwrap().unwrap(), "val");
128 assert_eq!(args.get_vec("key").unwrap().len(), 1);
129 }
130
131 #[test]
132 fn one_key_repeated() {
133 let args = Arguments::parse(&["-key", "val", "-key", "val2"]);
134 assert!(!args.is_empty());
135 assert_eq!(args.len(), 1);
136 assert!(args.contains("key"));
137 assert!(args.contains_val("key"));
138 assert!(args.get("key").is_some());
139 assert_eq!(args.get("key").unwrap().unwrap(), "val");
140 assert_eq!(
141 args.get_vec("key").unwrap(),
142 &vec!(Some("val".to_string()), Some("val2".to_string()))
143 );
144 assert_eq!(args.get_vec("key").unwrap().len(), 2);
145 }
146
147 #[test]
148 fn one_key_cut_short() {
149 let args = Arguments::parse(&["-key", "-key", "val2"]);
150 assert!(!args.is_empty());
151 assert_eq!(args.len(), 1);
152 assert!(args.contains("key"));
153 assert!(args.contains_val("key"));
154 assert!(args.get("key").is_some());
155 assert_eq!(args.get("key").unwrap(), None);
156 assert_eq!(
157 args.get_vec("key").unwrap(),
158 &vec!(None, Some("val2".to_string()))
159 );
160 assert_eq!(args.get_vec("key").unwrap().len(), 2);
161 }
162
163 #[test]
164 fn two_keys() {
165 let args = Arguments::parse(&["-key", "val", "-key2", "val2"]);
166 assert!(!args.is_empty());
167 assert_eq!(args.len(), 2);
168 assert!(args.contains("key"));
169 assert!(args.contains("key2"));
170 assert!(args.contains_val("key"));
171 assert!(args.contains_val("key2"));
172 assert!(args.get("key").is_some());
173 assert!(args.get("key2").is_some());
174 assert_eq!(args.get("key").unwrap().unwrap(), "val");
175 assert_eq!(args.get("key2").unwrap().unwrap(), "val2");
176 assert_eq!(args.get_vec("key").unwrap().len(), 1);
177 assert_eq!(args.get_vec("key2").unwrap().len(), 1);
178 }
179
180 #[test]
181 fn two_keys_cut_short() {
182 let args = Arguments::parse(&["-key", "-key2", "val2"]);
183 assert!(!args.is_empty());
184 assert_eq!(args.len(), 2);
185 assert!(args.contains("key"));
186 assert!(args.contains("key2"));
187 assert!(!args.contains_val("key"));
188 assert!(args.contains_val("key2"));
189 assert!(args.get("key").is_some());
190 assert!(args.get("key2").is_some());
191 assert_eq!(args.get("key").unwrap(), None);
192 assert_eq!(args.get("key2").unwrap().unwrap(), "val2");
193 assert_eq!(args.get_vec("key").unwrap().len(), 1);
194 assert_eq!(args.get_vec("key2").unwrap().len(), 1);
195 }
196
197 #[test]
198 fn ergonomics() {
199 let sys_args: Vec<String> = vec!["-key".into(), "val".into()];
200 let args = Arguments::parse(&sys_args);
201 assert!(!args.is_empty());
202 assert_eq!(args.len(), 1);
203 assert!(args.contains("key"));
204 assert!(args.contains_val("key"));
205 assert!(args.get("key").is_some());
206 assert_eq!(args.get("key").unwrap().unwrap(), "val");
207 assert_eq!(args.get_vec("key").unwrap().len(), 1);
208 }
209}