119625d8cSopenharmony_ci// Std
219625d8cSopenharmony_ciuse std::ffi::OsString;
319625d8cSopenharmony_ciuse std::mem;
419625d8cSopenharmony_ciuse std::ops::Deref;
519625d8cSopenharmony_ci
619625d8cSopenharmony_ci// Internal
719625d8cSopenharmony_ciuse crate::builder::{Arg, ArgPredicate, Command};
819625d8cSopenharmony_ciuse crate::parser::AnyValue;
919625d8cSopenharmony_ciuse crate::parser::Identifier;
1019625d8cSopenharmony_ciuse crate::parser::PendingArg;
1119625d8cSopenharmony_ciuse crate::parser::{ArgMatches, MatchedArg, SubCommand, ValueSource};
1219625d8cSopenharmony_ciuse crate::util::FlatMap;
1319625d8cSopenharmony_ciuse crate::util::Id;
1419625d8cSopenharmony_ciuse crate::INTERNAL_ERROR_MSG;
1519625d8cSopenharmony_ci
1619625d8cSopenharmony_ci#[derive(Debug, Default)]
1719625d8cSopenharmony_cipub(crate) struct ArgMatcher {
1819625d8cSopenharmony_ci    matches: ArgMatches,
1919625d8cSopenharmony_ci    pending: Option<PendingArg>,
2019625d8cSopenharmony_ci}
2119625d8cSopenharmony_ci
2219625d8cSopenharmony_ciimpl ArgMatcher {
2319625d8cSopenharmony_ci    pub(crate) fn new(_cmd: &Command) -> Self {
2419625d8cSopenharmony_ci        ArgMatcher {
2519625d8cSopenharmony_ci            matches: ArgMatches {
2619625d8cSopenharmony_ci                #[cfg(debug_assertions)]
2719625d8cSopenharmony_ci                valid_args: {
2819625d8cSopenharmony_ci                    let args = _cmd.get_arguments().map(|a| a.get_id().clone());
2919625d8cSopenharmony_ci                    let groups = _cmd.get_groups().map(|g| g.get_id().clone());
3019625d8cSopenharmony_ci                    args.chain(groups).collect()
3119625d8cSopenharmony_ci                },
3219625d8cSopenharmony_ci                #[cfg(debug_assertions)]
3319625d8cSopenharmony_ci                valid_subcommands: _cmd
3419625d8cSopenharmony_ci                    .get_subcommands()
3519625d8cSopenharmony_ci                    .map(|sc| sc.get_name_str().clone())
3619625d8cSopenharmony_ci                    .collect(),
3719625d8cSopenharmony_ci                ..Default::default()
3819625d8cSopenharmony_ci            },
3919625d8cSopenharmony_ci            pending: None,
4019625d8cSopenharmony_ci        }
4119625d8cSopenharmony_ci    }
4219625d8cSopenharmony_ci
4319625d8cSopenharmony_ci    pub(crate) fn into_inner(self) -> ArgMatches {
4419625d8cSopenharmony_ci        self.matches
4519625d8cSopenharmony_ci    }
4619625d8cSopenharmony_ci
4719625d8cSopenharmony_ci    pub(crate) fn propagate_globals(&mut self, global_arg_vec: &[Id]) {
4819625d8cSopenharmony_ci        debug!(
4919625d8cSopenharmony_ci            "ArgMatcher::get_global_values: global_arg_vec={:?}",
5019625d8cSopenharmony_ci            global_arg_vec
5119625d8cSopenharmony_ci        );
5219625d8cSopenharmony_ci        let mut vals_map = FlatMap::new();
5319625d8cSopenharmony_ci        self.fill_in_global_values(global_arg_vec, &mut vals_map);
5419625d8cSopenharmony_ci    }
5519625d8cSopenharmony_ci
5619625d8cSopenharmony_ci    fn fill_in_global_values(
5719625d8cSopenharmony_ci        &mut self,
5819625d8cSopenharmony_ci        global_arg_vec: &[Id],
5919625d8cSopenharmony_ci        vals_map: &mut FlatMap<Id, MatchedArg>,
6019625d8cSopenharmony_ci    ) {
6119625d8cSopenharmony_ci        for global_arg in global_arg_vec {
6219625d8cSopenharmony_ci            if let Some(ma) = self.get(global_arg) {
6319625d8cSopenharmony_ci                // We have to check if the parent's global arg wasn't used but still exists
6419625d8cSopenharmony_ci                // such as from a default value.
6519625d8cSopenharmony_ci                //
6619625d8cSopenharmony_ci                // For example, `myprog subcommand --global-arg=value` where `--global-arg` defines
6719625d8cSopenharmony_ci                // a default value of `other` myprog would have an existing MatchedArg for
6819625d8cSopenharmony_ci                // `--global-arg` where the value is `other`
6919625d8cSopenharmony_ci                let to_update = if let Some(parent_ma) = vals_map.get(global_arg) {
7019625d8cSopenharmony_ci                    if parent_ma.source() > ma.source() {
7119625d8cSopenharmony_ci                        parent_ma
7219625d8cSopenharmony_ci                    } else {
7319625d8cSopenharmony_ci                        ma
7419625d8cSopenharmony_ci                    }
7519625d8cSopenharmony_ci                } else {
7619625d8cSopenharmony_ci                    ma
7719625d8cSopenharmony_ci                }
7819625d8cSopenharmony_ci                .clone();
7919625d8cSopenharmony_ci                vals_map.insert(global_arg.clone(), to_update);
8019625d8cSopenharmony_ci            }
8119625d8cSopenharmony_ci        }
8219625d8cSopenharmony_ci        if let Some(ref mut sc) = self.matches.subcommand {
8319625d8cSopenharmony_ci            let mut am = ArgMatcher {
8419625d8cSopenharmony_ci                matches: mem::take(&mut sc.matches),
8519625d8cSopenharmony_ci                pending: None,
8619625d8cSopenharmony_ci            };
8719625d8cSopenharmony_ci            am.fill_in_global_values(global_arg_vec, vals_map);
8819625d8cSopenharmony_ci            mem::swap(&mut am.matches, &mut sc.matches);
8919625d8cSopenharmony_ci        }
9019625d8cSopenharmony_ci
9119625d8cSopenharmony_ci        for (name, matched_arg) in vals_map.iter_mut() {
9219625d8cSopenharmony_ci            self.matches.args.insert(name.clone(), matched_arg.clone());
9319625d8cSopenharmony_ci        }
9419625d8cSopenharmony_ci    }
9519625d8cSopenharmony_ci
9619625d8cSopenharmony_ci    pub(crate) fn get(&self, arg: &Id) -> Option<&MatchedArg> {
9719625d8cSopenharmony_ci        self.matches.args.get(arg)
9819625d8cSopenharmony_ci    }
9919625d8cSopenharmony_ci
10019625d8cSopenharmony_ci    pub(crate) fn get_mut(&mut self, arg: &Id) -> Option<&mut MatchedArg> {
10119625d8cSopenharmony_ci        self.matches.args.get_mut(arg)
10219625d8cSopenharmony_ci    }
10319625d8cSopenharmony_ci
10419625d8cSopenharmony_ci    pub(crate) fn remove(&mut self, arg: &Id) -> bool {
10519625d8cSopenharmony_ci        self.matches.args.remove(arg).is_some()
10619625d8cSopenharmony_ci    }
10719625d8cSopenharmony_ci
10819625d8cSopenharmony_ci    pub(crate) fn contains(&self, arg: &Id) -> bool {
10919625d8cSopenharmony_ci        self.matches.args.contains_key(arg)
11019625d8cSopenharmony_ci    }
11119625d8cSopenharmony_ci
11219625d8cSopenharmony_ci    pub(crate) fn arg_ids(&self) -> std::slice::Iter<'_, Id> {
11319625d8cSopenharmony_ci        self.matches.args.keys()
11419625d8cSopenharmony_ci    }
11519625d8cSopenharmony_ci
11619625d8cSopenharmony_ci    pub(crate) fn args(&self) -> crate::util::flat_map::Iter<'_, Id, MatchedArg> {
11719625d8cSopenharmony_ci        self.matches.args.iter()
11819625d8cSopenharmony_ci    }
11919625d8cSopenharmony_ci
12019625d8cSopenharmony_ci    pub(crate) fn entry(&mut self, arg: Id) -> crate::util::Entry<Id, MatchedArg> {
12119625d8cSopenharmony_ci        self.matches.args.entry(arg)
12219625d8cSopenharmony_ci    }
12319625d8cSopenharmony_ci
12419625d8cSopenharmony_ci    pub(crate) fn subcommand(&mut self, sc: SubCommand) {
12519625d8cSopenharmony_ci        self.matches.subcommand = Some(Box::new(sc));
12619625d8cSopenharmony_ci    }
12719625d8cSopenharmony_ci
12819625d8cSopenharmony_ci    pub(crate) fn subcommand_name(&self) -> Option<&str> {
12919625d8cSopenharmony_ci        self.matches.subcommand_name()
13019625d8cSopenharmony_ci    }
13119625d8cSopenharmony_ci
13219625d8cSopenharmony_ci    pub(crate) fn check_explicit(&self, arg: &Id, predicate: &ArgPredicate) -> bool {
13319625d8cSopenharmony_ci        self.get(arg).map_or(false, |a| a.check_explicit(predicate))
13419625d8cSopenharmony_ci    }
13519625d8cSopenharmony_ci
13619625d8cSopenharmony_ci    pub(crate) fn start_custom_arg(&mut self, arg: &Arg, source: ValueSource) {
13719625d8cSopenharmony_ci        let id = arg.get_id().clone();
13819625d8cSopenharmony_ci        debug!(
13919625d8cSopenharmony_ci            "ArgMatcher::start_custom_arg: id={:?}, source={:?}",
14019625d8cSopenharmony_ci            id, source
14119625d8cSopenharmony_ci        );
14219625d8cSopenharmony_ci        let ma = self.entry(id).or_insert(MatchedArg::new_arg(arg));
14319625d8cSopenharmony_ci        debug_assert_eq!(ma.type_id(), Some(arg.get_value_parser().type_id()));
14419625d8cSopenharmony_ci        ma.set_source(source);
14519625d8cSopenharmony_ci        ma.new_val_group();
14619625d8cSopenharmony_ci    }
14719625d8cSopenharmony_ci
14819625d8cSopenharmony_ci    pub(crate) fn start_custom_group(&mut self, id: Id, source: ValueSource) {
14919625d8cSopenharmony_ci        debug!(
15019625d8cSopenharmony_ci            "ArgMatcher::start_custom_arg: id={:?}, source={:?}",
15119625d8cSopenharmony_ci            id, source
15219625d8cSopenharmony_ci        );
15319625d8cSopenharmony_ci        let ma = self.entry(id).or_insert(MatchedArg::new_group());
15419625d8cSopenharmony_ci        debug_assert_eq!(ma.type_id(), None);
15519625d8cSopenharmony_ci        ma.set_source(source);
15619625d8cSopenharmony_ci        ma.new_val_group();
15719625d8cSopenharmony_ci    }
15819625d8cSopenharmony_ci
15919625d8cSopenharmony_ci    pub(crate) fn start_occurrence_of_external(&mut self, cmd: &crate::Command) {
16019625d8cSopenharmony_ci        let id = Id::from_static_ref(Id::EXTERNAL);
16119625d8cSopenharmony_ci        debug!("ArgMatcher::start_occurrence_of_external: id={:?}", id,);
16219625d8cSopenharmony_ci        let ma = self.entry(id).or_insert(MatchedArg::new_external(cmd));
16319625d8cSopenharmony_ci        debug_assert_eq!(
16419625d8cSopenharmony_ci            ma.type_id(),
16519625d8cSopenharmony_ci            Some(
16619625d8cSopenharmony_ci                cmd.get_external_subcommand_value_parser()
16719625d8cSopenharmony_ci                    .expect(INTERNAL_ERROR_MSG)
16819625d8cSopenharmony_ci                    .type_id()
16919625d8cSopenharmony_ci            )
17019625d8cSopenharmony_ci        );
17119625d8cSopenharmony_ci        ma.set_source(ValueSource::CommandLine);
17219625d8cSopenharmony_ci        ma.new_val_group();
17319625d8cSopenharmony_ci    }
17419625d8cSopenharmony_ci
17519625d8cSopenharmony_ci    pub(crate) fn add_val_to(&mut self, arg: &Id, val: AnyValue, raw_val: OsString) {
17619625d8cSopenharmony_ci        let ma = self.get_mut(arg).expect(INTERNAL_ERROR_MSG);
17719625d8cSopenharmony_ci        ma.append_val(val, raw_val);
17819625d8cSopenharmony_ci    }
17919625d8cSopenharmony_ci
18019625d8cSopenharmony_ci    pub(crate) fn add_index_to(&mut self, arg: &Id, idx: usize) {
18119625d8cSopenharmony_ci        let ma = self.get_mut(arg).expect(INTERNAL_ERROR_MSG);
18219625d8cSopenharmony_ci        ma.push_index(idx);
18319625d8cSopenharmony_ci    }
18419625d8cSopenharmony_ci
18519625d8cSopenharmony_ci    pub(crate) fn needs_more_vals(&self, o: &Arg) -> bool {
18619625d8cSopenharmony_ci        let num_pending = self
18719625d8cSopenharmony_ci            .pending
18819625d8cSopenharmony_ci            .as_ref()
18919625d8cSopenharmony_ci            .and_then(|p| (p.id == *o.get_id()).then_some(p.raw_vals.len()))
19019625d8cSopenharmony_ci            .unwrap_or(0);
19119625d8cSopenharmony_ci        debug!(
19219625d8cSopenharmony_ci            "ArgMatcher::needs_more_vals: o={}, pending={}",
19319625d8cSopenharmony_ci            o.get_id(),
19419625d8cSopenharmony_ci            num_pending
19519625d8cSopenharmony_ci        );
19619625d8cSopenharmony_ci        let expected = o.get_num_args().expect(INTERNAL_ERROR_MSG);
19719625d8cSopenharmony_ci        debug!(
19819625d8cSopenharmony_ci            "ArgMatcher::needs_more_vals: expected={}, actual={}",
19919625d8cSopenharmony_ci            expected, num_pending
20019625d8cSopenharmony_ci        );
20119625d8cSopenharmony_ci        expected.accepts_more(num_pending)
20219625d8cSopenharmony_ci    }
20319625d8cSopenharmony_ci
20419625d8cSopenharmony_ci    pub(crate) fn pending_arg_id(&self) -> Option<&Id> {
20519625d8cSopenharmony_ci        self.pending.as_ref().map(|p| &p.id)
20619625d8cSopenharmony_ci    }
20719625d8cSopenharmony_ci
20819625d8cSopenharmony_ci    pub(crate) fn pending_values_mut(
20919625d8cSopenharmony_ci        &mut self,
21019625d8cSopenharmony_ci        id: &Id,
21119625d8cSopenharmony_ci        ident: Option<Identifier>,
21219625d8cSopenharmony_ci        trailing_values: bool,
21319625d8cSopenharmony_ci    ) -> &mut Vec<OsString> {
21419625d8cSopenharmony_ci        let pending = self.pending.get_or_insert_with(|| PendingArg {
21519625d8cSopenharmony_ci            id: id.clone(),
21619625d8cSopenharmony_ci            ident,
21719625d8cSopenharmony_ci            raw_vals: Default::default(),
21819625d8cSopenharmony_ci            trailing_idx: None,
21919625d8cSopenharmony_ci        });
22019625d8cSopenharmony_ci        debug_assert_eq!(pending.id, *id, "{INTERNAL_ERROR_MSG}");
22119625d8cSopenharmony_ci        if ident.is_some() {
22219625d8cSopenharmony_ci            debug_assert_eq!(pending.ident, ident, "{INTERNAL_ERROR_MSG}");
22319625d8cSopenharmony_ci        }
22419625d8cSopenharmony_ci        if trailing_values {
22519625d8cSopenharmony_ci            pending.trailing_idx.get_or_insert(pending.raw_vals.len());
22619625d8cSopenharmony_ci        }
22719625d8cSopenharmony_ci        &mut pending.raw_vals
22819625d8cSopenharmony_ci    }
22919625d8cSopenharmony_ci
23019625d8cSopenharmony_ci    pub(crate) fn start_trailing(&mut self) {
23119625d8cSopenharmony_ci        if let Some(pending) = &mut self.pending {
23219625d8cSopenharmony_ci            // Allow asserting its started on subsequent calls
23319625d8cSopenharmony_ci            pending.trailing_idx.get_or_insert(pending.raw_vals.len());
23419625d8cSopenharmony_ci        }
23519625d8cSopenharmony_ci    }
23619625d8cSopenharmony_ci
23719625d8cSopenharmony_ci    pub(crate) fn take_pending(&mut self) -> Option<PendingArg> {
23819625d8cSopenharmony_ci        self.pending.take()
23919625d8cSopenharmony_ci    }
24019625d8cSopenharmony_ci}
24119625d8cSopenharmony_ci
24219625d8cSopenharmony_ciimpl Deref for ArgMatcher {
24319625d8cSopenharmony_ci    type Target = ArgMatches;
24419625d8cSopenharmony_ci
24519625d8cSopenharmony_ci    fn deref(&self) -> &Self::Target {
24619625d8cSopenharmony_ci        &self.matches
24719625d8cSopenharmony_ci    }
24819625d8cSopenharmony_ci}
249