119625d8cSopenharmony_ci// Std
219625d8cSopenharmony_ciuse std::{
319625d8cSopenharmony_ci    ffi::{OsStr, OsString},
419625d8cSopenharmony_ci    iter::{Cloned, Flatten},
519625d8cSopenharmony_ci    slice::Iter,
619625d8cSopenharmony_ci};
719625d8cSopenharmony_ci
819625d8cSopenharmony_ciuse crate::builder::ArgPredicate;
919625d8cSopenharmony_ciuse crate::parser::AnyValue;
1019625d8cSopenharmony_ciuse crate::parser::AnyValueId;
1119625d8cSopenharmony_ciuse crate::parser::ValueSource;
1219625d8cSopenharmony_ciuse crate::util::eq_ignore_case;
1319625d8cSopenharmony_ciuse crate::INTERNAL_ERROR_MSG;
1419625d8cSopenharmony_ci
1519625d8cSopenharmony_ci#[derive(Debug, Clone)]
1619625d8cSopenharmony_cipub(crate) struct MatchedArg {
1719625d8cSopenharmony_ci    source: Option<ValueSource>,
1819625d8cSopenharmony_ci    indices: Vec<usize>,
1919625d8cSopenharmony_ci    type_id: Option<AnyValueId>,
2019625d8cSopenharmony_ci    vals: Vec<Vec<AnyValue>>,
2119625d8cSopenharmony_ci    raw_vals: Vec<Vec<OsString>>,
2219625d8cSopenharmony_ci    ignore_case: bool,
2319625d8cSopenharmony_ci}
2419625d8cSopenharmony_ci
2519625d8cSopenharmony_ciimpl MatchedArg {
2619625d8cSopenharmony_ci    pub(crate) fn new_arg(arg: &crate::Arg) -> Self {
2719625d8cSopenharmony_ci        let ignore_case = arg.is_ignore_case_set();
2819625d8cSopenharmony_ci        Self {
2919625d8cSopenharmony_ci            source: None,
3019625d8cSopenharmony_ci            indices: Vec::new(),
3119625d8cSopenharmony_ci            type_id: Some(arg.get_value_parser().type_id()),
3219625d8cSopenharmony_ci            vals: Vec::new(),
3319625d8cSopenharmony_ci            raw_vals: Vec::new(),
3419625d8cSopenharmony_ci            ignore_case,
3519625d8cSopenharmony_ci        }
3619625d8cSopenharmony_ci    }
3719625d8cSopenharmony_ci
3819625d8cSopenharmony_ci    pub(crate) fn new_group() -> Self {
3919625d8cSopenharmony_ci        let ignore_case = false;
4019625d8cSopenharmony_ci        Self {
4119625d8cSopenharmony_ci            source: None,
4219625d8cSopenharmony_ci            indices: Vec::new(),
4319625d8cSopenharmony_ci            type_id: None,
4419625d8cSopenharmony_ci            vals: Vec::new(),
4519625d8cSopenharmony_ci            raw_vals: Vec::new(),
4619625d8cSopenharmony_ci            ignore_case,
4719625d8cSopenharmony_ci        }
4819625d8cSopenharmony_ci    }
4919625d8cSopenharmony_ci
5019625d8cSopenharmony_ci    pub(crate) fn new_external(cmd: &crate::Command) -> Self {
5119625d8cSopenharmony_ci        let ignore_case = false;
5219625d8cSopenharmony_ci        Self {
5319625d8cSopenharmony_ci            source: None,
5419625d8cSopenharmony_ci            indices: Vec::new(),
5519625d8cSopenharmony_ci            type_id: Some(
5619625d8cSopenharmony_ci                cmd.get_external_subcommand_value_parser()
5719625d8cSopenharmony_ci                    .expect(INTERNAL_ERROR_MSG)
5819625d8cSopenharmony_ci                    .type_id(),
5919625d8cSopenharmony_ci            ),
6019625d8cSopenharmony_ci            vals: Vec::new(),
6119625d8cSopenharmony_ci            raw_vals: Vec::new(),
6219625d8cSopenharmony_ci            ignore_case,
6319625d8cSopenharmony_ci        }
6419625d8cSopenharmony_ci    }
6519625d8cSopenharmony_ci
6619625d8cSopenharmony_ci    pub(crate) fn indices(&self) -> Cloned<Iter<'_, usize>> {
6719625d8cSopenharmony_ci        self.indices.iter().cloned()
6819625d8cSopenharmony_ci    }
6919625d8cSopenharmony_ci
7019625d8cSopenharmony_ci    pub(crate) fn get_index(&self, index: usize) -> Option<usize> {
7119625d8cSopenharmony_ci        self.indices.get(index).cloned()
7219625d8cSopenharmony_ci    }
7319625d8cSopenharmony_ci
7419625d8cSopenharmony_ci    pub(crate) fn push_index(&mut self, index: usize) {
7519625d8cSopenharmony_ci        self.indices.push(index)
7619625d8cSopenharmony_ci    }
7719625d8cSopenharmony_ci
7819625d8cSopenharmony_ci    pub(crate) fn vals(&self) -> Iter<Vec<AnyValue>> {
7919625d8cSopenharmony_ci        self.vals.iter()
8019625d8cSopenharmony_ci    }
8119625d8cSopenharmony_ci
8219625d8cSopenharmony_ci    pub(crate) fn into_vals(self) -> Vec<Vec<AnyValue>> {
8319625d8cSopenharmony_ci        self.vals
8419625d8cSopenharmony_ci    }
8519625d8cSopenharmony_ci
8619625d8cSopenharmony_ci    pub(crate) fn vals_flatten(&self) -> Flatten<Iter<Vec<AnyValue>>> {
8719625d8cSopenharmony_ci        self.vals.iter().flatten()
8819625d8cSopenharmony_ci    }
8919625d8cSopenharmony_ci
9019625d8cSopenharmony_ci    pub(crate) fn into_vals_flatten(self) -> Flatten<std::vec::IntoIter<Vec<AnyValue>>> {
9119625d8cSopenharmony_ci        self.vals.into_iter().flatten()
9219625d8cSopenharmony_ci    }
9319625d8cSopenharmony_ci
9419625d8cSopenharmony_ci    pub(crate) fn raw_vals(&self) -> Iter<Vec<OsString>> {
9519625d8cSopenharmony_ci        self.raw_vals.iter()
9619625d8cSopenharmony_ci    }
9719625d8cSopenharmony_ci
9819625d8cSopenharmony_ci    pub(crate) fn raw_vals_flatten(&self) -> Flatten<Iter<Vec<OsString>>> {
9919625d8cSopenharmony_ci        self.raw_vals.iter().flatten()
10019625d8cSopenharmony_ci    }
10119625d8cSopenharmony_ci
10219625d8cSopenharmony_ci    pub(crate) fn first(&self) -> Option<&AnyValue> {
10319625d8cSopenharmony_ci        self.vals_flatten().next()
10419625d8cSopenharmony_ci    }
10519625d8cSopenharmony_ci
10619625d8cSopenharmony_ci    #[cfg(test)]
10719625d8cSopenharmony_ci    pub(crate) fn first_raw(&self) -> Option<&OsString> {
10819625d8cSopenharmony_ci        self.raw_vals_flatten().next()
10919625d8cSopenharmony_ci    }
11019625d8cSopenharmony_ci
11119625d8cSopenharmony_ci    pub(crate) fn new_val_group(&mut self) {
11219625d8cSopenharmony_ci        self.vals.push(vec![]);
11319625d8cSopenharmony_ci        self.raw_vals.push(vec![]);
11419625d8cSopenharmony_ci    }
11519625d8cSopenharmony_ci
11619625d8cSopenharmony_ci    pub(crate) fn append_val(&mut self, val: AnyValue, raw_val: OsString) {
11719625d8cSopenharmony_ci        // We assume there is always a group created before.
11819625d8cSopenharmony_ci        self.vals.last_mut().expect(INTERNAL_ERROR_MSG).push(val);
11919625d8cSopenharmony_ci        self.raw_vals
12019625d8cSopenharmony_ci            .last_mut()
12119625d8cSopenharmony_ci            .expect(INTERNAL_ERROR_MSG)
12219625d8cSopenharmony_ci            .push(raw_val);
12319625d8cSopenharmony_ci    }
12419625d8cSopenharmony_ci
12519625d8cSopenharmony_ci    pub(crate) fn num_vals(&self) -> usize {
12619625d8cSopenharmony_ci        self.vals.iter().map(|v| v.len()).sum()
12719625d8cSopenharmony_ci    }
12819625d8cSopenharmony_ci
12919625d8cSopenharmony_ci    // Will be used later
13019625d8cSopenharmony_ci    #[allow(dead_code)]
13119625d8cSopenharmony_ci    pub(crate) fn num_vals_last_group(&self) -> usize {
13219625d8cSopenharmony_ci        self.vals.last().map(|x| x.len()).unwrap_or(0)
13319625d8cSopenharmony_ci    }
13419625d8cSopenharmony_ci
13519625d8cSopenharmony_ci    pub(crate) fn all_val_groups_empty(&self) -> bool {
13619625d8cSopenharmony_ci        self.vals.iter().flatten().count() == 0
13719625d8cSopenharmony_ci    }
13819625d8cSopenharmony_ci
13919625d8cSopenharmony_ci    pub(crate) fn check_explicit(&self, predicate: &ArgPredicate) -> bool {
14019625d8cSopenharmony_ci        if self.source.map(|s| !s.is_explicit()).unwrap_or(false) {
14119625d8cSopenharmony_ci            return false;
14219625d8cSopenharmony_ci        }
14319625d8cSopenharmony_ci
14419625d8cSopenharmony_ci        match predicate {
14519625d8cSopenharmony_ci            ArgPredicate::Equals(val) => self.raw_vals_flatten().any(|v| {
14619625d8cSopenharmony_ci                if self.ignore_case {
14719625d8cSopenharmony_ci                    // If `v` isn't utf8, it can't match `val`, so `OsStr::to_str` should be fine
14819625d8cSopenharmony_ci                    eq_ignore_case(&v.to_string_lossy(), &val.to_string_lossy())
14919625d8cSopenharmony_ci                } else {
15019625d8cSopenharmony_ci                    OsString::as_os_str(v) == OsStr::new(val)
15119625d8cSopenharmony_ci                }
15219625d8cSopenharmony_ci            }),
15319625d8cSopenharmony_ci            ArgPredicate::IsPresent => true,
15419625d8cSopenharmony_ci        }
15519625d8cSopenharmony_ci    }
15619625d8cSopenharmony_ci
15719625d8cSopenharmony_ci    pub(crate) fn source(&self) -> Option<ValueSource> {
15819625d8cSopenharmony_ci        self.source
15919625d8cSopenharmony_ci    }
16019625d8cSopenharmony_ci
16119625d8cSopenharmony_ci    pub(crate) fn set_source(&mut self, source: ValueSource) {
16219625d8cSopenharmony_ci        if let Some(existing) = self.source {
16319625d8cSopenharmony_ci            self.source = Some(existing.max(source));
16419625d8cSopenharmony_ci        } else {
16519625d8cSopenharmony_ci            self.source = Some(source)
16619625d8cSopenharmony_ci        }
16719625d8cSopenharmony_ci    }
16819625d8cSopenharmony_ci
16919625d8cSopenharmony_ci    pub(crate) fn type_id(&self) -> Option<AnyValueId> {
17019625d8cSopenharmony_ci        self.type_id
17119625d8cSopenharmony_ci    }
17219625d8cSopenharmony_ci
17319625d8cSopenharmony_ci    pub(crate) fn infer_type_id(&self, expected: AnyValueId) -> AnyValueId {
17419625d8cSopenharmony_ci        self.type_id()
17519625d8cSopenharmony_ci            .or_else(|| {
17619625d8cSopenharmony_ci                self.vals_flatten()
17719625d8cSopenharmony_ci                    .map(|v| v.type_id())
17819625d8cSopenharmony_ci                    .find(|actual| *actual != expected)
17919625d8cSopenharmony_ci            })
18019625d8cSopenharmony_ci            .unwrap_or(expected)
18119625d8cSopenharmony_ci    }
18219625d8cSopenharmony_ci}
18319625d8cSopenharmony_ci
18419625d8cSopenharmony_ciimpl PartialEq for MatchedArg {
18519625d8cSopenharmony_ci    fn eq(&self, other: &MatchedArg) -> bool {
18619625d8cSopenharmony_ci        let MatchedArg {
18719625d8cSopenharmony_ci            source: self_source,
18819625d8cSopenharmony_ci            indices: self_indices,
18919625d8cSopenharmony_ci            type_id: self_type_id,
19019625d8cSopenharmony_ci            vals: _,
19119625d8cSopenharmony_ci            raw_vals: self_raw_vals,
19219625d8cSopenharmony_ci            ignore_case: self_ignore_case,
19319625d8cSopenharmony_ci        } = self;
19419625d8cSopenharmony_ci        let MatchedArg {
19519625d8cSopenharmony_ci            source: other_source,
19619625d8cSopenharmony_ci            indices: other_indices,
19719625d8cSopenharmony_ci            type_id: other_type_id,
19819625d8cSopenharmony_ci            vals: _,
19919625d8cSopenharmony_ci            raw_vals: other_raw_vals,
20019625d8cSopenharmony_ci            ignore_case: other_ignore_case,
20119625d8cSopenharmony_ci        } = other;
20219625d8cSopenharmony_ci        self_source == other_source
20319625d8cSopenharmony_ci            && self_indices == other_indices
20419625d8cSopenharmony_ci            && self_type_id == other_type_id
20519625d8cSopenharmony_ci            && self_raw_vals == other_raw_vals
20619625d8cSopenharmony_ci            && self_ignore_case == other_ignore_case
20719625d8cSopenharmony_ci    }
20819625d8cSopenharmony_ci}
20919625d8cSopenharmony_ci
21019625d8cSopenharmony_ciimpl Eq for MatchedArg {}
21119625d8cSopenharmony_ci
21219625d8cSopenharmony_ci#[cfg(test)]
21319625d8cSopenharmony_cimod tests {
21419625d8cSopenharmony_ci    use super::*;
21519625d8cSopenharmony_ci
21619625d8cSopenharmony_ci    #[test]
21719625d8cSopenharmony_ci    fn test_grouped_vals_first() {
21819625d8cSopenharmony_ci        let mut m = MatchedArg::new_group();
21919625d8cSopenharmony_ci        m.new_val_group();
22019625d8cSopenharmony_ci        m.new_val_group();
22119625d8cSopenharmony_ci        m.append_val(AnyValue::new(String::from("bbb")), "bbb".into());
22219625d8cSopenharmony_ci        m.append_val(AnyValue::new(String::from("ccc")), "ccc".into());
22319625d8cSopenharmony_ci        assert_eq!(m.first_raw(), Some(&OsString::from("bbb")));
22419625d8cSopenharmony_ci    }
22519625d8cSopenharmony_ci}
226