1// Std 2use std::ffi::OsString; 3use std::mem; 4use std::ops::Deref; 5 6// Internal 7use crate::builder::{Arg, ArgPredicate, Command}; 8use crate::parser::AnyValue; 9use crate::parser::Identifier; 10use crate::parser::PendingArg; 11use crate::parser::{ArgMatches, MatchedArg, SubCommand, ValueSource}; 12use crate::util::FlatMap; 13use crate::util::Id; 14use crate::INTERNAL_ERROR_MSG; 15 16#[derive(Debug, Default)] 17pub(crate) struct ArgMatcher { 18 matches: ArgMatches, 19 pending: Option<PendingArg>, 20} 21 22impl ArgMatcher { 23 pub(crate) fn new(_cmd: &Command) -> Self { 24 ArgMatcher { 25 matches: ArgMatches { 26 #[cfg(debug_assertions)] 27 valid_args: { 28 let args = _cmd.get_arguments().map(|a| a.get_id().clone()); 29 let groups = _cmd.get_groups().map(|g| g.get_id().clone()); 30 args.chain(groups).collect() 31 }, 32 #[cfg(debug_assertions)] 33 valid_subcommands: _cmd 34 .get_subcommands() 35 .map(|sc| sc.get_name_str().clone()) 36 .collect(), 37 ..Default::default() 38 }, 39 pending: None, 40 } 41 } 42 43 pub(crate) fn into_inner(self) -> ArgMatches { 44 self.matches 45 } 46 47 pub(crate) fn propagate_globals(&mut self, global_arg_vec: &[Id]) { 48 debug!( 49 "ArgMatcher::get_global_values: global_arg_vec={:?}", 50 global_arg_vec 51 ); 52 let mut vals_map = FlatMap::new(); 53 self.fill_in_global_values(global_arg_vec, &mut vals_map); 54 } 55 56 fn fill_in_global_values( 57 &mut self, 58 global_arg_vec: &[Id], 59 vals_map: &mut FlatMap<Id, MatchedArg>, 60 ) { 61 for global_arg in global_arg_vec { 62 if let Some(ma) = self.get(global_arg) { 63 // We have to check if the parent's global arg wasn't used but still exists 64 // such as from a default value. 65 // 66 // For example, `myprog subcommand --global-arg=value` where `--global-arg` defines 67 // a default value of `other` myprog would have an existing MatchedArg for 68 // `--global-arg` where the value is `other` 69 let to_update = if let Some(parent_ma) = vals_map.get(global_arg) { 70 if parent_ma.source() > ma.source() { 71 parent_ma 72 } else { 73 ma 74 } 75 } else { 76 ma 77 } 78 .clone(); 79 vals_map.insert(global_arg.clone(), to_update); 80 } 81 } 82 if let Some(ref mut sc) = self.matches.subcommand { 83 let mut am = ArgMatcher { 84 matches: mem::take(&mut sc.matches), 85 pending: None, 86 }; 87 am.fill_in_global_values(global_arg_vec, vals_map); 88 mem::swap(&mut am.matches, &mut sc.matches); 89 } 90 91 for (name, matched_arg) in vals_map.iter_mut() { 92 self.matches.args.insert(name.clone(), matched_arg.clone()); 93 } 94 } 95 96 pub(crate) fn get(&self, arg: &Id) -> Option<&MatchedArg> { 97 self.matches.args.get(arg) 98 } 99 100 pub(crate) fn get_mut(&mut self, arg: &Id) -> Option<&mut MatchedArg> { 101 self.matches.args.get_mut(arg) 102 } 103 104 pub(crate) fn remove(&mut self, arg: &Id) -> bool { 105 self.matches.args.remove(arg).is_some() 106 } 107 108 pub(crate) fn contains(&self, arg: &Id) -> bool { 109 self.matches.args.contains_key(arg) 110 } 111 112 pub(crate) fn arg_ids(&self) -> std::slice::Iter<'_, Id> { 113 self.matches.args.keys() 114 } 115 116 pub(crate) fn args(&self) -> crate::util::flat_map::Iter<'_, Id, MatchedArg> { 117 self.matches.args.iter() 118 } 119 120 pub(crate) fn entry(&mut self, arg: Id) -> crate::util::Entry<Id, MatchedArg> { 121 self.matches.args.entry(arg) 122 } 123 124 pub(crate) fn subcommand(&mut self, sc: SubCommand) { 125 self.matches.subcommand = Some(Box::new(sc)); 126 } 127 128 pub(crate) fn subcommand_name(&self) -> Option<&str> { 129 self.matches.subcommand_name() 130 } 131 132 pub(crate) fn check_explicit(&self, arg: &Id, predicate: &ArgPredicate) -> bool { 133 self.get(arg).map_or(false, |a| a.check_explicit(predicate)) 134 } 135 136 pub(crate) fn start_custom_arg(&mut self, arg: &Arg, source: ValueSource) { 137 let id = arg.get_id().clone(); 138 debug!( 139 "ArgMatcher::start_custom_arg: id={:?}, source={:?}", 140 id, source 141 ); 142 let ma = self.entry(id).or_insert(MatchedArg::new_arg(arg)); 143 debug_assert_eq!(ma.type_id(), Some(arg.get_value_parser().type_id())); 144 ma.set_source(source); 145 ma.new_val_group(); 146 } 147 148 pub(crate) fn start_custom_group(&mut self, id: Id, source: ValueSource) { 149 debug!( 150 "ArgMatcher::start_custom_arg: id={:?}, source={:?}", 151 id, source 152 ); 153 let ma = self.entry(id).or_insert(MatchedArg::new_group()); 154 debug_assert_eq!(ma.type_id(), None); 155 ma.set_source(source); 156 ma.new_val_group(); 157 } 158 159 pub(crate) fn start_occurrence_of_external(&mut self, cmd: &crate::Command) { 160 let id = Id::from_static_ref(Id::EXTERNAL); 161 debug!("ArgMatcher::start_occurrence_of_external: id={:?}", id,); 162 let ma = self.entry(id).or_insert(MatchedArg::new_external(cmd)); 163 debug_assert_eq!( 164 ma.type_id(), 165 Some( 166 cmd.get_external_subcommand_value_parser() 167 .expect(INTERNAL_ERROR_MSG) 168 .type_id() 169 ) 170 ); 171 ma.set_source(ValueSource::CommandLine); 172 ma.new_val_group(); 173 } 174 175 pub(crate) fn add_val_to(&mut self, arg: &Id, val: AnyValue, raw_val: OsString) { 176 let ma = self.get_mut(arg).expect(INTERNAL_ERROR_MSG); 177 ma.append_val(val, raw_val); 178 } 179 180 pub(crate) fn add_index_to(&mut self, arg: &Id, idx: usize) { 181 let ma = self.get_mut(arg).expect(INTERNAL_ERROR_MSG); 182 ma.push_index(idx); 183 } 184 185 pub(crate) fn needs_more_vals(&self, o: &Arg) -> bool { 186 let num_pending = self 187 .pending 188 .as_ref() 189 .and_then(|p| (p.id == *o.get_id()).then_some(p.raw_vals.len())) 190 .unwrap_or(0); 191 debug!( 192 "ArgMatcher::needs_more_vals: o={}, pending={}", 193 o.get_id(), 194 num_pending 195 ); 196 let expected = o.get_num_args().expect(INTERNAL_ERROR_MSG); 197 debug!( 198 "ArgMatcher::needs_more_vals: expected={}, actual={}", 199 expected, num_pending 200 ); 201 expected.accepts_more(num_pending) 202 } 203 204 pub(crate) fn pending_arg_id(&self) -> Option<&Id> { 205 self.pending.as_ref().map(|p| &p.id) 206 } 207 208 pub(crate) fn pending_values_mut( 209 &mut self, 210 id: &Id, 211 ident: Option<Identifier>, 212 trailing_values: bool, 213 ) -> &mut Vec<OsString> { 214 let pending = self.pending.get_or_insert_with(|| PendingArg { 215 id: id.clone(), 216 ident, 217 raw_vals: Default::default(), 218 trailing_idx: None, 219 }); 220 debug_assert_eq!(pending.id, *id, "{INTERNAL_ERROR_MSG}"); 221 if ident.is_some() { 222 debug_assert_eq!(pending.ident, ident, "{INTERNAL_ERROR_MSG}"); 223 } 224 if trailing_values { 225 pending.trailing_idx.get_or_insert(pending.raw_vals.len()); 226 } 227 &mut pending.raw_vals 228 } 229 230 pub(crate) fn start_trailing(&mut self) { 231 if let Some(pending) = &mut self.pending { 232 // Allow asserting its started on subsequent calls 233 pending.trailing_idx.get_or_insert(pending.raw_vals.len()); 234 } 235 } 236 237 pub(crate) fn take_pending(&mut self) -> Option<PendingArg> { 238 self.pending.take() 239 } 240} 241 242impl Deref for ArgMatcher { 243 type Target = ArgMatches; 244 245 fn deref(&self) -> &Self::Target { 246 &self.matches 247 } 248} 249