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