1use std::cell::RefCell;
2use std::collections::HashSet;
3use std::marker::PhantomData;
4use std::rc::Rc;
5use std::str::FromStr;
6
7use crate::api::capture::*;
8use crate::model::Nargs;
9use crate::prelude::Collectable;
10
11pub struct Scalar<'a, T> {
13 variable: Rc<RefCell<&'a mut T>>,
14}
15
16impl<'a, T> CliOption for Scalar<'a, T> {}
17impl<'a, T> CliArgument for Scalar<'a, T> {}
18
19impl<'a, T> Scalar<'a, T> {
20 pub fn new(variable: &'a mut T) -> Self {
22 Self {
23 variable: Rc::new(RefCell::new(variable)),
24 }
25 }
26}
27
28impl<'a, T> GenericCapturable<'a, T> for Scalar<'a, T>
29where
30 T: FromStr,
31{
32 fn matched(&mut self) {
33 }
35
36 fn capture(&mut self, token: &str) -> Result<(), InvalidCapture> {
37 let result: Result<T, InvalidCapture> =
38 T::from_str(token).map_err(|_| InvalidCapture::InvalidConversion {
39 token: token.to_string(),
40 type_name: std::any::type_name::<T>(),
41 });
42 let value = result?;
43 **self.variable.borrow_mut() = value;
44 Ok(())
45 }
46
47 fn nargs(&self) -> Nargs {
48 Nargs::Precisely(1)
49 }
50}
51
52pub struct Switch<'a, T> {
54 variable: Rc<RefCell<&'a mut T>>,
55 target: Option<T>,
56}
57
58impl<'a, T> CliOption for Switch<'a, T> {}
59
60impl<'a, T> Switch<'a, T> {
61 pub fn new(variable: &'a mut T, target: T) -> Self {
63 Self {
64 variable: Rc::new(RefCell::new(variable)),
65 target: Some(target),
66 }
67 }
68}
69
70impl<'a, T> GenericCapturable<'a, T> for Switch<'a, T> {
71 fn matched(&mut self) {
72 **self.variable.borrow_mut() = self
73 .target
74 .take()
75 .expect("internal error - must be able to take the Switch#target");
76 }
77
78 fn capture(&mut self, _token: &str) -> Result<(), InvalidCapture> {
79 unreachable!("internal error - must not capture on a Switch");
80 }
81
82 fn nargs(&self) -> Nargs {
83 Nargs::Precisely(0)
84 }
85}
86
87pub struct Optional<'a, T> {
89 variable: Rc<RefCell<&'a mut Option<T>>>,
90}
91
92impl<'a, T> CliOption for Optional<'a, T> {}
93
94impl<'a, T> Optional<'a, T> {
95 pub fn new(variable: &'a mut Option<T>) -> Self {
97 Self {
98 variable: Rc::new(RefCell::new(variable)),
99 }
100 }
101}
102
103impl<'a, T> GenericCapturable<'a, T> for Optional<'a, T>
104where
105 T: FromStr,
106{
107 fn matched(&mut self) {
108 }
110
111 fn capture(&mut self, token: &str) -> Result<(), InvalidCapture> {
112 let result: Result<T, InvalidCapture> =
113 T::from_str(token).map_err(|_| InvalidCapture::InvalidConversion {
114 token: token.to_string(),
115 type_name: std::any::type_name::<T>(),
116 });
117 let value = result?;
118 self.variable.borrow_mut().replace(value);
119 Ok(())
120 }
121
122 fn nargs(&self) -> Nargs {
123 Nargs::Precisely(1)
124 }
125}
126
127pub struct Collection<'a, C, T>
129where
130 C: 'a + Collectable<T>,
131{
132 variable: Rc<RefCell<&'a mut C>>,
133 nargs: Nargs,
134 _phantom: PhantomData<T>,
135}
136
137impl<'a, C, T> CliOption for Collection<'a, C, T> where C: 'a + Collectable<T> {}
138
139impl<'a, C, T> CliArgument for Collection<'a, C, T> where C: 'a + Collectable<T> {}
140
141impl<'a, C, T> Collection<'a, C, T>
142where
143 C: 'a + Collectable<T>,
144{
145 pub fn new(variable: &'a mut C, nargs: Nargs) -> Self {
147 Self {
148 variable: Rc::new(RefCell::new(variable)),
149 nargs,
150 _phantom: PhantomData,
151 }
152 }
153}
154
155impl<'a, C, T> GenericCapturable<'a, T> for Collection<'a, C, T>
156where
157 T: FromStr,
158 C: 'a + Collectable<T>,
159{
160 fn matched(&mut self) {
161 }
163
164 fn capture(&mut self, token: &str) -> Result<(), InvalidCapture> {
165 let result: Result<T, InvalidCapture> =
166 T::from_str(token).map_err(|_| InvalidCapture::InvalidConversion {
167 token: token.to_string(),
168 type_name: std::any::type_name::<T>(),
169 });
170 let value = result?;
171 (**self.variable.borrow_mut())
172 .add(value)
173 .map_err(|message| InvalidCapture::InvalidAdd {
174 token: token.to_string(),
175 message,
176 })?;
177 Ok(())
178 }
179
180 fn nargs(&self) -> Nargs {
181 self.nargs
182 }
183}
184
185impl<T> Collectable<T> for Vec<T> {
186 fn add(&mut self, item: T) -> Result<(), String> {
187 self.push(item);
188 Ok(())
189 }
190}
191
192impl<T: Eq + std::hash::Hash> Collectable<T> for HashSet<T> {
193 fn add(&mut self, item: T) -> Result<(), String> {
194 if self.insert(item) {
195 Ok(())
196 } else {
197 Err("set already contains item".to_string())
198 }
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205
206 #[test]
207 fn vec() {
208 let mut collection: Vec<u32> = Vec::default();
209 collection.add(1).unwrap();
210 collection.add(0).unwrap();
211 assert_eq!(collection, vec![1, 0]);
212 }
213
214 #[test]
215 fn hash_set() {
216 let mut collection: HashSet<u32> = HashSet::default();
217 collection.add(1).unwrap();
218 collection.add(0).unwrap();
219 let message = collection.add(1).unwrap_err();
220 assert_eq!(collection, HashSet::from([1, 0]));
221 assert_eq!(message, "set already contains item".to_string());
222 }
223
224 #[test]
225 fn value_capture() {
226 let mut variable: u32 = u32::default();
228 let mut value = Scalar::new(&mut variable);
229 value.capture("5").unwrap();
230 assert_eq!(variable, 5);
231
232 let mut variable: bool = false;
234 let mut value = Scalar::new(&mut variable);
235 value.capture("true").unwrap();
236 assert!(variable);
237 }
238
239 #[test]
240 #[should_panic]
241 fn switch_capture() {
242 let mut variable: u32 = u32::default();
243 let mut switch = Switch::new(&mut variable, 1);
244 match switch.capture("5") {
245 Ok(_) => {}
246 Err(_) => {}
247 };
248 }
249
250 #[test]
251 fn optional_capture() {
252 let mut variable: Option<u32> = None;
254 let mut optional = Optional::new(&mut variable);
255 optional.capture("1").unwrap();
256 assert_eq!(variable, Some(1));
257 }
258
259 #[test]
260 fn collection_capture() {
261 let mut variable: Vec<u32> = Vec::default();
263 let mut collection = Collection::new(&mut variable, Nargs::Any);
264 collection.capture("1").unwrap();
265 collection.capture("0").unwrap();
266 assert_eq!(variable, vec![1, 0]);
267
268 let mut variable: HashSet<u32> = HashSet::default();
270 let mut collection = Collection::new(&mut variable, Nargs::Any);
271 collection.capture("1").unwrap();
272 collection.capture("0").unwrap();
273 let error = collection.capture("0").unwrap_err();
274 assert_eq!(variable, HashSet::from([0, 1]));
275 assert_matches!(error, InvalidCapture::InvalidAdd { token, message } => {
276 assert_eq!(token, "0".to_string());
277 assert_eq!(message, "set already contains item".to_string());
278 });
279 }
280
281 #[test]
282 fn value_overwritten() {
283 let mut variable: u32 = u32::default();
284 let mut value = Scalar::new(&mut variable);
285 value.capture("5").unwrap();
286 variable = 2;
287 assert_eq!(variable, 2);
288 }
289
290 #[test]
291 fn value_matched() {
292 let mut variable: u32 = u32::default();
293 let mut value = Scalar::new(&mut variable);
294 value.matched();
295 assert_eq!(variable, 0);
296 }
297
298 #[test]
299 fn switch_matched() {
300 let mut variable: u32 = u32::default();
301 let mut switch = Switch::new(&mut variable, 2);
302 switch.matched();
303 assert_eq!(variable, 2);
304 }
305
306 #[test]
307 fn optional_matched() {
308 let mut variable: Option<u32> = None;
309 let mut optional = Optional::new(&mut variable);
310 optional.matched();
311 assert_eq!(variable, None);
312 }
313
314 #[test]
315 fn collection_matched() {
316 let mut variable: Vec<u32> = Vec::default();
317 let mut collection = Collection::new(&mut variable, Nargs::Any);
318 collection.matched();
319 assert_eq!(variable, vec![]);
320 }
321
322 #[test]
323 fn test_nargs() {
324 let mut variable: u32 = u32::default();
325 let value = Scalar::new(&mut variable);
326 assert_eq!(value.nargs(), Nargs::Precisely(1));
327
328 let mut variable: u32 = u32::default();
329 let switch = Switch::new(&mut variable, 2);
330 assert_eq!(switch.nargs(), Nargs::Precisely(0));
331
332 let mut variable: Option<u32> = None;
333 let optional = Optional::new(&mut variable);
334 assert_eq!(optional.nargs(), Nargs::Precisely(1));
335
336 let mut variable: Vec<u32> = Vec::default();
337 let collection = Collection::new(&mut variable, Nargs::Any);
338 assert_eq!(collection.nargs(), Nargs::Any);
339
340 let mut variable: Vec<u32> = Vec::default();
341 let collection = Collection::new(&mut variable, Nargs::AtLeastOne);
342 assert_eq!(collection.nargs(), Nargs::AtLeastOne);
343 }
344}