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