clap/args/
arg_matcher.rs

1// Std
2use std::{
3    collections::{
4        hash_map::{Entry, Iter},
5        HashMap,
6    },
7    ffi::OsStr,
8    mem,
9    ops::Deref,
10};
11
12// Internal
13use crate::args::{settings::ArgSettings, AnyArg, ArgMatches, MatchedArg, SubCommand};
14
15#[doc(hidden)]
16#[allow(missing_debug_implementations)]
17pub struct ArgMatcher<'a>(pub ArgMatches<'a>);
18
19impl<'a> Default for ArgMatcher<'a> {
20    fn default() -> Self {
21        ArgMatcher(ArgMatches::default())
22    }
23}
24
25impl<'a> ArgMatcher<'a> {
26    pub fn new() -> Self {
27        ArgMatcher::default()
28    }
29
30    pub fn process_arg_overrides<'b>(
31        &mut self,
32        a: Option<&AnyArg<'a, 'b>>,
33        overrides: &mut Vec<(&'b str, &'a str)>,
34        required: &mut Vec<&'a str>,
35        check_all: bool,
36    ) {
37        debugln!(
38            "ArgMatcher::process_arg_overrides:{:?};",
39            a.map_or(None, |a| Some(a.name()))
40        );
41        if let Some(aa) = a {
42            let mut self_done = false;
43            if let Some(a_overrides) = aa.overrides() {
44                for overr in a_overrides {
45                    debugln!("ArgMatcher::process_arg_overrides:iter:{};", overr);
46                    if overr == &aa.name() {
47                        self_done = true;
48                        self.handle_self_overrides(a);
49                    } else if self.is_present(overr) {
50                        debugln!(
51                            "ArgMatcher::process_arg_overrides:iter:{}: removing from matches;",
52                            overr
53                        );
54                        self.remove(overr);
55                        for i in (0..required.len()).rev() {
56                            if &required[i] == overr {
57                                debugln!(
58                                    "ArgMatcher::process_arg_overrides:iter:{}: removing required;",
59                                    overr
60                                );
61                                required.swap_remove(i);
62                                break;
63                            }
64                        }
65                        overrides.push((overr, aa.name()));
66                    } else {
67                        overrides.push((overr, aa.name()));
68                    }
69                }
70            }
71            if check_all && !self_done {
72                self.handle_self_overrides(a);
73            }
74        }
75    }
76
77    pub fn handle_self_overrides<'b>(&mut self, a: Option<&AnyArg<'a, 'b>>) {
78        debugln!(
79            "ArgMatcher::handle_self_overrides:{:?};",
80            a.map_or(None, |a| Some(a.name()))
81        );
82        if let Some(aa) = a {
83            if !aa.has_switch() || aa.is_set(ArgSettings::Multiple) {
84                // positional args can't override self or else we would never advance to the next
85
86                // Also flags with --multiple set are ignored otherwise we could never have more
87                // than one
88                return;
89            }
90            if let Some(ma) = self.get_mut(aa.name()) {
91                if ma.vals.len() > 1 {
92                    // swap_remove(0) would be O(1) but does not preserve order, which
93                    // we need
94                    ma.vals.remove(0);
95                    ma.occurs = 1;
96                } else if !aa.takes_value() && ma.occurs > 1 {
97                    ma.occurs = 1;
98                }
99            }
100        }
101    }
102
103    pub fn is_present(&self, name: &str) -> bool {
104        self.0.is_present(name)
105    }
106
107    pub fn propagate_globals(&mut self, global_arg_vec: &[&'a str]) {
108        debugln!(
109            "ArgMatcher::get_global_values: global_arg_vec={:?}",
110            global_arg_vec
111        );
112        let mut vals_map = HashMap::new();
113        self.fill_in_global_values(global_arg_vec, &mut vals_map);
114    }
115
116    fn fill_in_global_values(
117        &mut self,
118        global_arg_vec: &[&'a str],
119        vals_map: &mut HashMap<&'a str, MatchedArg>,
120    ) {
121        for global_arg in global_arg_vec {
122            if let Some(ma) = self.get(global_arg) {
123                // We have to check if the parent's global arg wasn't used but still exists
124                // such as from a default value.
125                //
126                // For example, `myprog subcommand --global-arg=value` where --global-arg defines
127                // a default value of `other` myprog would have an existing MatchedArg for
128                // --global-arg where the value is `other`, however the occurs will be 0.
129                let to_update = if let Some(parent_ma) = vals_map.get(global_arg) {
130                    if parent_ma.occurs > 0 && ma.occurs == 0 {
131                        parent_ma.clone()
132                    } else {
133                        ma.clone()
134                    }
135                } else {
136                    ma.clone()
137                };
138                vals_map.insert(global_arg, to_update);
139            }
140        }
141        if let Some(ref mut sc) = self.0.subcommand {
142            let mut am = ArgMatcher(mem::replace(&mut sc.matches, ArgMatches::new()));
143            am.fill_in_global_values(global_arg_vec, vals_map);
144            mem::swap(&mut am.0, &mut sc.matches);
145        }
146
147        for (name, matched_arg) in vals_map.iter_mut() {
148            self.0.args.insert(name, matched_arg.clone());
149        }
150    }
151
152    pub fn get_mut(&mut self, arg: &str) -> Option<&mut MatchedArg> {
153        self.0.args.get_mut(arg)
154    }
155
156    pub fn get(&self, arg: &str) -> Option<&MatchedArg> {
157        self.0.args.get(arg)
158    }
159
160    pub fn remove(&mut self, arg: &str) {
161        self.0.args.remove(arg);
162    }
163
164    pub fn remove_all(&mut self, args: &[&str]) {
165        for &arg in args {
166            self.0.args.remove(arg);
167        }
168    }
169
170    pub fn insert(&mut self, name: &'a str) {
171        self.0.args.insert(name, MatchedArg::new());
172    }
173
174    pub fn contains(&self, arg: &str) -> bool {
175        self.0.args.contains_key(arg)
176    }
177
178    pub fn is_empty(&self) -> bool {
179        self.0.args.is_empty()
180    }
181
182    pub fn usage(&mut self, usage: String) {
183        self.0.usage = Some(usage);
184    }
185
186    pub fn arg_names(&'a self) -> Vec<&'a str> {
187        self.0.args.keys().map(Deref::deref).collect()
188    }
189
190    pub fn entry(&mut self, arg: &'a str) -> Entry<&'a str, MatchedArg> {
191        self.0.args.entry(arg)
192    }
193
194    pub fn subcommand(&mut self, sc: SubCommand<'a>) {
195        self.0.subcommand = Some(Box::new(sc));
196    }
197
198    pub fn subcommand_name(&self) -> Option<&str> {
199        self.0.subcommand_name()
200    }
201
202    pub fn iter(&self) -> Iter<&str, MatchedArg> {
203        self.0.args.iter()
204    }
205
206    pub fn inc_occurrence_of(&mut self, arg: &'a str) {
207        debugln!("ArgMatcher::inc_occurrence_of: arg={}", arg);
208        if let Some(a) = self.get_mut(arg) {
209            a.occurs += 1;
210            return;
211        }
212        debugln!("ArgMatcher::inc_occurrence_of: first instance");
213        self.insert(arg);
214    }
215
216    pub fn inc_occurrences_of(&mut self, args: &[&'a str]) {
217        debugln!("ArgMatcher::inc_occurrences_of: args={:?}", args);
218        for arg in args {
219            self.inc_occurrence_of(arg);
220        }
221    }
222
223    pub fn add_val_to(&mut self, arg: &'a str, val: &OsStr) {
224        let ma = self.entry(arg).or_insert(MatchedArg {
225            occurs: 0,
226            indices: Vec::with_capacity(1),
227            vals: Vec::with_capacity(1),
228        });
229        ma.vals.push(val.to_owned());
230    }
231
232    pub fn add_index_to(&mut self, arg: &'a str, idx: usize) {
233        let ma = self.entry(arg).or_insert(MatchedArg {
234            occurs: 0,
235            indices: Vec::with_capacity(1),
236            vals: Vec::new(),
237        });
238        ma.indices.push(idx);
239    }
240
241    pub fn needs_more_vals<'b, A>(&self, o: &A) -> bool
242    where
243        A: AnyArg<'a, 'b>,
244    {
245        debugln!("ArgMatcher::needs_more_vals: o={}", o.name());
246        if let Some(ma) = self.get(o.name()) {
247            if let Some(num) = o.num_vals() {
248                debugln!("ArgMatcher::needs_more_vals: num_vals...{}", num);
249                return if o.is_set(ArgSettings::Multiple) {
250                    ((ma.vals.len() as u64) % num) != 0
251                } else {
252                    num != (ma.vals.len() as u64)
253                };
254            } else if let Some(num) = o.max_vals() {
255                debugln!("ArgMatcher::needs_more_vals: max_vals...{}", num);
256                return (ma.vals.len() as u64) <= num;
257            } else if o.min_vals().is_some() {
258                debugln!("ArgMatcher::needs_more_vals: min_vals...true");
259                return true;
260            }
261            return o.is_set(ArgSettings::Multiple);
262        }
263        true
264    }
265}
266
267// Not changing to From just to not deal with possible breaking changes on v2 since v3 is coming
268// in the future anyways
269#[cfg_attr(feature = "cargo-clippy", allow(clippy::from_over_into))]
270impl<'a> Into<ArgMatches<'a>> for ArgMatcher<'a> {
271    fn into(self) -> ArgMatches<'a> {
272        self.0
273    }
274}