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