1 // Std
2 use std::{
3     ffi::{OsStr, OsString},
4     iter::{Cloned, Flatten},
5     slice::Iter,
6 };
7 
8 use crate::builder::ArgPredicate;
9 use crate::parser::ValueSource;
10 use crate::util::eq_ignore_case;
11 use crate::util::AnyValue;
12 use crate::util::AnyValueId;
13 use crate::INTERNAL_ERROR_MSG;
14 
15 #[derive(Debug, Clone)]
16 pub(crate) struct MatchedArg {
17     source: Option<ValueSource>,
18     indices: Vec<usize>,
19     type_id: Option<AnyValueId>,
20     vals: Vec<Vec<AnyValue>>,
21     raw_vals: Vec<Vec<OsString>>,
22     ignore_case: bool,
23 }
24 
25 impl MatchedArg {
new_arg(arg: &crate::Arg) -> Self26     pub(crate) fn new_arg(arg: &crate::Arg) -> Self {
27         let ignore_case = arg.is_ignore_case_set();
28         Self {
29             source: None,
30             indices: Vec::new(),
31             type_id: Some(arg.get_value_parser().type_id()),
32             vals: Vec::new(),
33             raw_vals: Vec::new(),
34             ignore_case,
35         }
36     }
37 
new_group() -> Self38     pub(crate) fn new_group() -> Self {
39         let ignore_case = false;
40         Self {
41             source: None,
42             indices: Vec::new(),
43             type_id: None,
44             vals: Vec::new(),
45             raw_vals: Vec::new(),
46             ignore_case,
47         }
48     }
49 
new_external(cmd: &crate::Command) -> Self50     pub(crate) fn new_external(cmd: &crate::Command) -> Self {
51         let ignore_case = false;
52         Self {
53             source: None,
54             indices: Vec::new(),
55             type_id: Some(
56                 cmd.get_external_subcommand_value_parser()
57                     .expect(INTERNAL_ERROR_MSG)
58                     .type_id(),
59             ),
60             vals: Vec::new(),
61             raw_vals: Vec::new(),
62             ignore_case,
63         }
64     }
65 
indices(&self) -> Cloned<Iter<'_, usize>>66     pub(crate) fn indices(&self) -> Cloned<Iter<'_, usize>> {
67         self.indices.iter().cloned()
68     }
69 
get_index(&self, index: usize) -> Option<usize>70     pub(crate) fn get_index(&self, index: usize) -> Option<usize> {
71         self.indices.get(index).cloned()
72     }
73 
push_index(&mut self, index: usize)74     pub(crate) fn push_index(&mut self, index: usize) {
75         self.indices.push(index)
76     }
77 
vals(&self) -> Iter<Vec<AnyValue>>78     pub(crate) fn vals(&self) -> Iter<Vec<AnyValue>> {
79         self.vals.iter()
80     }
81 
into_vals(self) -> Vec<Vec<AnyValue>>82     pub(crate) fn into_vals(self) -> Vec<Vec<AnyValue>> {
83         self.vals
84     }
85 
vals_flatten(&self) -> Flatten<Iter<Vec<AnyValue>>>86     pub(crate) fn vals_flatten(&self) -> Flatten<Iter<Vec<AnyValue>>> {
87         self.vals.iter().flatten()
88     }
89 
into_vals_flatten(self) -> Flatten<std::vec::IntoIter<Vec<AnyValue>>>90     pub(crate) fn into_vals_flatten(self) -> Flatten<std::vec::IntoIter<Vec<AnyValue>>> {
91         self.vals.into_iter().flatten()
92     }
93 
raw_vals(&self) -> Iter<Vec<OsString>>94     pub(crate) fn raw_vals(&self) -> Iter<Vec<OsString>> {
95         self.raw_vals.iter()
96     }
97 
raw_vals_flatten(&self) -> Flatten<Iter<Vec<OsString>>>98     pub(crate) fn raw_vals_flatten(&self) -> Flatten<Iter<Vec<OsString>>> {
99         self.raw_vals.iter().flatten()
100     }
101 
first(&self) -> Option<&AnyValue>102     pub(crate) fn first(&self) -> Option<&AnyValue> {
103         self.vals_flatten().next()
104     }
105 
106     #[cfg(test)]
first_raw(&self) -> Option<&OsString>107     pub(crate) fn first_raw(&self) -> Option<&OsString> {
108         self.raw_vals_flatten().next()
109     }
110 
new_val_group(&mut self)111     pub(crate) fn new_val_group(&mut self) {
112         self.vals.push(vec![]);
113         self.raw_vals.push(vec![]);
114     }
115 
append_val(&mut self, val: AnyValue, raw_val: OsString)116     pub(crate) fn append_val(&mut self, val: AnyValue, raw_val: OsString) {
117         // We assume there is always a group created before.
118         self.vals.last_mut().expect(INTERNAL_ERROR_MSG).push(val);
119         self.raw_vals
120             .last_mut()
121             .expect(INTERNAL_ERROR_MSG)
122             .push(raw_val);
123     }
124 
num_vals(&self) -> usize125     pub(crate) fn num_vals(&self) -> usize {
126         self.vals.iter().map(|v| v.len()).sum()
127     }
128 
129     // Will be used later
130     #[allow(dead_code)]
num_vals_last_group(&self) -> usize131     pub(crate) fn num_vals_last_group(&self) -> usize {
132         self.vals.last().map(|x| x.len()).unwrap_or(0)
133     }
134 
all_val_groups_empty(&self) -> bool135     pub(crate) fn all_val_groups_empty(&self) -> bool {
136         self.vals.iter().flatten().count() == 0
137     }
138 
check_explicit(&self, predicate: &ArgPredicate) -> bool139     pub(crate) fn check_explicit(&self, predicate: &ArgPredicate) -> bool {
140         if self.source.map(|s| !s.is_explicit()).unwrap_or(false) {
141             return false;
142         }
143 
144         match predicate {
145             ArgPredicate::Equals(val) => self.raw_vals_flatten().any(|v| {
146                 if self.ignore_case {
147                     // If `v` isn't utf8, it can't match `val`, so `OsStr::to_str` should be fine
148                     eq_ignore_case(&v.to_string_lossy(), &val.to_string_lossy())
149                 } else {
150                     OsString::as_os_str(v) == OsStr::new(val)
151                 }
152             }),
153             ArgPredicate::IsPresent => true,
154         }
155     }
156 
source(&self) -> Option<ValueSource>157     pub(crate) fn source(&self) -> Option<ValueSource> {
158         self.source
159     }
160 
set_source(&mut self, source: ValueSource)161     pub(crate) fn set_source(&mut self, source: ValueSource) {
162         if let Some(existing) = self.source {
163             self.source = Some(existing.max(source));
164         } else {
165             self.source = Some(source)
166         }
167     }
168 
type_id(&self) -> Option<AnyValueId>169     pub(crate) fn type_id(&self) -> Option<AnyValueId> {
170         self.type_id
171     }
172 
infer_type_id(&self, expected: AnyValueId) -> AnyValueId173     pub(crate) fn infer_type_id(&self, expected: AnyValueId) -> AnyValueId {
174         self.type_id()
175             .or_else(|| {
176                 self.vals_flatten()
177                     .map(|v| v.type_id())
178                     .find(|actual| *actual != expected)
179             })
180             .unwrap_or(expected)
181     }
182 }
183 
184 impl PartialEq for MatchedArg {
eq(&self, other: &MatchedArg) -> bool185     fn eq(&self, other: &MatchedArg) -> bool {
186         let MatchedArg {
187             source: self_source,
188             indices: self_indices,
189             type_id: self_type_id,
190             vals: _,
191             raw_vals: self_raw_vals,
192             ignore_case: self_ignore_case,
193         } = self;
194         let MatchedArg {
195             source: other_source,
196             indices: other_indices,
197             type_id: other_type_id,
198             vals: _,
199             raw_vals: other_raw_vals,
200             ignore_case: other_ignore_case,
201         } = other;
202         self_source == other_source
203             && self_indices == other_indices
204             && self_type_id == other_type_id
205             && self_raw_vals == other_raw_vals
206             && self_ignore_case == other_ignore_case
207     }
208 }
209 
210 impl Eq for MatchedArg {}
211 
212 #[cfg(test)]
213 mod tests {
214     use super::*;
215 
216     #[test]
test_grouped_vals_first()217     fn test_grouped_vals_first() {
218         let mut m = MatchedArg::new_group();
219         m.new_val_group();
220         m.new_val_group();
221         m.append_val(AnyValue::new(String::from("bbb")), "bbb".into());
222         m.append_val(AnyValue::new(String::from("ccc")), "ccc".into());
223         assert_eq!(m.first_raw(), Some(&OsString::from("bbb")));
224     }
225 }
226