clap_builder/parser/matches/arg_matches.rs
1// Std
2use std::any::Any;
3use std::ffi::{OsStr, OsString};
4use std::fmt::Debug;
5use std::iter::{Cloned, Flatten, Map};
6use std::slice::Iter;
7
8// Internal
9#[cfg(debug_assertions)]
10use crate::builder::Str;
11use crate::parser::MatchedArg;
12use crate::parser::MatchesError;
13use crate::parser::ValueSource;
14use crate::util::AnyValue;
15use crate::util::AnyValueId;
16use crate::util::FlatMap;
17use crate::util::Id;
18use crate::INTERNAL_ERROR_MSG;
19
20/// Container for parse results.
21///
22/// Used to get information about the arguments that were supplied to the program at runtime by
23/// the user. New instances of this struct are obtained by using the [`Command::get_matches`] family of
24/// methods.
25///
26/// # Examples
27///
28/// ```no_run
29/// # use clap_builder as clap;
30/// # use clap::{Command, Arg, ArgAction};
31/// # use clap::parser::ValueSource;
32/// let matches = Command::new("MyApp")
33/// .arg(Arg::new("out")
34/// .long("output")
35/// .required(true)
36/// .action(ArgAction::Set)
37/// .default_value("-"))
38/// .arg(Arg::new("cfg")
39/// .short('c')
40/// .action(ArgAction::Set))
41/// .get_matches(); // builds the instance of ArgMatches
42///
43/// // to get information about the "cfg" argument we created, such as the value supplied we use
44/// // various ArgMatches methods, such as [ArgMatches::get_one]
45/// if let Some(c) = matches.get_one::<String>("cfg") {
46/// println!("Value for -c: {c}");
47/// }
48///
49/// // The ArgMatches::get_one method returns an Option because the user may not have supplied
50/// // that argument at runtime. But if we specified that the argument was "required" as we did
51/// // with the "out" argument, we can safely unwrap because `clap` verifies that was actually
52/// // used at runtime.
53/// println!("Value for --output: {}", matches.get_one::<String>("out").unwrap());
54///
55/// // You can check the presence of an argument's values
56/// if matches.contains_id("out") {
57/// // However, if you want to know where the value came from
58/// if matches.value_source("out").expect("checked contains_id") == ValueSource::CommandLine {
59/// println!("`out` set by user");
60/// } else {
61/// println!("`out` is defaulted");
62/// }
63/// }
64/// ```
65/// [`Command::get_matches`]: crate::Command::get_matches()
66#[derive(Debug, Clone, Default, PartialEq, Eq)]
67pub struct ArgMatches {
68 #[cfg(debug_assertions)]
69 pub(crate) valid_args: Vec<Id>,
70 #[cfg(debug_assertions)]
71 pub(crate) valid_subcommands: Vec<Str>,
72 pub(crate) args: FlatMap<Id, MatchedArg>,
73 pub(crate) subcommand: Option<Box<SubCommand>>,
74}
75
76/// # Arguments
77impl ArgMatches {
78 /// Gets the value of a specific option or positional argument.
79 ///
80 /// i.e. an argument that [takes an additional value][crate::Arg::num_args] at runtime.
81 ///
82 /// Returns an error if the wrong type was used.
83 ///
84 /// Returns `None` if the option wasn't present.
85 ///
86 /// <div class="warning">
87 ///
88 /// *NOTE:* This will always return `Some(value)` if [`default_value`] has been set.
89 /// [`ArgMatches::value_source`] can be used to check if a value is present at runtime.
90 ///
91 /// </div>
92 ///
93 /// # Panic
94 ///
95 /// If the argument definition and access mismatch. To handle this case programmatically, see
96 /// [`ArgMatches::try_get_one`].
97 ///
98 /// # Examples
99 ///
100 /// ```rust
101 /// # use clap_builder as clap;
102 /// # use clap::{Command, Arg, value_parser, ArgAction};
103 /// let m = Command::new("myapp")
104 /// .arg(Arg::new("port")
105 /// .value_parser(value_parser!(usize))
106 /// .action(ArgAction::Set)
107 /// .required(true))
108 /// .get_matches_from(vec!["myapp", "2020"]);
109 ///
110 /// let port: usize = *m
111 /// .get_one("port")
112 /// .expect("`port`is required");
113 /// assert_eq!(port, 2020);
114 /// ```
115 /// [positional]: crate::Arg::index()
116 /// [`default_value`]: crate::Arg::default_value()
117 #[cfg_attr(debug_assertions, track_caller)]
118 pub fn get_one<T: Any + Clone + Send + Sync + 'static>(&self, id: &str) -> Option<&T> {
119 MatchesError::unwrap(id, self.try_get_one(id))
120 }
121
122 /// Gets the value of a specific [`ArgAction::Count`][crate::ArgAction::Count] flag
123 ///
124 /// # Panic
125 ///
126 /// If the argument's action is not [`ArgAction::Count`][crate::ArgAction::Count]
127 ///
128 /// # Examples
129 ///
130 /// ```rust
131 /// # use clap_builder as clap;
132 /// # use clap::Command;
133 /// # use clap::Arg;
134 /// let cmd = Command::new("mycmd")
135 /// .arg(
136 /// Arg::new("flag")
137 /// .long("flag")
138 /// .action(clap::ArgAction::Count)
139 /// );
140 ///
141 /// let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag", "--flag"]).unwrap();
142 /// assert_eq!(
143 /// matches.get_count("flag"),
144 /// 2
145 /// );
146 /// ```
147 #[cfg_attr(debug_assertions, track_caller)]
148 pub fn get_count(&self, id: &str) -> u8 {
149 *self.get_one::<u8>(id).unwrap_or_else(|| {
150 panic!("arg `{id}`'s `ArgAction` should be `Count` which should provide a default")
151 })
152 }
153
154 /// Gets the value of a specific [`ArgAction::SetTrue`][crate::ArgAction::SetTrue] or [`ArgAction::SetFalse`][crate::ArgAction::SetFalse] flag
155 ///
156 /// # Panic
157 ///
158 /// If the argument's action is not [`ArgAction::SetTrue`][crate::ArgAction::SetTrue] or [`ArgAction::SetFalse`][crate::ArgAction::SetFalse]
159 ///
160 /// # Examples
161 ///
162 /// ```rust
163 /// # use clap_builder as clap;
164 /// # use clap::Command;
165 /// # use clap::Arg;
166 /// let cmd = Command::new("mycmd")
167 /// .arg(
168 /// Arg::new("flag")
169 /// .long("flag")
170 /// .action(clap::ArgAction::SetTrue)
171 /// );
172 ///
173 /// let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag"]).unwrap();
174 /// assert!(matches.contains_id("flag"));
175 /// assert_eq!(
176 /// matches.get_flag("flag"),
177 /// true
178 /// );
179 /// ```
180 #[cfg_attr(debug_assertions, track_caller)]
181 pub fn get_flag(&self, id: &str) -> bool {
182 *self
183 .get_one::<bool>(id)
184 .unwrap_or_else(|| {
185 panic!(
186 "arg `{id}`'s `ArgAction` should be one of `SetTrue`, `SetFalse` which should provide a default"
187 )
188 })
189 }
190
191 /// Iterate over values of a specific option or positional argument.
192 ///
193 /// i.e. an argument that takes multiple values at runtime.
194 ///
195 /// Returns an error if the wrong type was used.
196 ///
197 /// Returns `None` if the option wasn't present.
198 ///
199 /// # Panic
200 ///
201 /// If the argument definition and access mismatch. To handle this case programmatically, see
202 /// [`ArgMatches::try_get_many`].
203 ///
204 /// # Examples
205 ///
206 /// ```rust
207 /// # use clap_builder as clap;
208 /// # use clap::{Command, Arg, value_parser, ArgAction};
209 /// let m = Command::new("myprog")
210 /// .arg(Arg::new("ports")
211 /// .action(ArgAction::Append)
212 /// .value_parser(value_parser!(usize))
213 /// .short('p')
214 /// .required(true))
215 /// .get_matches_from(vec![
216 /// "myprog", "-p", "22", "-p", "80", "-p", "2020"
217 /// ]);
218 /// let vals: Vec<usize> = m.get_many("ports")
219 /// .expect("`port`is required")
220 /// .copied()
221 /// .collect();
222 /// assert_eq!(vals, [22, 80, 2020]);
223 /// ```
224 #[cfg_attr(debug_assertions, track_caller)]
225 pub fn get_many<T: Any + Clone + Send + Sync + 'static>(
226 &self,
227 id: &str,
228 ) -> Option<ValuesRef<'_, T>> {
229 MatchesError::unwrap(id, self.try_get_many(id))
230 }
231
232 /// Iterate over the values passed to each occurrence of an option.
233 ///
234 /// Each item is itself an iterator containing the arguments passed to a single occurrence
235 /// of the option.
236 ///
237 /// If the option doesn't support multiple occurrences, or there was only a single occurrence,
238 /// the iterator will only contain a single item.
239 ///
240 /// Returns `None` if the option wasn't present.
241 ///
242 /// # Panics
243 ///
244 /// If the argument definition and access mismatch (debug builds). To handle this case programmatically, see
245 /// [`ArgMatches::try_get_occurrences`].
246 ///
247 /// # Examples
248 /// ```rust
249 /// # use clap_builder as clap;
250 /// # use clap::{Command,Arg, ArgAction, value_parser};
251 /// let m = Command::new("myprog")
252 /// .arg(Arg::new("x")
253 /// .short('x')
254 /// .num_args(2)
255 /// .action(ArgAction::Append)
256 /// .value_parser(value_parser!(String)))
257 /// .get_matches_from(vec![
258 /// "myprog", "-x", "a", "b", "-x", "c", "d"]);
259 /// let vals: Vec<Vec<&String>> = m.get_occurrences("x").unwrap().map(Iterator::collect).collect();
260 /// assert_eq!(vals, [["a", "b"], ["c", "d"]]);
261 /// ```
262 #[cfg_attr(debug_assertions, track_caller)]
263 pub fn get_occurrences<T: Any + Clone + Send + Sync + 'static>(
264 &self,
265 id: &str,
266 ) -> Option<OccurrencesRef<'_, T>> {
267 MatchesError::unwrap(id, self.try_get_occurrences(id))
268 }
269
270 /// Iterate over the original argument values.
271 ///
272 /// An `OsStr` on Unix-like systems is any series of bytes, regardless of whether or not they
273 /// contain valid UTF-8. Since [`String`]s in Rust are guaranteed to be valid UTF-8, a valid
274 /// filename on a Unix system as an argument value may contain invalid UTF-8.
275 ///
276 /// Returns `None` if the option wasn't present.
277 ///
278 /// # Panic
279 ///
280 /// If the argument definition and access mismatch. To handle this case programmatically, see
281 /// [`ArgMatches::try_get_raw`].
282 ///
283 /// # Examples
284 ///
285 /// ```rust
286 /// # #[cfg(unix)] {
287 /// # use clap_builder as clap;
288 /// # use clap::{Command, arg, value_parser};
289 /// # use std::ffi::{OsStr,OsString};
290 /// # use std::os::unix::ffi::{OsStrExt,OsStringExt};
291 /// use std::path::PathBuf;
292 ///
293 /// let m = Command::new("utf8")
294 /// .arg(arg!(<arg> ... "some arg").value_parser(value_parser!(PathBuf)))
295 /// .get_matches_from(vec![OsString::from("myprog"),
296 /// // "Hi"
297 /// OsString::from_vec(vec![b'H', b'i']),
298 /// // "{0xe9}!"
299 /// OsString::from_vec(vec![0xe9, b'!'])]);
300 ///
301 /// let mut itr = m.get_raw("arg")
302 /// .expect("`port`is required")
303 /// .into_iter();
304 /// assert_eq!(itr.next(), Some(OsStr::new("Hi")));
305 /// assert_eq!(itr.next(), Some(OsStr::from_bytes(&[0xe9, b'!'])));
306 /// assert_eq!(itr.next(), None);
307 /// # }
308 /// ```
309 /// [`Iterator`]: std::iter::Iterator
310 /// [`OsSt`]: std::ffi::OsStr
311 /// [`String`]: std::string::String
312 #[cfg_attr(debug_assertions, track_caller)]
313 pub fn get_raw(&self, id: &str) -> Option<RawValues<'_>> {
314 MatchesError::unwrap(id, self.try_get_raw(id))
315 }
316
317 /// Iterate over the original values for each occurrence of an option.
318 ///
319 /// Similar to [`ArgMatches::get_occurrences`] but returns raw values.
320 ///
321 /// An `OsStr` on Unix-like systems is any series of bytes, regardless of whether or not they
322 /// contain valid UTF-8. Since [`String`]s in Rust are guaranteed to be valid UTF-8, a valid
323 /// filename on a Unix system as an argument value may contain invalid UTF-8.
324 ///
325 /// Returns `None` if the option wasn't present.
326 ///
327 /// # Panic
328 ///
329 /// If the argument definition and access mismatch. To handle this case programmatically, see
330 /// [`ArgMatches::try_get_raw_occurrences`].
331 ///
332 /// # Examples
333 ///
334 /// ```rust
335 /// # #[cfg(unix)] {
336 /// # use clap_builder as clap;
337 /// # use clap::{Command, arg, value_parser, ArgAction, Arg};
338 /// # use std::ffi::{OsStr,OsString};
339 /// # use std::os::unix::ffi::{OsStrExt,OsStringExt};
340 /// use std::path::PathBuf;
341 ///
342 /// let m = Command::new("myprog")
343 /// .arg(Arg::new("x")
344 /// .short('x')
345 /// .num_args(2)
346 /// .action(ArgAction::Append)
347 /// .value_parser(value_parser!(PathBuf)))
348 /// .get_matches_from(vec![OsString::from("myprog"),
349 /// OsString::from("-x"),
350 /// OsString::from("a"), OsString::from("b"),
351 /// OsString::from("-x"),
352 /// OsString::from("c"),
353 /// // "{0xe9}!"
354 /// OsString::from_vec(vec![0xe9, b'!'])]);
355 /// let mut itr = m.get_raw_occurrences("x")
356 /// .expect("`-x`is required")
357 /// .map(Iterator::collect::<Vec<_>>);
358 /// assert_eq!(itr.next(), Some(vec![OsStr::new("a"), OsStr::new("b")]));
359 /// assert_eq!(itr.next(), Some(vec![OsStr::new("c"), OsStr::from_bytes(&[0xe9, b'!'])]));
360 /// assert_eq!(itr.next(), None);
361 /// # }
362 /// ```
363 /// [`Iterator`]: std::iter::Iterator
364 /// [`OsStr`]: std::ffi::OsStr
365 /// [`String`]: std::string::String
366 #[cfg_attr(debug_assertions, track_caller)]
367 pub fn get_raw_occurrences(&self, id: &str) -> Option<RawOccurrences<'_>> {
368 MatchesError::unwrap(id, self.try_get_raw_occurrences(id))
369 }
370
371 /// Returns the value of a specific option or positional argument.
372 ///
373 /// i.e. an argument that [takes an additional value][crate::Arg::num_args] at runtime.
374 ///
375 /// Returns an error if the wrong type was used. No item will have been removed.
376 ///
377 /// Returns `None` if the option wasn't present.
378 ///
379 /// <div class="warning">
380 ///
381 /// *NOTE:* This will always return `Some(value)` if [`default_value`] has been set.
382 /// [`ArgMatches::value_source`] can be used to check if a value is present at runtime.
383 ///
384 /// </div>
385 ///
386 /// # Panic
387 ///
388 /// If the argument definition and access mismatch. To handle this case programmatically, see
389 /// [`ArgMatches::try_remove_one`].
390 ///
391 /// # Examples
392 ///
393 /// ```rust
394 /// # use clap_builder as clap;
395 /// # use clap::{Command, Arg, value_parser, ArgAction};
396 /// let mut m = Command::new("myprog")
397 /// .arg(Arg::new("file")
398 /// .required(true)
399 /// .action(ArgAction::Set))
400 /// .get_matches_from(vec![
401 /// "myprog", "file.txt",
402 /// ]);
403 /// let vals: String = m.remove_one("file")
404 /// .expect("`file`is required");
405 /// assert_eq!(vals, "file.txt");
406 /// ```
407 /// [positional]: crate::Arg::index()
408 /// [`default_value`]: crate::Arg::default_value()
409 #[cfg_attr(debug_assertions, track_caller)]
410 pub fn remove_one<T: Any + Clone + Send + Sync + 'static>(&mut self, id: &str) -> Option<T> {
411 MatchesError::unwrap(id, self.try_remove_one(id))
412 }
413
414 /// Return values of a specific option or positional argument.
415 ///
416 /// i.e. an argument that takes multiple values at runtime.
417 ///
418 /// Returns an error if the wrong type was used. No item will have been removed.
419 ///
420 /// Returns `None` if the option wasn't present.
421 ///
422 /// # Panic
423 ///
424 /// If the argument definition and access mismatch. To handle this case programmatically, see
425 /// [`ArgMatches::try_remove_many`].
426 ///
427 /// # Examples
428 ///
429 /// ```rust
430 /// # use clap_builder as clap;
431 /// # use clap::{Command, Arg, value_parser, ArgAction};
432 /// let mut m = Command::new("myprog")
433 /// .arg(Arg::new("file")
434 /// .action(ArgAction::Append)
435 /// .num_args(1..)
436 /// .required(true))
437 /// .get_matches_from(vec![
438 /// "myprog", "file1.txt", "file2.txt", "file3.txt", "file4.txt",
439 /// ]);
440 /// let vals: Vec<String> = m.remove_many("file")
441 /// .expect("`file`is required")
442 /// .collect();
443 /// assert_eq!(vals, ["file1.txt", "file2.txt", "file3.txt", "file4.txt"]);
444 /// ```
445 #[cfg_attr(debug_assertions, track_caller)]
446 pub fn remove_many<T: Any + Clone + Send + Sync + 'static>(
447 &mut self,
448 id: &str,
449 ) -> Option<Values<T>> {
450 MatchesError::unwrap(id, self.try_remove_many(id))
451 }
452
453 /// Return values for each occurrence of an option.
454 ///
455 /// Each item is itself an iterator containing the arguments passed to a single occurrence of
456 /// the option.
457 ///
458 /// If the option doesn't support multiple occurrences, or there was only a single occurrence,
459 /// the iterator will only contain a single item.
460 ///
461 /// Returns `None` if the option wasn't present.
462 ///
463 /// # Panic
464 ///
465 /// If the argument definition and access mismatch. To handle this case programmatically, see
466 /// [`ArgMatches::try_remove_occurrences`].
467 ///
468 /// # Examples
469 ///
470 /// ```rust
471 /// # use clap_builder as clap;
472 /// # use clap::{Command, Arg, value_parser, ArgAction};
473 /// let mut m = Command::new("myprog")
474 /// .arg(Arg::new("x")
475 /// .short('x')
476 /// .num_args(2)
477 /// .action(ArgAction::Append)
478 /// .value_parser(value_parser!(String)))
479 /// .get_matches_from(vec![
480 /// "myprog", "-x", "a", "b", "-x", "c", "d"]);
481 /// let vals: Vec<Vec<String>> = m.remove_occurrences("x").unwrap().map(Iterator::collect).collect();
482 /// assert_eq!(vals, [["a", "b"], ["c", "d"]]);
483 /// ```
484 #[cfg_attr(debug_assertions, track_caller)]
485 pub fn remove_occurrences<T: Any + Clone + Send + Sync + 'static>(
486 &mut self,
487 id: &str,
488 ) -> Option<Occurrences<T>> {
489 MatchesError::unwrap(id, self.try_remove_occurrences(id))
490 }
491
492 /// Check if values are present for the argument or group id
493 ///
494 /// <div class="warning">
495 ///
496 /// *NOTE:* This will always return `true` if [`default_value`] has been set.
497 /// [`ArgMatches::value_source`] can be used to check if a value is present at runtime.
498 ///
499 /// </div>
500 ///
501 /// # Panics
502 ///
503 /// If `id` is not a valid argument or group name (debug builds). To handle this case programmatically, see
504 /// [`ArgMatches::try_contains_id`].
505 ///
506 /// # Examples
507 ///
508 /// ```rust
509 /// # use clap_builder as clap;
510 /// # use clap::{Command, Arg, ArgAction};
511 /// let m = Command::new("myprog")
512 /// .arg(Arg::new("debug")
513 /// .short('d')
514 /// .action(ArgAction::SetTrue))
515 /// .get_matches_from(vec![
516 /// "myprog", "-d"
517 /// ]);
518 ///
519 /// assert!(m.contains_id("debug"));
520 /// ```
521 ///
522 /// [`default_value`]: crate::Arg::default_value()
523 pub fn contains_id(&self, id: &str) -> bool {
524 MatchesError::unwrap(id, self.try_contains_id(id))
525 }
526
527 /// Iterate over [`Arg`][crate::Arg] and [`ArgGroup`][crate::ArgGroup] [`Id`]s via [`ArgMatches::ids`].
528 ///
529 /// # Examples
530 ///
531 /// ```rust
532 /// # use clap_builder as clap;
533 /// # use clap::{Command, arg, value_parser};
534 ///
535 /// let m = Command::new("myprog")
536 /// .arg(arg!(--color <when>)
537 /// .value_parser(["auto", "always", "never"]))
538 /// .arg(arg!(--config <path>)
539 /// .value_parser(value_parser!(std::path::PathBuf)))
540 /// .get_matches_from(["myprog", "--config=config.toml", "--color=auto"]);
541 /// assert_eq!(m.ids().len(), 2);
542 /// assert_eq!(
543 /// m.ids()
544 /// .map(|id| id.as_str())
545 /// .collect::<Vec<_>>(),
546 /// ["config", "color"]
547 /// );
548 /// ```
549 pub fn ids(&self) -> IdsRef<'_> {
550 IdsRef {
551 iter: self.args.keys(),
552 }
553 }
554
555 /// Check if any [`Arg`][crate::Arg]s were present on the command line
556 ///
557 /// See [`ArgMatches::subcommand_name()`] or [`ArgMatches::subcommand()`] to check if a
558 /// subcommand was present on the command line.
559 ///
560 /// # Examples
561 ///
562 /// ```rust
563 /// # use clap_builder as clap;
564 /// # use clap::{Command, Arg, ArgAction};
565 /// let mut cmd = Command::new("myapp")
566 /// .arg(Arg::new("output")
567 /// .action(ArgAction::Set));
568 ///
569 /// let m = cmd
570 /// .try_get_matches_from_mut(vec!["myapp", "something"])
571 /// .unwrap();
572 /// assert!(m.args_present());
573 ///
574 /// let m = cmd
575 /// .try_get_matches_from_mut(vec!["myapp"])
576 /// .unwrap();
577 /// assert!(! m.args_present());
578 pub fn args_present(&self) -> bool {
579 self.args
580 .values()
581 .any(|v| v.source().map(|s| s.is_explicit()).unwrap_or(false))
582 }
583
584 /// Report where argument value came from
585 ///
586 /// # Panics
587 ///
588 /// If `id` is not a valid argument or group id (debug builds).
589 ///
590 /// # Examples
591 ///
592 /// ```rust
593 /// # use clap_builder as clap;
594 /// # use clap::{Command, Arg, ArgAction};
595 /// # use clap::parser::ValueSource;
596 /// let m = Command::new("myprog")
597 /// .arg(Arg::new("debug")
598 /// .short('d')
599 /// .action(ArgAction::SetTrue))
600 /// .get_matches_from(vec![
601 /// "myprog", "-d"
602 /// ]);
603 ///
604 /// assert_eq!(m.value_source("debug"), Some(ValueSource::CommandLine));
605 /// ```
606 ///
607 /// [`default_value`]: crate::Arg::default_value()
608 #[cfg_attr(debug_assertions, track_caller)]
609 pub fn value_source(&self, id: &str) -> Option<ValueSource> {
610 let value = self.get_arg(id);
611
612 value.and_then(MatchedArg::source)
613 }
614
615 /// The first index of that an argument showed up.
616 ///
617 /// Indices are similar to argv indices, but are not exactly 1:1.
618 ///
619 /// For flags (i.e. those arguments which don't have an associated value), indices refer
620 /// to occurrence of the switch, such as `-f`, or `--flag`. However, for options the indices
621 /// refer to the *values* `-o val` would therefore not represent two distinct indices, only the
622 /// index for `val` would be recorded. This is by design.
623 ///
624 /// Besides the flag/option discrepancy, the primary difference between an argv index and clap
625 /// index, is that clap continues counting once all arguments have properly separated, whereas
626 /// an argv index does not.
627 ///
628 /// The examples should clear this up.
629 ///
630 /// <div class="warning">
631 ///
632 /// *NOTE:* If an argument is allowed multiple times, this method will only give the *first*
633 /// index. See [`ArgMatches::indices_of`].
634 ///
635 /// </div>
636 ///
637 /// # Panics
638 ///
639 /// If `id` is not a valid argument or group id (debug builds).
640 ///
641 /// # Examples
642 ///
643 /// The argv indices are listed in the comments below. See how they correspond to the clap
644 /// indices. Note that if it's not listed in a clap index, this is because it's not saved in
645 /// in an `ArgMatches` struct for querying.
646 ///
647 /// ```rust
648 /// # use clap_builder as clap;
649 /// # use clap::{Command, Arg, ArgAction};
650 /// let m = Command::new("myapp")
651 /// .arg(Arg::new("flag")
652 /// .short('f')
653 /// .action(ArgAction::SetTrue))
654 /// .arg(Arg::new("option")
655 /// .short('o')
656 /// .action(ArgAction::Set))
657 /// .get_matches_from(vec!["myapp", "-f", "-o", "val"]);
658 /// // ARGV indices: ^0 ^1 ^2 ^3
659 /// // clap indices: ^1 ^3
660 ///
661 /// assert_eq!(m.index_of("flag"), Some(1));
662 /// assert_eq!(m.index_of("option"), Some(3));
663 /// ```
664 ///
665 /// Now notice, if we use one of the other styles of options:
666 ///
667 /// ```rust
668 /// # use clap_builder as clap;
669 /// # use clap::{Command, Arg, ArgAction};
670 /// let m = Command::new("myapp")
671 /// .arg(Arg::new("flag")
672 /// .short('f')
673 /// .action(ArgAction::SetTrue))
674 /// .arg(Arg::new("option")
675 /// .short('o')
676 /// .action(ArgAction::Set))
677 /// .get_matches_from(vec!["myapp", "-f", "-o=val"]);
678 /// // ARGV indices: ^0 ^1 ^2
679 /// // clap indices: ^1 ^3
680 ///
681 /// assert_eq!(m.index_of("flag"), Some(1));
682 /// assert_eq!(m.index_of("option"), Some(3));
683 /// ```
684 ///
685 /// Things become much more complicated, or clear if we look at a more complex combination of
686 /// flags. Let's also throw in the final option style for good measure.
687 ///
688 /// ```rust
689 /// # use clap_builder as clap;
690 /// # use clap::{Command, Arg, ArgAction};
691 /// let m = Command::new("myapp")
692 /// .arg(Arg::new("flag")
693 /// .short('f')
694 /// .action(ArgAction::SetTrue))
695 /// .arg(Arg::new("flag2")
696 /// .short('F')
697 /// .action(ArgAction::SetTrue))
698 /// .arg(Arg::new("flag3")
699 /// .short('z')
700 /// .action(ArgAction::SetTrue))
701 /// .arg(Arg::new("option")
702 /// .short('o')
703 /// .action(ArgAction::Set))
704 /// .get_matches_from(vec!["myapp", "-fzF", "-oval"]);
705 /// // ARGV indices: ^0 ^1 ^2
706 /// // clap indices: ^1,2,3 ^5
707 /// //
708 /// // clap sees the above as 'myapp -f -z -F -o val'
709 /// // ^0 ^1 ^2 ^3 ^4 ^5
710 /// assert_eq!(m.index_of("flag"), Some(1));
711 /// assert_eq!(m.index_of("flag2"), Some(3));
712 /// assert_eq!(m.index_of("flag3"), Some(2));
713 /// assert_eq!(m.index_of("option"), Some(5));
714 /// ```
715 ///
716 /// One final combination of flags/options to see how they combine:
717 ///
718 /// ```rust
719 /// # use clap_builder as clap;
720 /// # use clap::{Command, Arg, ArgAction};
721 /// let m = Command::new("myapp")
722 /// .arg(Arg::new("flag")
723 /// .short('f')
724 /// .action(ArgAction::SetTrue))
725 /// .arg(Arg::new("flag2")
726 /// .short('F')
727 /// .action(ArgAction::SetTrue))
728 /// .arg(Arg::new("flag3")
729 /// .short('z')
730 /// .action(ArgAction::SetTrue))
731 /// .arg(Arg::new("option")
732 /// .short('o')
733 /// .action(ArgAction::Set))
734 /// .get_matches_from(vec!["myapp", "-fzFoval"]);
735 /// // ARGV indices: ^0 ^1
736 /// // clap indices: ^1,2,3^5
737 /// //
738 /// // clap sees the above as 'myapp -f -z -F -o val'
739 /// // ^0 ^1 ^2 ^3 ^4 ^5
740 /// assert_eq!(m.index_of("flag"), Some(1));
741 /// assert_eq!(m.index_of("flag2"), Some(3));
742 /// assert_eq!(m.index_of("flag3"), Some(2));
743 /// assert_eq!(m.index_of("option"), Some(5));
744 /// ```
745 ///
746 /// The last part to mention is when values are sent in multiple groups with a [delimiter].
747 ///
748 /// ```rust
749 /// # use clap_builder as clap;
750 /// # use clap::{Command, Arg};
751 /// let m = Command::new("myapp")
752 /// .arg(Arg::new("option")
753 /// .short('o')
754 /// .value_delimiter(',')
755 /// .num_args(1..))
756 /// .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]);
757 /// // ARGV indices: ^0 ^1
758 /// // clap indices: ^2 ^3 ^4
759 /// //
760 /// // clap sees the above as 'myapp -o val1 val2 val3'
761 /// // ^0 ^1 ^2 ^3 ^4
762 /// assert_eq!(m.index_of("option"), Some(2));
763 /// assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2, 3, 4]);
764 /// ```
765 /// [delimiter]: crate::Arg::value_delimiter()
766 #[cfg_attr(debug_assertions, track_caller)]
767 pub fn index_of(&self, id: &str) -> Option<usize> {
768 let arg = some!(self.get_arg(id));
769 let i = some!(arg.get_index(0));
770 Some(i)
771 }
772
773 /// All indices an argument appeared at when parsing.
774 ///
775 /// Indices are similar to argv indices, but are not exactly 1:1.
776 ///
777 /// For flags (i.e. those arguments which don't have an associated value), indices refer
778 /// to occurrence of the switch, such as `-f`, or `--flag`. However, for options the indices
779 /// refer to the *values* `-o val` would therefore not represent two distinct indices, only the
780 /// index for `val` would be recorded. This is by design.
781 ///
782 /// <div class="warning">
783 ///
784 /// *NOTE:* For more information about how clap indices compared to argv indices, see
785 /// [`ArgMatches::index_of`]
786 ///
787 /// </div>
788 ///
789 /// # Panics
790 ///
791 /// If `id` is not a valid argument or group id (debug builds).
792 ///
793 /// # Examples
794 ///
795 /// ```rust
796 /// # use clap_builder as clap;
797 /// # use clap::{Command, Arg};
798 /// let m = Command::new("myapp")
799 /// .arg(Arg::new("option")
800 /// .short('o')
801 /// .value_delimiter(','))
802 /// .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]);
803 /// // ARGV indices: ^0 ^1
804 /// // clap indices: ^2 ^3 ^4
805 /// //
806 /// // clap sees the above as 'myapp -o val1 val2 val3'
807 /// // ^0 ^1 ^2 ^3 ^4
808 /// assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2, 3, 4]);
809 /// ```
810 ///
811 /// Another quick example is when flags and options are used together
812 ///
813 /// ```rust
814 /// # use clap_builder as clap;
815 /// # use clap::{Command, Arg, ArgAction};
816 /// let m = Command::new("myapp")
817 /// .arg(Arg::new("option")
818 /// .short('o')
819 /// .action(ArgAction::Set)
820 /// .action(ArgAction::Append))
821 /// .arg(Arg::new("flag")
822 /// .short('f')
823 /// .action(ArgAction::Count))
824 /// .get_matches_from(vec!["myapp", "-o", "val1", "-f", "-o", "val2", "-f"]);
825 /// // ARGV indices: ^0 ^1 ^2 ^3 ^4 ^5 ^6
826 /// // clap indices: ^2 ^3 ^5 ^6
827 ///
828 /// assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2, 5]);
829 /// assert_eq!(m.indices_of("flag").unwrap().collect::<Vec<_>>(), &[6]);
830 /// ```
831 ///
832 /// One final example, which is an odd case; if we *don't* use value delimiter as we did with
833 /// the first example above instead of `val1`, `val2` and `val3` all being distinc values, they
834 /// would all be a single value of `val1,val2,val3`, in which case they'd only receive a single
835 /// index.
836 ///
837 /// ```rust
838 /// # use clap_builder as clap;
839 /// # use clap::{Command, Arg, ArgAction};
840 /// let m = Command::new("myapp")
841 /// .arg(Arg::new("option")
842 /// .short('o')
843 /// .action(ArgAction::Set)
844 /// .num_args(1..))
845 /// .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]);
846 /// // ARGV indices: ^0 ^1
847 /// // clap indices: ^2
848 /// //
849 /// // clap sees the above as 'myapp -o "val1,val2,val3"'
850 /// // ^0 ^1 ^2
851 /// assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2]);
852 /// ```
853 /// [`ArgMatches::index_of`]: ArgMatches::index_of()
854 #[cfg_attr(debug_assertions, track_caller)]
855 pub fn indices_of(&self, id: &str) -> Option<Indices<'_>> {
856 let arg = some!(self.get_arg(id));
857 let i = Indices {
858 iter: arg.indices(),
859 len: arg.num_vals(),
860 };
861 Some(i)
862 }
863}
864
865/// # Subcommands
866impl ArgMatches {
867 /// The name and `ArgMatches` of the current [subcommand].
868 ///
869 /// Subcommand values are put in a child [`ArgMatches`]
870 ///
871 /// Returns `None` if the subcommand wasn't present at runtime,
872 ///
873 /// # Examples
874 ///
875 /// ```no_run
876 /// # use clap_builder as clap;
877 /// # use clap::{Command, Arg, };
878 /// let app_m = Command::new("git")
879 /// .subcommand(Command::new("clone"))
880 /// .subcommand(Command::new("push"))
881 /// .subcommand(Command::new("commit"))
882 /// .get_matches();
883 ///
884 /// match app_m.subcommand() {
885 /// Some(("clone", sub_m)) => {}, // clone was used
886 /// Some(("push", sub_m)) => {}, // push was used
887 /// Some(("commit", sub_m)) => {}, // commit was used
888 /// _ => {}, // Either no subcommand or one not tested for...
889 /// }
890 /// ```
891 ///
892 /// Another useful scenario is when you want to support third party, or external, subcommands.
893 /// In these cases you can't know the subcommand name ahead of time, so use a variable instead
894 /// with pattern matching!
895 ///
896 /// ```rust
897 /// # use clap_builder as clap;
898 /// # use std::ffi::OsString;
899 /// # use std::ffi::OsStr;
900 /// # use clap::Command;
901 /// // Assume there is an external subcommand named "subcmd"
902 /// let app_m = Command::new("myprog")
903 /// .allow_external_subcommands(true)
904 /// .get_matches_from(vec![
905 /// "myprog", "subcmd", "--option", "value", "-fff", "--flag"
906 /// ]);
907 ///
908 /// // All trailing arguments will be stored under the subcommand's sub-matches using an empty
909 /// // string argument name
910 /// match app_m.subcommand() {
911 /// Some((external, sub_m)) => {
912 /// let ext_args: Vec<&OsStr> = sub_m.get_many::<OsString>("")
913 /// .unwrap().map(|s| s.as_os_str()).collect();
914 /// assert_eq!(external, "subcmd");
915 /// assert_eq!(ext_args, ["--option", "value", "-fff", "--flag"]);
916 /// },
917 /// _ => {},
918 /// }
919 /// ```
920 /// [subcommand]: crate::Command::subcommand
921 #[inline]
922 pub fn subcommand(&self) -> Option<(&str, &ArgMatches)> {
923 self.subcommand.as_ref().map(|sc| (&*sc.name, &sc.matches))
924 }
925
926 /// Return the name and `ArgMatches` of the current [subcommand].
927 ///
928 /// Subcommand values are put in a child [`ArgMatches`]
929 ///
930 /// Returns `None` if the subcommand wasn't present at runtime,
931 ///
932 /// # Examples
933 ///
934 /// ```no_run
935 /// # use clap_builder as clap;
936 /// # use clap::{Command, Arg, };
937 /// let mut app_m = Command::new("git")
938 /// .subcommand(Command::new("clone"))
939 /// .subcommand(Command::new("push"))
940 /// .subcommand(Command::new("commit"))
941 /// .subcommand_required(true)
942 /// .get_matches();
943 ///
944 /// let (name, sub_m) = app_m.remove_subcommand().expect("required");
945 /// match (name.as_str(), sub_m) {
946 /// ("clone", sub_m) => {}, // clone was used
947 /// ("push", sub_m) => {}, // push was used
948 /// ("commit", sub_m) => {}, // commit was used
949 /// (name, _) => unimplemented!("{name}"),
950 /// }
951 /// ```
952 ///
953 /// Another useful scenario is when you want to support third party, or external, subcommands.
954 /// In these cases you can't know the subcommand name ahead of time, so use a variable instead
955 /// with pattern matching!
956 ///
957 /// ```rust
958 /// # use clap_builder as clap;
959 /// # use std::ffi::OsString;
960 /// # use clap::Command;
961 /// // Assume there is an external subcommand named "subcmd"
962 /// let mut app_m = Command::new("myprog")
963 /// .allow_external_subcommands(true)
964 /// .get_matches_from(vec![
965 /// "myprog", "subcmd", "--option", "value", "-fff", "--flag"
966 /// ]);
967 ///
968 /// // All trailing arguments will be stored under the subcommand's sub-matches using an empty
969 /// // string argument name
970 /// match app_m.remove_subcommand() {
971 /// Some((external, mut sub_m)) => {
972 /// let ext_args: Vec<OsString> = sub_m.remove_many("")
973 /// .expect("`file`is required")
974 /// .collect();
975 /// assert_eq!(external, "subcmd");
976 /// assert_eq!(ext_args, ["--option", "value", "-fff", "--flag"]);
977 /// },
978 /// _ => {},
979 /// }
980 /// ```
981 /// [subcommand]: crate::Command::subcommand
982 pub fn remove_subcommand(&mut self) -> Option<(String, ArgMatches)> {
983 self.subcommand.take().map(|sc| (sc.name, sc.matches))
984 }
985
986 /// The `ArgMatches` for the current [subcommand].
987 ///
988 /// Subcommand values are put in a child [`ArgMatches`]
989 ///
990 /// Returns `None` if the subcommand wasn't present at runtime,
991 ///
992 /// # Panics
993 ///
994 /// If `id` is not a valid subcommand (debug builds).
995 ///
996 /// # Examples
997 ///
998 /// ```rust
999 /// # use clap_builder as clap;
1000 /// # use clap::{Command, Arg, ArgAction};
1001 /// let app_m = Command::new("myprog")
1002 /// .arg(Arg::new("debug")
1003 /// .short('d')
1004 /// .action(ArgAction::SetTrue)
1005 /// )
1006 /// .subcommand(Command::new("test")
1007 /// .arg(Arg::new("opt")
1008 /// .long("option")
1009 /// .action(ArgAction::Set)))
1010 /// .get_matches_from(vec![
1011 /// "myprog", "-d", "test", "--option", "val"
1012 /// ]);
1013 ///
1014 /// // Both parent commands, and child subcommands can have arguments present at the same times
1015 /// assert!(app_m.get_flag("debug"));
1016 ///
1017 /// // Get the subcommand's ArgMatches instance
1018 /// if let Some(sub_m) = app_m.subcommand_matches("test") {
1019 /// // Use the struct like normal
1020 /// assert_eq!(sub_m.get_one::<String>("opt").map(|s| s.as_str()), Some("val"));
1021 /// }
1022 /// ```
1023 ///
1024 /// [subcommand]: crate::Command::subcommand
1025 /// [`Command`]: crate::Command
1026 pub fn subcommand_matches(&self, name: &str) -> Option<&ArgMatches> {
1027 self.get_subcommand(name).map(|sc| &sc.matches)
1028 }
1029
1030 /// The name of the current [subcommand].
1031 ///
1032 /// Returns `None` if the subcommand wasn't present at runtime,
1033 ///
1034 /// # Examples
1035 ///
1036 /// ```no_run
1037 /// # use clap_builder as clap;
1038 /// # use clap::{Command, Arg, };
1039 /// let app_m = Command::new("git")
1040 /// .subcommand(Command::new("clone"))
1041 /// .subcommand(Command::new("push"))
1042 /// .subcommand(Command::new("commit"))
1043 /// .get_matches();
1044 ///
1045 /// match app_m.subcommand_name() {
1046 /// Some("clone") => {}, // clone was used
1047 /// Some("push") => {}, // push was used
1048 /// Some("commit") => {}, // commit was used
1049 /// _ => {}, // Either no subcommand or one not tested for...
1050 /// }
1051 /// ```
1052 /// [subcommand]: crate::Command::subcommand
1053 /// [`Command`]: crate::Command
1054 #[inline]
1055 pub fn subcommand_name(&self) -> Option<&str> {
1056 self.subcommand.as_ref().map(|sc| &*sc.name)
1057 }
1058
1059 /// Check if a subcommand can be queried
1060 ///
1061 /// By default, `ArgMatches` functions assert on undefined `Id`s to help catch programmer
1062 /// mistakes. In some context, this doesn't work, so users can use this function to check
1063 /// before they do a query on `ArgMatches`.
1064 #[inline]
1065 #[doc(hidden)]
1066 pub fn is_valid_subcommand(&self, _name: &str) -> bool {
1067 #[cfg(debug_assertions)]
1068 {
1069 _name.is_empty() || self.valid_subcommands.iter().any(|s| *s == _name)
1070 }
1071 #[cfg(not(debug_assertions))]
1072 {
1073 true
1074 }
1075 }
1076}
1077
1078/// # Advanced
1079impl ArgMatches {
1080 /// Non-panicking version of [`ArgMatches::get_one`]
1081 pub fn try_get_one<T: Any + Clone + Send + Sync + 'static>(
1082 &self,
1083 id: &str,
1084 ) -> Result<Option<&T>, MatchesError> {
1085 let arg = ok!(self.try_get_arg_t::<T>(id));
1086 let value = match arg.and_then(|a| a.first()) {
1087 Some(value) => value,
1088 None => {
1089 return Ok(None);
1090 }
1091 };
1092 Ok(value
1093 .downcast_ref::<T>()
1094 .map(Some)
1095 .expect(INTERNAL_ERROR_MSG)) // enforced by `try_get_arg_t`
1096 }
1097
1098 /// Non-panicking version of [`ArgMatches::get_many`]
1099 pub fn try_get_many<T: Any + Clone + Send + Sync + 'static>(
1100 &self,
1101 id: &str,
1102 ) -> Result<Option<ValuesRef<'_, T>>, MatchesError> {
1103 let arg = match ok!(self.try_get_arg_t::<T>(id)) {
1104 Some(arg) => arg,
1105 None => return Ok(None),
1106 };
1107 let len = arg.num_vals();
1108 let values = arg.vals_flatten();
1109 let values = ValuesRef {
1110 // enforced by `try_get_arg_t`
1111 iter: values.map(unwrap_downcast_ref),
1112 len,
1113 };
1114 Ok(Some(values))
1115 }
1116
1117 /// Non-panicking version of [`ArgMatches::get_occurrences`]
1118 pub fn try_get_occurrences<T: Any + Clone + Send + Sync + 'static>(
1119 &self,
1120 id: &str,
1121 ) -> Result<Option<OccurrencesRef<'_, T>>, MatchesError> {
1122 let arg = match ok!(self.try_get_arg_t::<T>(id)) {
1123 Some(arg) => arg,
1124 None => return Ok(None),
1125 };
1126 let values = arg.vals();
1127 Ok(Some(OccurrencesRef {
1128 iter: values.map(|g| OccurrenceValuesRef {
1129 iter: g.iter().map(unwrap_downcast_ref),
1130 }),
1131 }))
1132 }
1133
1134 /// Non-panicking version of [`ArgMatches::get_raw`]
1135 pub fn try_get_raw(&self, id: &str) -> Result<Option<RawValues<'_>>, MatchesError> {
1136 let arg = match ok!(self.try_get_arg(id)) {
1137 Some(arg) => arg,
1138 None => return Ok(None),
1139 };
1140 let len = arg.num_vals();
1141 let values = arg.raw_vals_flatten();
1142 let values = RawValues {
1143 iter: values.map(OsString::as_os_str),
1144 len,
1145 };
1146 Ok(Some(values))
1147 }
1148
1149 /// Non-panicking version of [`ArgMatches::get_raw_occurrences`]
1150 pub fn try_get_raw_occurrences(
1151 &self,
1152 id: &str,
1153 ) -> Result<Option<RawOccurrences<'_>>, MatchesError> {
1154 let arg = match ok!(self.try_get_arg(id)) {
1155 Some(arg) => arg,
1156 None => return Ok(None),
1157 };
1158 let values = arg.raw_vals();
1159 let occurrences = RawOccurrences {
1160 iter: values.map(|g| RawOccurrenceValues {
1161 iter: g.iter().map(OsString::as_os_str),
1162 }),
1163 };
1164 Ok(Some(occurrences))
1165 }
1166
1167 /// Non-panicking version of [`ArgMatches::remove_one`]
1168 pub fn try_remove_one<T: Any + Clone + Send + Sync + 'static>(
1169 &mut self,
1170 id: &str,
1171 ) -> Result<Option<T>, MatchesError> {
1172 match ok!(self.try_remove_arg_t::<T>(id)) {
1173 Some(values) => Ok(values
1174 .into_vals_flatten()
1175 // enforced by `try_get_arg_t`
1176 .map(unwrap_downcast_into)
1177 .next()),
1178 None => Ok(None),
1179 }
1180 }
1181
1182 /// Non-panicking version of [`ArgMatches::remove_many`]
1183 pub fn try_remove_many<T: Any + Clone + Send + Sync + 'static>(
1184 &mut self,
1185 id: &str,
1186 ) -> Result<Option<Values<T>>, MatchesError> {
1187 let arg = match ok!(self.try_remove_arg_t::<T>(id)) {
1188 Some(arg) => arg,
1189 None => return Ok(None),
1190 };
1191 let len = arg.num_vals();
1192 let values = arg.into_vals_flatten();
1193 let values = Values {
1194 // enforced by `try_get_arg_t`
1195 iter: values.map(unwrap_downcast_into),
1196 len,
1197 };
1198 Ok(Some(values))
1199 }
1200
1201 /// Non-panicking version of [`ArgMatches::remove_occurrences`]
1202 pub fn try_remove_occurrences<T: Any + Clone + Send + Sync + 'static>(
1203 &mut self,
1204 id: &str,
1205 ) -> Result<Option<Occurrences<T>>, MatchesError> {
1206 let arg = match ok!(self.try_remove_arg_t::<T>(id)) {
1207 Some(arg) => arg,
1208 None => return Ok(None),
1209 };
1210 let values = arg.into_vals();
1211 let occurrences = Occurrences {
1212 iter: values.into_iter().map(|g| OccurrenceValues {
1213 iter: g.into_iter().map(unwrap_downcast_into),
1214 }),
1215 };
1216 Ok(Some(occurrences))
1217 }
1218
1219 /// Non-panicking version of [`ArgMatches::contains_id`]
1220 pub fn try_contains_id(&self, id: &str) -> Result<bool, MatchesError> {
1221 ok!(self.verify_arg(id));
1222
1223 let presence = self.args.contains_key(id);
1224 Ok(presence)
1225 }
1226
1227 /// Clears the values for the given `id`
1228 ///
1229 /// Alternative to [`try_remove_*`][ArgMatches::try_remove_one] when the type is not known.
1230 ///
1231 /// Returns `Err([``MatchesError``])` if the given `id` isn't valid for current `ArgMatches` instance.
1232 ///
1233 /// Returns `Ok(true)` if there were any matches with the given `id`, `Ok(false)` otherwise.
1234 pub fn try_clear_id(&mut self, id: &str) -> Result<bool, MatchesError> {
1235 ok!(self.verify_arg(id));
1236 Ok(self.args.remove_entry(id).is_some())
1237 }
1238}
1239
1240// Private methods
1241impl ArgMatches {
1242 #[inline]
1243 fn try_get_arg(&self, arg: &str) -> Result<Option<&MatchedArg>, MatchesError> {
1244 ok!(self.verify_arg(arg));
1245 Ok(self.args.get(arg))
1246 }
1247
1248 #[inline]
1249 fn try_get_arg_t<T: Any + Send + Sync + 'static>(
1250 &self,
1251 arg: &str,
1252 ) -> Result<Option<&MatchedArg>, MatchesError> {
1253 let arg = match ok!(self.try_get_arg(arg)) {
1254 Some(arg) => arg,
1255 None => {
1256 return Ok(None);
1257 }
1258 };
1259 ok!(self.verify_arg_t::<T>(arg));
1260 Ok(Some(arg))
1261 }
1262
1263 #[inline]
1264 fn try_remove_arg_t<T: Any + Send + Sync + 'static>(
1265 &mut self,
1266 arg: &str,
1267 ) -> Result<Option<MatchedArg>, MatchesError> {
1268 ok!(self.verify_arg(arg));
1269 let (id, matched) = match self.args.remove_entry(arg) {
1270 Some((id, matched)) => (id, matched),
1271 None => {
1272 return Ok(None);
1273 }
1274 };
1275
1276 let expected = AnyValueId::of::<T>();
1277 let actual = matched.infer_type_id(expected);
1278 if actual == expected {
1279 Ok(Some(matched))
1280 } else {
1281 self.args.insert(id, matched);
1282 Err(MatchesError::Downcast { actual, expected })
1283 }
1284 }
1285
1286 fn verify_arg_t<T: Any + Send + Sync + 'static>(
1287 &self,
1288 arg: &MatchedArg,
1289 ) -> Result<(), MatchesError> {
1290 let expected = AnyValueId::of::<T>();
1291 let actual = arg.infer_type_id(expected);
1292 if expected == actual {
1293 Ok(())
1294 } else {
1295 Err(MatchesError::Downcast { actual, expected })
1296 }
1297 }
1298
1299 #[inline]
1300 fn verify_arg(&self, _arg: &str) -> Result<(), MatchesError> {
1301 #[cfg(debug_assertions)]
1302 {
1303 if _arg == Id::EXTERNAL || self.valid_args.iter().any(|s| *s == _arg) {
1304 } else {
1305 debug!(
1306 "`{:?}` is not an id of an argument or a group.\n\
1307 Make sure you're using the name of the argument itself \
1308 and not the name of short or long flags.",
1309 _arg
1310 );
1311 return Err(MatchesError::UnknownArgument {});
1312 }
1313 }
1314 Ok(())
1315 }
1316
1317 #[inline]
1318 #[cfg_attr(debug_assertions, track_caller)]
1319 fn get_arg<'s>(&'s self, arg: &str) -> Option<&'s MatchedArg> {
1320 #[cfg(debug_assertions)]
1321 {
1322 if arg == Id::EXTERNAL || self.valid_args.iter().any(|s| *s == arg) {
1323 } else {
1324 panic!(
1325 "`{arg:?}` is not an id of an argument or a group.\n\
1326 Make sure you're using the name of the argument itself \
1327 and not the name of short or long flags."
1328 );
1329 }
1330 }
1331
1332 self.args.get(arg)
1333 }
1334
1335 #[inline]
1336 #[cfg_attr(debug_assertions, track_caller)]
1337 fn get_subcommand(&self, name: &str) -> Option<&SubCommand> {
1338 #[cfg(debug_assertions)]
1339 {
1340 if name.is_empty() || self.valid_subcommands.iter().any(|s| *s == name) {
1341 } else {
1342 panic!("`{name}` is not a name of a subcommand.");
1343 }
1344 }
1345
1346 if let Some(ref sc) = self.subcommand {
1347 if sc.name == name {
1348 return Some(sc);
1349 }
1350 }
1351
1352 None
1353 }
1354}
1355
1356#[derive(Debug, Clone, PartialEq, Eq)]
1357pub(crate) struct SubCommand {
1358 pub(crate) name: String,
1359 pub(crate) matches: ArgMatches,
1360}
1361
1362/// Iterate over [`Arg`][crate::Arg] and [`ArgGroup`][crate::ArgGroup] [`Id`]s via [`ArgMatches::ids`].
1363///
1364/// # Examples
1365///
1366/// ```rust
1367/// # use clap_builder as clap;
1368/// # use clap::{Command, arg, value_parser};
1369///
1370/// let m = Command::new("myprog")
1371/// .arg(arg!(--color <when>)
1372/// .value_parser(["auto", "always", "never"]))
1373/// .arg(arg!(--config <path>)
1374/// .value_parser(value_parser!(std::path::PathBuf)))
1375/// .get_matches_from(["myprog", "--config=config.toml", "--color=auto"]);
1376/// assert_eq!(
1377/// m.ids()
1378/// .map(|id| id.as_str())
1379/// .collect::<Vec<_>>(),
1380/// ["config", "color"]
1381/// );
1382/// ```
1383#[derive(Clone, Debug)]
1384pub struct IdsRef<'a> {
1385 iter: Iter<'a, Id>,
1386}
1387
1388impl<'a> Iterator for IdsRef<'a> {
1389 type Item = &'a Id;
1390
1391 fn next(&mut self) -> Option<&'a Id> {
1392 self.iter.next()
1393 }
1394 fn size_hint(&self) -> (usize, Option<usize>) {
1395 self.iter.size_hint()
1396 }
1397}
1398
1399impl<'a> DoubleEndedIterator for IdsRef<'a> {
1400 fn next_back(&mut self) -> Option<&'a Id> {
1401 self.iter.next_back()
1402 }
1403}
1404
1405impl ExactSizeIterator for IdsRef<'_> {}
1406
1407/// Iterate over multiple values for an argument via [`ArgMatches::remove_many`].
1408///
1409/// # Examples
1410///
1411/// ```rust
1412/// # use clap_builder as clap;
1413/// # use clap::{Command, Arg, ArgAction};
1414/// let mut m = Command::new("myapp")
1415/// .arg(Arg::new("output")
1416/// .short('o')
1417/// .action(ArgAction::Append))
1418/// .get_matches_from(vec!["myapp", "-o", "val1", "-o", "val2"]);
1419///
1420/// let mut values = m.remove_many::<String>("output")
1421/// .unwrap();
1422///
1423/// assert_eq!(values.next(), Some(String::from("val1")));
1424/// assert_eq!(values.next(), Some(String::from("val2")));
1425/// assert_eq!(values.next(), None);
1426/// ```
1427#[derive(Clone, Debug)]
1428pub struct Values<T> {
1429 #[allow(clippy::type_complexity)]
1430 iter: Map<Flatten<std::vec::IntoIter<Vec<AnyValue>>>, fn(AnyValue) -> T>,
1431 len: usize,
1432}
1433
1434impl<T> Iterator for Values<T> {
1435 type Item = T;
1436
1437 fn next(&mut self) -> Option<Self::Item> {
1438 if let Some(next) = self.iter.next() {
1439 self.len -= 1;
1440 Some(next)
1441 } else {
1442 None
1443 }
1444 }
1445 fn size_hint(&self) -> (usize, Option<usize>) {
1446 (self.len, Some(self.len))
1447 }
1448}
1449
1450impl<T> DoubleEndedIterator for Values<T> {
1451 fn next_back(&mut self) -> Option<Self::Item> {
1452 if let Some(next) = self.iter.next_back() {
1453 self.len -= 1;
1454 Some(next)
1455 } else {
1456 None
1457 }
1458 }
1459}
1460
1461impl<T> ExactSizeIterator for Values<T> {}
1462
1463/// Creates an empty iterator.
1464impl<T> Default for Values<T> {
1465 fn default() -> Self {
1466 let empty: Vec<Vec<AnyValue>> = Default::default();
1467 Values {
1468 iter: empty.into_iter().flatten().map(|_| unreachable!()),
1469 len: 0,
1470 }
1471 }
1472}
1473
1474/// Iterate over multiple values for an argument via [`ArgMatches::get_many`].
1475///
1476/// # Examples
1477///
1478/// ```rust
1479/// # use clap_builder as clap;
1480/// # use clap::{Command, Arg, ArgAction};
1481/// let m = Command::new("myapp")
1482/// .arg(Arg::new("output")
1483/// .short('o')
1484/// .action(ArgAction::Append))
1485/// .get_matches_from(vec!["myapp", "-o", "val1", "-o", "val2"]);
1486///
1487/// let mut values = m.get_many::<String>("output")
1488/// .unwrap()
1489/// .map(|s| s.as_str());
1490///
1491/// assert_eq!(values.next(), Some("val1"));
1492/// assert_eq!(values.next(), Some("val2"));
1493/// assert_eq!(values.next(), None);
1494/// ```
1495#[derive(Clone, Debug)]
1496pub struct ValuesRef<'a, T> {
1497 #[allow(clippy::type_complexity)]
1498 iter: Map<Flatten<Iter<'a, Vec<AnyValue>>>, fn(&AnyValue) -> &T>,
1499 len: usize,
1500}
1501
1502impl<'a, T: 'a> Iterator for ValuesRef<'a, T> {
1503 type Item = &'a T;
1504
1505 fn next(&mut self) -> Option<Self::Item> {
1506 if let Some(next) = self.iter.next() {
1507 self.len -= 1;
1508 Some(next)
1509 } else {
1510 None
1511 }
1512 }
1513 fn size_hint(&self) -> (usize, Option<usize>) {
1514 (self.len, Some(self.len))
1515 }
1516}
1517
1518impl<'a, T: 'a> DoubleEndedIterator for ValuesRef<'a, T> {
1519 fn next_back(&mut self) -> Option<Self::Item> {
1520 if let Some(next) = self.iter.next_back() {
1521 self.len -= 1;
1522 Some(next)
1523 } else {
1524 None
1525 }
1526 }
1527}
1528
1529impl<'a, T: 'a> ExactSizeIterator for ValuesRef<'a, T> {}
1530
1531/// Creates an empty iterator.
1532impl<'a, T: 'a> Default for ValuesRef<'a, T> {
1533 fn default() -> Self {
1534 static EMPTY: [Vec<AnyValue>; 0] = [];
1535 ValuesRef {
1536 iter: EMPTY[..].iter().flatten().map(|_| unreachable!()),
1537 len: 0,
1538 }
1539 }
1540}
1541
1542/// Iterate over raw argument values via [`ArgMatches::get_raw`].
1543///
1544/// # Examples
1545///
1546/// ```rust
1547/// # #[cfg(unix)] {
1548/// # use clap_builder as clap;
1549/// # use clap::{Command, arg, value_parser};
1550/// use std::ffi::OsString;
1551/// use std::os::unix::ffi::{OsStrExt,OsStringExt};
1552///
1553/// let m = Command::new("utf8")
1554/// .arg(arg!(<arg> "some arg")
1555/// .value_parser(value_parser!(OsString)))
1556/// .get_matches_from(vec![OsString::from("myprog"),
1557/// // "Hi {0xe9}!"
1558/// OsString::from_vec(vec![b'H', b'i', b' ', 0xe9, b'!'])]);
1559/// assert_eq!(
1560/// &*m.get_raw("arg")
1561/// .unwrap()
1562/// .next().unwrap()
1563/// .as_bytes(),
1564/// [b'H', b'i', b' ', 0xe9, b'!']
1565/// );
1566/// # }
1567/// ```
1568#[derive(Clone, Debug)]
1569pub struct RawValues<'a> {
1570 #[allow(clippy::type_complexity)]
1571 iter: Map<Flatten<Iter<'a, Vec<OsString>>>, fn(&OsString) -> &OsStr>,
1572 len: usize,
1573}
1574
1575impl<'a> Iterator for RawValues<'a> {
1576 type Item = &'a OsStr;
1577
1578 fn next(&mut self) -> Option<&'a OsStr> {
1579 if let Some(next) = self.iter.next() {
1580 self.len -= 1;
1581 Some(next)
1582 } else {
1583 None
1584 }
1585 }
1586 fn size_hint(&self) -> (usize, Option<usize>) {
1587 (self.len, Some(self.len))
1588 }
1589}
1590
1591impl<'a> DoubleEndedIterator for RawValues<'a> {
1592 fn next_back(&mut self) -> Option<&'a OsStr> {
1593 if let Some(next) = self.iter.next_back() {
1594 self.len -= 1;
1595 Some(next)
1596 } else {
1597 None
1598 }
1599 }
1600}
1601
1602impl ExactSizeIterator for RawValues<'_> {}
1603
1604/// Creates an empty iterator.
1605impl Default for RawValues<'_> {
1606 fn default() -> Self {
1607 static EMPTY: [Vec<OsString>; 0] = [];
1608 RawValues {
1609 iter: EMPTY[..].iter().flatten().map(|_| unreachable!()),
1610 len: 0,
1611 }
1612 }
1613}
1614
1615// The following were taken and adapted from vec_map source
1616// repo: https://github.com/contain-rs/vec-map
1617// commit: be5e1fa3c26e351761b33010ddbdaf5f05dbcc33
1618// license: MIT - Copyright (c) 2015 The Rust Project Developers
1619
1620#[derive(Clone, Debug)]
1621pub struct Occurrences<T> {
1622 #[allow(clippy::type_complexity)]
1623 iter: Map<std::vec::IntoIter<Vec<AnyValue>>, fn(Vec<AnyValue>) -> OccurrenceValues<T>>,
1624}
1625
1626impl<T> Iterator for Occurrences<T> {
1627 type Item = OccurrenceValues<T>;
1628
1629 fn next(&mut self) -> Option<Self::Item> {
1630 self.iter.next()
1631 }
1632
1633 fn size_hint(&self) -> (usize, Option<usize>) {
1634 self.iter.size_hint()
1635 }
1636}
1637
1638impl<T> DoubleEndedIterator for Occurrences<T> {
1639 fn next_back(&mut self) -> Option<Self::Item> {
1640 self.iter.next_back()
1641 }
1642}
1643
1644impl<T> ExactSizeIterator for Occurrences<T> {}
1645
1646impl<T> Default for Occurrences<T> {
1647 fn default() -> Self {
1648 let empty: Vec<Vec<AnyValue>> = Default::default();
1649 Occurrences {
1650 iter: empty.into_iter().map(|_| unreachable!()),
1651 }
1652 }
1653}
1654
1655#[derive(Clone, Debug)]
1656pub struct OccurrenceValues<T> {
1657 #[allow(clippy::type_complexity)]
1658 iter: Map<std::vec::IntoIter<AnyValue>, fn(AnyValue) -> T>,
1659}
1660
1661impl<T> Iterator for OccurrenceValues<T> {
1662 type Item = T;
1663
1664 fn next(&mut self) -> Option<Self::Item> {
1665 self.iter.next()
1666 }
1667
1668 fn size_hint(&self) -> (usize, Option<usize>) {
1669 self.iter.size_hint()
1670 }
1671}
1672
1673impl<T> DoubleEndedIterator for OccurrenceValues<T> {
1674 fn next_back(&mut self) -> Option<Self::Item> {
1675 self.iter.next_back()
1676 }
1677}
1678
1679impl<T> ExactSizeIterator for OccurrenceValues<T> {}
1680
1681#[derive(Clone, Debug)]
1682pub struct OccurrencesRef<'a, T> {
1683 #[allow(clippy::type_complexity)]
1684 iter: Map<Iter<'a, Vec<AnyValue>>, fn(&Vec<AnyValue>) -> OccurrenceValuesRef<'_, T>>,
1685}
1686
1687impl<'a, T> Iterator for OccurrencesRef<'a, T>
1688where
1689 Self: 'a,
1690{
1691 type Item = OccurrenceValuesRef<'a, T>;
1692
1693 fn next(&mut self) -> Option<Self::Item> {
1694 self.iter.next()
1695 }
1696
1697 fn size_hint(&self) -> (usize, Option<usize>) {
1698 self.iter.size_hint()
1699 }
1700}
1701
1702impl<'a, T> DoubleEndedIterator for OccurrencesRef<'a, T>
1703where
1704 Self: 'a,
1705{
1706 fn next_back(&mut self) -> Option<Self::Item> {
1707 self.iter.next_back()
1708 }
1709}
1710
1711impl<'a, T> ExactSizeIterator for OccurrencesRef<'a, T> where Self: 'a {}
1712impl<T> Default for OccurrencesRef<'_, T> {
1713 fn default() -> Self {
1714 static EMPTY: [Vec<AnyValue>; 0] = [];
1715 OccurrencesRef {
1716 iter: EMPTY[..].iter().map(|_| unreachable!()),
1717 }
1718 }
1719}
1720
1721#[derive(Clone, Debug)]
1722pub struct OccurrenceValuesRef<'a, T> {
1723 #[allow(clippy::type_complexity)]
1724 iter: Map<Iter<'a, AnyValue>, fn(&AnyValue) -> &T>,
1725}
1726
1727impl<'a, T> Iterator for OccurrenceValuesRef<'a, T>
1728where
1729 Self: 'a,
1730{
1731 type Item = &'a T;
1732
1733 fn next(&mut self) -> Option<Self::Item> {
1734 self.iter.next()
1735 }
1736
1737 fn size_hint(&self) -> (usize, Option<usize>) {
1738 self.iter.size_hint()
1739 }
1740}
1741
1742impl<'a, T> DoubleEndedIterator for OccurrenceValuesRef<'a, T>
1743where
1744 Self: 'a,
1745{
1746 fn next_back(&mut self) -> Option<Self::Item> {
1747 self.iter.next_back()
1748 }
1749}
1750
1751impl<'a, T> ExactSizeIterator for OccurrenceValuesRef<'a, T> where Self: 'a {}
1752
1753#[derive(Clone, Debug)]
1754pub struct RawOccurrences<'a> {
1755 #[allow(clippy::type_complexity)]
1756 iter: Map<Iter<'a, Vec<OsString>>, fn(&Vec<OsString>) -> RawOccurrenceValues<'_>>,
1757}
1758
1759impl<'a> Iterator for RawOccurrences<'a> {
1760 type Item = RawOccurrenceValues<'a>;
1761
1762 fn next(&mut self) -> Option<Self::Item> {
1763 self.iter.next()
1764 }
1765
1766 fn size_hint(&self) -> (usize, Option<usize>) {
1767 self.iter.size_hint()
1768 }
1769}
1770
1771impl DoubleEndedIterator for RawOccurrences<'_> {
1772 fn next_back(&mut self) -> Option<Self::Item> {
1773 self.iter.next_back()
1774 }
1775}
1776
1777impl ExactSizeIterator for RawOccurrences<'_> {}
1778
1779impl Default for RawOccurrences<'_> {
1780 fn default() -> Self {
1781 static EMPTY: [Vec<OsString>; 0] = [];
1782 RawOccurrences {
1783 iter: EMPTY[..].iter().map(|_| unreachable!()),
1784 }
1785 }
1786}
1787
1788#[derive(Clone, Debug)]
1789pub struct RawOccurrenceValues<'a> {
1790 #[allow(clippy::type_complexity)]
1791 iter: Map<Iter<'a, OsString>, fn(&OsString) -> &OsStr>,
1792}
1793
1794impl<'a> Iterator for RawOccurrenceValues<'a>
1795where
1796 Self: 'a,
1797{
1798 type Item = &'a OsStr;
1799
1800 fn next(&mut self) -> Option<Self::Item> {
1801 self.iter.next()
1802 }
1803
1804 fn size_hint(&self) -> (usize, Option<usize>) {
1805 self.iter.size_hint()
1806 }
1807}
1808
1809impl<'a> DoubleEndedIterator for RawOccurrenceValues<'a>
1810where
1811 Self: 'a,
1812{
1813 fn next_back(&mut self) -> Option<Self::Item> {
1814 self.iter.next_back()
1815 }
1816}
1817
1818impl ExactSizeIterator for RawOccurrenceValues<'_> {}
1819
1820/// Iterate over indices for where an argument appeared when parsing, via [`ArgMatches::indices_of`]
1821///
1822/// # Examples
1823///
1824/// ```rust
1825/// # use clap_builder as clap;
1826/// # use clap::{Command, Arg, ArgAction};
1827/// let m = Command::new("myapp")
1828/// .arg(Arg::new("output")
1829/// .short('o')
1830/// .num_args(1..)
1831/// .action(ArgAction::Set))
1832/// .get_matches_from(vec!["myapp", "-o", "val1", "val2"]);
1833///
1834/// let mut indices = m.indices_of("output").unwrap();
1835///
1836/// assert_eq!(indices.next(), Some(2));
1837/// assert_eq!(indices.next(), Some(3));
1838/// assert_eq!(indices.next(), None);
1839/// ```
1840/// [`ArgMatches::indices_of`]: ArgMatches::indices_of()
1841#[derive(Clone, Debug)]
1842pub struct Indices<'a> {
1843 iter: Cloned<Iter<'a, usize>>,
1844 len: usize,
1845}
1846
1847impl Iterator for Indices<'_> {
1848 type Item = usize;
1849
1850 fn next(&mut self) -> Option<usize> {
1851 if let Some(next) = self.iter.next() {
1852 self.len -= 1;
1853 Some(next)
1854 } else {
1855 None
1856 }
1857 }
1858 fn size_hint(&self) -> (usize, Option<usize>) {
1859 (self.len, Some(self.len))
1860 }
1861}
1862
1863impl DoubleEndedIterator for Indices<'_> {
1864 fn next_back(&mut self) -> Option<usize> {
1865 if let Some(next) = self.iter.next_back() {
1866 self.len -= 1;
1867 Some(next)
1868 } else {
1869 None
1870 }
1871 }
1872}
1873
1874impl ExactSizeIterator for Indices<'_> {}
1875
1876/// Creates an empty iterator.
1877impl Default for Indices<'_> {
1878 fn default() -> Self {
1879 static EMPTY: [usize; 0] = [];
1880 // This is never called because the iterator is empty:
1881 Indices {
1882 iter: EMPTY[..].iter().cloned(),
1883 len: 0,
1884 }
1885 }
1886}
1887
1888#[track_caller]
1889fn unwrap_downcast_ref<T: Any + Clone + Send + Sync + 'static>(value: &AnyValue) -> &T {
1890 value.downcast_ref().expect(INTERNAL_ERROR_MSG)
1891}
1892
1893#[track_caller]
1894fn unwrap_downcast_into<T: Any + Clone + Send + Sync + 'static>(value: AnyValue) -> T {
1895 value.downcast_into().expect(INTERNAL_ERROR_MSG)
1896}
1897
1898#[cfg(test)]
1899mod tests {
1900 use super::*;
1901
1902 use crate::ArgAction;
1903
1904 #[test]
1905 fn check_auto_traits() {
1906 static_assertions::assert_impl_all!(ArgMatches: Send, Sync, Unpin);
1907 }
1908
1909 #[test]
1910 fn test_default_raw_values() {
1911 let mut values: RawValues<'_> = Default::default();
1912 assert_eq!(values.next(), None);
1913 }
1914
1915 #[test]
1916 fn test_default_indices() {
1917 let mut indices: Indices<'_> = Indices::default();
1918 assert_eq!(indices.next(), None);
1919 }
1920
1921 #[test]
1922 fn test_default_indices_with_shorter_lifetime() {
1923 let matches = ArgMatches::default();
1924 let mut indices = matches.indices_of("").unwrap_or_default();
1925 assert_eq!(indices.next(), None);
1926 }
1927
1928 #[test]
1929 fn values_exact_size() {
1930 let l = crate::Command::new("test")
1931 .arg(
1932 crate::Arg::new("POTATO")
1933 .action(ArgAction::Set)
1934 .num_args(1..)
1935 .required(true),
1936 )
1937 .try_get_matches_from(["test", "one"])
1938 .unwrap()
1939 .get_many::<String>("POTATO")
1940 .expect("present")
1941 .count();
1942 assert_eq!(l, 1);
1943 }
1944
1945 #[test]
1946 fn os_values_exact_size() {
1947 let l = crate::Command::new("test")
1948 .arg(
1949 crate::Arg::new("POTATO")
1950 .action(ArgAction::Set)
1951 .num_args(1..)
1952 .value_parser(crate::builder::ValueParser::os_string())
1953 .required(true),
1954 )
1955 .try_get_matches_from(["test", "one"])
1956 .unwrap()
1957 .get_many::<OsString>("POTATO")
1958 .expect("present")
1959 .count();
1960 assert_eq!(l, 1);
1961 }
1962
1963 #[test]
1964 fn indices_exact_size() {
1965 let l = crate::Command::new("test")
1966 .arg(
1967 crate::Arg::new("POTATO")
1968 .action(ArgAction::Set)
1969 .num_args(1..)
1970 .required(true),
1971 )
1972 .try_get_matches_from(["test", "one"])
1973 .unwrap()
1974 .indices_of("POTATO")
1975 .expect("present")
1976 .len();
1977 assert_eq!(l, 1);
1978 }
1979
1980 #[test]
1981 fn rev_iter() {
1982 let mut matches = crate::Command::new("myprog")
1983 .arg(crate::Arg::new("a").short('a').action(ArgAction::Append))
1984 .arg(crate::Arg::new("b").short('b').action(ArgAction::Append))
1985 .try_get_matches_from(vec!["myprog", "-a1", "-b1", "-b3"])
1986 .unwrap();
1987
1988 let a_index = matches
1989 .indices_of("a")
1990 .expect("missing aopt indices")
1991 .collect::<Vec<_>>();
1992 dbg!(&a_index);
1993 let a_value = matches
1994 .remove_many::<String>("a")
1995 .expect("missing aopt values");
1996 dbg!(&a_value);
1997 let a = a_index.into_iter().zip(a_value).rev().collect::<Vec<_>>();
1998 dbg!(a);
1999
2000 let b_index = matches
2001 .indices_of("b")
2002 .expect("missing aopt indices")
2003 .collect::<Vec<_>>();
2004 dbg!(&b_index);
2005 let b_value = matches
2006 .remove_many::<String>("b")
2007 .expect("missing aopt values");
2008 dbg!(&b_value);
2009 let b = b_index.into_iter().zip(b_value).rev().collect::<Vec<_>>();
2010 dbg!(b);
2011 }
2012
2013 #[test]
2014 fn delete_id_without_returning() {
2015 let mut matches = crate::Command::new("myprog")
2016 .arg(crate::Arg::new("a").short('a').action(ArgAction::Append))
2017 .arg(crate::Arg::new("b").short('b').action(ArgAction::Append))
2018 .arg(crate::Arg::new("c").short('c').action(ArgAction::Append))
2019 .try_get_matches_from(vec!["myprog", "-b1", "-a1", "-b2"])
2020 .unwrap();
2021 let matches_ids_count = matches.ids().count();
2022 assert_eq!(matches_ids_count, 2);
2023
2024 let _ = matches
2025 .try_clear_id("d")
2026 .expect_err("should fail due to there is no arg 'd'");
2027
2028 let c_was_presented = matches
2029 .try_clear_id("c")
2030 .expect("doesn't fail because there is no matches for 'c' argument");
2031 assert!(!c_was_presented);
2032 let matches_ids_count = matches.ids().count();
2033 assert_eq!(matches_ids_count, 2);
2034
2035 let b_was_presented = matches.try_clear_id("b").unwrap();
2036 assert!(b_was_presented);
2037 let matches_ids_count = matches.ids().count();
2038 assert_eq!(matches_ids_count, 1);
2039
2040 let a_was_presented = matches.try_clear_id("a").unwrap();
2041 assert!(a_was_presented);
2042 let matches_ids_count = matches.ids().count();
2043 assert_eq!(matches_ids_count, 0);
2044 }
2045}