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