use std::any::Any;
use std::ffi::{OsStr, OsString};
use std::fmt::Debug;
use std::iter::{Cloned, Flatten, Map};
use std::slice::Iter;
#[cfg(debug_assertions)]
use crate::builder::Str;
use crate::parser::MatchedArg;
use crate::parser::MatchesError;
use crate::parser::ValueSource;
use crate::util::AnyValue;
use crate::util::AnyValueId;
use crate::util::FlatMap;
use crate::util::Id;
use crate::INTERNAL_ERROR_MSG;
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct ArgMatches {
#[cfg(debug_assertions)]
pub(crate) valid_args: Vec<Id>,
#[cfg(debug_assertions)]
pub(crate) valid_subcommands: Vec<Str>,
pub(crate) args: FlatMap<Id, MatchedArg>,
pub(crate) subcommand: Option<Box<SubCommand>>,
}
impl ArgMatches {
#[cfg_attr(debug_assertions, track_caller)]
pub fn get_one<T: Any + Clone + Send + Sync + 'static>(&self, id: &str) -> Option<&T> {
MatchesError::unwrap(id, self.try_get_one(id))
}
#[cfg_attr(debug_assertions, track_caller)]
pub fn get_count(&self, id: &str) -> u8 {
*self.get_one::<u8>(id).unwrap_or_else(|| {
panic!("arg `{id}`'s `ArgAction` should be `Count` which should provide a default")
})
}
#[cfg_attr(debug_assertions, track_caller)]
pub fn get_flag(&self, id: &str) -> bool {
*self
.get_one::<bool>(id)
.unwrap_or_else(|| {
panic!(
"arg `{id}`'s `ArgAction` should be one of `SetTrue`, `SetFalse` which should provide a default"
)
})
}
#[cfg_attr(debug_assertions, track_caller)]
pub fn get_many<T: Any + Clone + Send + Sync + 'static>(
&self,
id: &str,
) -> Option<ValuesRef<'_, T>> {
MatchesError::unwrap(id, self.try_get_many(id))
}
#[cfg_attr(debug_assertions, track_caller)]
pub fn get_occurrences<T: Any + Clone + Send + Sync + 'static>(
&self,
id: &str,
) -> Option<OccurrencesRef<'_, T>> {
MatchesError::unwrap(id, self.try_get_occurrences(id))
}
#[cfg_attr(debug_assertions, track_caller)]
pub fn get_raw(&self, id: &str) -> Option<RawValues<'_>> {
MatchesError::unwrap(id, self.try_get_raw(id))
}
#[cfg_attr(debug_assertions, track_caller)]
pub fn get_raw_occurrences(&self, id: &str) -> Option<RawOccurrences<'_>> {
MatchesError::unwrap(id, self.try_get_raw_occurrences(id))
}
#[cfg_attr(debug_assertions, track_caller)]
pub fn remove_one<T: Any + Clone + Send + Sync + 'static>(&mut self, id: &str) -> Option<T> {
MatchesError::unwrap(id, self.try_remove_one(id))
}
#[cfg_attr(debug_assertions, track_caller)]
pub fn remove_many<T: Any + Clone + Send + Sync + 'static>(
&mut self,
id: &str,
) -> Option<Values<T>> {
MatchesError::unwrap(id, self.try_remove_many(id))
}
#[cfg_attr(debug_assertions, track_caller)]
pub fn remove_occurrences<T: Any + Clone + Send + Sync + 'static>(
&mut self,
id: &str,
) -> Option<Occurrences<T>> {
MatchesError::unwrap(id, self.try_remove_occurrences(id))
}
pub fn contains_id(&self, id: &str) -> bool {
MatchesError::unwrap(id, self.try_contains_id(id))
}
pub fn ids(&self) -> IdsRef<'_> {
IdsRef {
iter: self.args.keys(),
}
}
pub fn args_present(&self) -> bool {
self.args
.values()
.any(|v| v.source().map(|s| s.is_explicit()).unwrap_or(false))
}
#[cfg_attr(debug_assertions, track_caller)]
pub fn value_source(&self, id: &str) -> Option<ValueSource> {
let value = self.get_arg(id);
value.and_then(MatchedArg::source)
}
#[cfg_attr(debug_assertions, track_caller)]
pub fn index_of(&self, id: &str) -> Option<usize> {
let arg = some!(self.get_arg(id));
let i = some!(arg.get_index(0));
Some(i)
}
#[cfg_attr(debug_assertions, track_caller)]
pub fn indices_of(&self, id: &str) -> Option<Indices<'_>> {
let arg = some!(self.get_arg(id));
let i = Indices {
iter: arg.indices(),
len: arg.num_vals(),
};
Some(i)
}
}
impl ArgMatches {
#[inline]
pub fn subcommand(&self) -> Option<(&str, &ArgMatches)> {
self.subcommand.as_ref().map(|sc| (&*sc.name, &sc.matches))
}
pub fn remove_subcommand(&mut self) -> Option<(String, ArgMatches)> {
self.subcommand.take().map(|sc| (sc.name, sc.matches))
}
pub fn subcommand_matches(&self, name: &str) -> Option<&ArgMatches> {
self.get_subcommand(name).map(|sc| &sc.matches)
}
#[inline]
pub fn subcommand_name(&self) -> Option<&str> {
self.subcommand.as_ref().map(|sc| &*sc.name)
}
#[inline]
#[doc(hidden)]
pub fn is_valid_subcommand(&self, _name: &str) -> bool {
#[cfg(debug_assertions)]
{
_name.is_empty() || self.valid_subcommands.iter().any(|s| *s == _name)
}
#[cfg(not(debug_assertions))]
{
true
}
}
}
impl ArgMatches {
pub fn try_get_one<T: Any + Clone + Send + Sync + 'static>(
&self,
id: &str,
) -> Result<Option<&T>, MatchesError> {
let arg = ok!(self.try_get_arg_t::<T>(id));
let value = match arg.and_then(|a| a.first()) {
Some(value) => value,
None => {
return Ok(None);
}
};
Ok(value
.downcast_ref::<T>()
.map(Some)
.expect(INTERNAL_ERROR_MSG)) }
pub fn try_get_many<T: Any + Clone + Send + Sync + 'static>(
&self,
id: &str,
) -> Result<Option<ValuesRef<'_, T>>, MatchesError> {
let arg = match ok!(self.try_get_arg_t::<T>(id)) {
Some(arg) => arg,
None => return Ok(None),
};
let len = arg.num_vals();
let values = arg.vals_flatten();
let values = ValuesRef {
iter: values.map(unwrap_downcast_ref),
len,
};
Ok(Some(values))
}
pub fn try_get_occurrences<T: Any + Clone + Send + Sync + 'static>(
&self,
id: &str,
) -> Result<Option<OccurrencesRef<'_, T>>, MatchesError> {
let arg = match ok!(self.try_get_arg_t::<T>(id)) {
Some(arg) => arg,
None => return Ok(None),
};
let values = arg.vals();
Ok(Some(OccurrencesRef {
iter: values.map(|g| OccurrenceValuesRef {
iter: g.iter().map(unwrap_downcast_ref),
}),
}))
}
pub fn try_get_raw(&self, id: &str) -> Result<Option<RawValues<'_>>, MatchesError> {
let arg = match ok!(self.try_get_arg(id)) {
Some(arg) => arg,
None => return Ok(None),
};
let len = arg.num_vals();
let values = arg.raw_vals_flatten();
let values = RawValues {
iter: values.map(OsString::as_os_str),
len,
};
Ok(Some(values))
}
pub fn try_get_raw_occurrences(
&self,
id: &str,
) -> Result<Option<RawOccurrences<'_>>, MatchesError> {
let arg = match ok!(self.try_get_arg(id)) {
Some(arg) => arg,
None => return Ok(None),
};
let values = arg.raw_vals();
let occurrences = RawOccurrences {
iter: values.map(|g| RawOccurrenceValues {
iter: g.iter().map(OsString::as_os_str),
}),
};
Ok(Some(occurrences))
}
pub fn try_remove_one<T: Any + Clone + Send + Sync + 'static>(
&mut self,
id: &str,
) -> Result<Option<T>, MatchesError> {
match ok!(self.try_remove_arg_t::<T>(id)) {
Some(values) => Ok(values
.into_vals_flatten()
.map(unwrap_downcast_into)
.next()),
None => Ok(None),
}
}
pub fn try_remove_many<T: Any + Clone + Send + Sync + 'static>(
&mut self,
id: &str,
) -> Result<Option<Values<T>>, MatchesError> {
let arg = match ok!(self.try_remove_arg_t::<T>(id)) {
Some(arg) => arg,
None => return Ok(None),
};
let len = arg.num_vals();
let values = arg.into_vals_flatten();
let values = Values {
iter: values.map(unwrap_downcast_into),
len,
};
Ok(Some(values))
}
pub fn try_remove_occurrences<T: Any + Clone + Send + Sync + 'static>(
&mut self,
id: &str,
) -> Result<Option<Occurrences<T>>, MatchesError> {
let arg = match ok!(self.try_remove_arg_t::<T>(id)) {
Some(arg) => arg,
None => return Ok(None),
};
let values = arg.into_vals();
let occurrences = Occurrences {
iter: values.into_iter().map(|g| OccurrenceValues {
iter: g.into_iter().map(unwrap_downcast_into),
}),
};
Ok(Some(occurrences))
}
pub fn try_contains_id(&self, id: &str) -> Result<bool, MatchesError> {
ok!(self.verify_arg(id));
let presence = self.args.contains_key(id);
Ok(presence)
}
pub fn try_clear_id(&mut self, id: &str) -> Result<bool, MatchesError> {
ok!(self.verify_arg(id));
Ok(self.args.remove_entry(id).is_some())
}
}
impl ArgMatches {
#[inline]
fn try_get_arg(&self, arg: &str) -> Result<Option<&MatchedArg>, MatchesError> {
ok!(self.verify_arg(arg));
Ok(self.args.get(arg))
}
#[inline]
fn try_get_arg_t<T: Any + Send + Sync + 'static>(
&self,
arg: &str,
) -> Result<Option<&MatchedArg>, MatchesError> {
let arg = match ok!(self.try_get_arg(arg)) {
Some(arg) => arg,
None => {
return Ok(None);
}
};
ok!(self.verify_arg_t::<T>(arg));
Ok(Some(arg))
}
#[inline]
fn try_remove_arg_t<T: Any + Send + Sync + 'static>(
&mut self,
arg: &str,
) -> Result<Option<MatchedArg>, MatchesError> {
ok!(self.verify_arg(arg));
let (id, matched) = match self.args.remove_entry(arg) {
Some((id, matched)) => (id, matched),
None => {
return Ok(None);
}
};
let expected = AnyValueId::of::<T>();
let actual = matched.infer_type_id(expected);
if actual == expected {
Ok(Some(matched))
} else {
self.args.insert(id, matched);
Err(MatchesError::Downcast { actual, expected })
}
}
fn verify_arg_t<T: Any + Send + Sync + 'static>(
&self,
arg: &MatchedArg,
) -> Result<(), MatchesError> {
let expected = AnyValueId::of::<T>();
let actual = arg.infer_type_id(expected);
if expected == actual {
Ok(())
} else {
Err(MatchesError::Downcast { actual, expected })
}
}
#[inline]
fn verify_arg(&self, _arg: &str) -> Result<(), MatchesError> {
#[cfg(debug_assertions)]
{
if _arg == Id::EXTERNAL || self.valid_args.iter().any(|s| *s == _arg) {
} else {
debug!(
"`{:?}` is not an id of an argument or a group.\n\
Make sure you're using the name of the argument itself \
and not the name of short or long flags.",
_arg
);
return Err(MatchesError::UnknownArgument {});
}
}
Ok(())
}
#[inline]
#[cfg_attr(debug_assertions, track_caller)]
fn get_arg<'s>(&'s self, arg: &str) -> Option<&'s MatchedArg> {
#[cfg(debug_assertions)]
{
if arg == Id::EXTERNAL || self.valid_args.iter().any(|s| *s == arg) {
} else {
panic!(
"`{arg:?}` is not an id of an argument or a group.\n\
Make sure you're using the name of the argument itself \
and not the name of short or long flags."
);
}
}
self.args.get(arg)
}
#[inline]
#[cfg_attr(debug_assertions, track_caller)]
fn get_subcommand(&self, name: &str) -> Option<&SubCommand> {
#[cfg(debug_assertions)]
{
if name.is_empty() || self.valid_subcommands.iter().any(|s| *s == name) {
} else {
panic!("`{name}` is not a name of a subcommand.");
}
}
if let Some(ref sc) = self.subcommand {
if sc.name == name {
return Some(sc);
}
}
None
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct SubCommand {
pub(crate) name: String,
pub(crate) matches: ArgMatches,
}
#[derive(Clone, Debug)]
pub struct IdsRef<'a> {
iter: Iter<'a, Id>,
}
impl<'a> Iterator for IdsRef<'a> {
type Item = &'a Id;
fn next(&mut self) -> Option<&'a Id> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<'a> DoubleEndedIterator for IdsRef<'a> {
fn next_back(&mut self) -> Option<&'a Id> {
self.iter.next_back()
}
}
impl ExactSizeIterator for IdsRef<'_> {}
#[derive(Clone, Debug)]
pub struct Values<T> {
#[allow(clippy::type_complexity)]
iter: Map<Flatten<std::vec::IntoIter<Vec<AnyValue>>>, fn(AnyValue) -> T>,
len: usize,
}
impl<T> Iterator for Values<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if let Some(next) = self.iter.next() {
self.len -= 1;
Some(next)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
}
impl<T> DoubleEndedIterator for Values<T> {
fn next_back(&mut self) -> Option<Self::Item> {
if let Some(next) = self.iter.next_back() {
self.len -= 1;
Some(next)
} else {
None
}
}
}
impl<T> ExactSizeIterator for Values<T> {}
impl<T> Default for Values<T> {
fn default() -> Self {
let empty: Vec<Vec<AnyValue>> = Default::default();
Values {
iter: empty.into_iter().flatten().map(|_| unreachable!()),
len: 0,
}
}
}
#[derive(Clone, Debug)]
pub struct ValuesRef<'a, T> {
#[allow(clippy::type_complexity)]
iter: Map<Flatten<Iter<'a, Vec<AnyValue>>>, fn(&AnyValue) -> &T>,
len: usize,
}
impl<'a, T: 'a> Iterator for ValuesRef<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
if let Some(next) = self.iter.next() {
self.len -= 1;
Some(next)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
}
impl<'a, T: 'a> DoubleEndedIterator for ValuesRef<'a, T> {
fn next_back(&mut self) -> Option<Self::Item> {
if let Some(next) = self.iter.next_back() {
self.len -= 1;
Some(next)
} else {
None
}
}
}
impl<'a, T: 'a> ExactSizeIterator for ValuesRef<'a, T> {}
impl<'a, T: 'a> Default for ValuesRef<'a, T> {
fn default() -> Self {
static EMPTY: [Vec<AnyValue>; 0] = [];
ValuesRef {
iter: EMPTY[..].iter().flatten().map(|_| unreachable!()),
len: 0,
}
}
}
#[derive(Clone, Debug)]
pub struct RawValues<'a> {
#[allow(clippy::type_complexity)]
iter: Map<Flatten<Iter<'a, Vec<OsString>>>, fn(&OsString) -> &OsStr>,
len: usize,
}
impl<'a> Iterator for RawValues<'a> {
type Item = &'a OsStr;
fn next(&mut self) -> Option<&'a OsStr> {
if let Some(next) = self.iter.next() {
self.len -= 1;
Some(next)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
}
impl<'a> DoubleEndedIterator for RawValues<'a> {
fn next_back(&mut self) -> Option<&'a OsStr> {
if let Some(next) = self.iter.next_back() {
self.len -= 1;
Some(next)
} else {
None
}
}
}
impl ExactSizeIterator for RawValues<'_> {}
impl Default for RawValues<'_> {
fn default() -> Self {
static EMPTY: [Vec<OsString>; 0] = [];
RawValues {
iter: EMPTY[..].iter().flatten().map(|_| unreachable!()),
len: 0,
}
}
}
#[derive(Clone, Debug)]
pub struct Occurrences<T> {
#[allow(clippy::type_complexity)]
iter: Map<std::vec::IntoIter<Vec<AnyValue>>, fn(Vec<AnyValue>) -> OccurrenceValues<T>>,
}
impl<T> Iterator for Occurrences<T> {
type Item = OccurrenceValues<T>;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<T> DoubleEndedIterator for Occurrences<T> {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back()
}
}
impl<T> ExactSizeIterator for Occurrences<T> {}
impl<T> Default for Occurrences<T> {
fn default() -> Self {
let empty: Vec<Vec<AnyValue>> = Default::default();
Occurrences {
iter: empty.into_iter().map(|_| unreachable!()),
}
}
}
#[derive(Clone, Debug)]
pub struct OccurrenceValues<T> {
#[allow(clippy::type_complexity)]
iter: Map<std::vec::IntoIter<AnyValue>, fn(AnyValue) -> T>,
}
impl<T> Iterator for OccurrenceValues<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<T> DoubleEndedIterator for OccurrenceValues<T> {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back()
}
}
impl<T> ExactSizeIterator for OccurrenceValues<T> {}
#[derive(Clone, Debug)]
pub struct OccurrencesRef<'a, T> {
#[allow(clippy::type_complexity)]
iter: Map<Iter<'a, Vec<AnyValue>>, fn(&Vec<AnyValue>) -> OccurrenceValuesRef<'_, T>>,
}
impl<'a, T> Iterator for OccurrencesRef<'a, T>
where
Self: 'a,
{
type Item = OccurrenceValuesRef<'a, T>;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<'a, T> DoubleEndedIterator for OccurrencesRef<'a, T>
where
Self: 'a,
{
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back()
}
}
impl<'a, T> ExactSizeIterator for OccurrencesRef<'a, T> where Self: 'a {}
impl<T> Default for OccurrencesRef<'_, T> {
fn default() -> Self {
static EMPTY: [Vec<AnyValue>; 0] = [];
OccurrencesRef {
iter: EMPTY[..].iter().map(|_| unreachable!()),
}
}
}
#[derive(Clone, Debug)]
pub struct OccurrenceValuesRef<'a, T> {
#[allow(clippy::type_complexity)]
iter: Map<Iter<'a, AnyValue>, fn(&AnyValue) -> &T>,
}
impl<'a, T> Iterator for OccurrenceValuesRef<'a, T>
where
Self: 'a,
{
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<'a, T> DoubleEndedIterator for OccurrenceValuesRef<'a, T>
where
Self: 'a,
{
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back()
}
}
impl<'a, T> ExactSizeIterator for OccurrenceValuesRef<'a, T> where Self: 'a {}
#[derive(Clone, Debug)]
pub struct RawOccurrences<'a> {
#[allow(clippy::type_complexity)]
iter: Map<Iter<'a, Vec<OsString>>, fn(&Vec<OsString>) -> RawOccurrenceValues<'_>>,
}
impl<'a> Iterator for RawOccurrences<'a> {
type Item = RawOccurrenceValues<'a>;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl DoubleEndedIterator for RawOccurrences<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back()
}
}
impl ExactSizeIterator for RawOccurrences<'_> {}
impl Default for RawOccurrences<'_> {
fn default() -> Self {
static EMPTY: [Vec<OsString>; 0] = [];
RawOccurrences {
iter: EMPTY[..].iter().map(|_| unreachable!()),
}
}
}
#[derive(Clone, Debug)]
pub struct RawOccurrenceValues<'a> {
#[allow(clippy::type_complexity)]
iter: Map<Iter<'a, OsString>, fn(&OsString) -> &OsStr>,
}
impl<'a> Iterator for RawOccurrenceValues<'a>
where
Self: 'a,
{
type Item = &'a OsStr;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<'a> DoubleEndedIterator for RawOccurrenceValues<'a>
where
Self: 'a,
{
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back()
}
}
impl ExactSizeIterator for RawOccurrenceValues<'_> {}
#[derive(Clone, Debug)]
pub struct Indices<'a> {
iter: Cloned<Iter<'a, usize>>,
len: usize,
}
impl Iterator for Indices<'_> {
type Item = usize;
fn next(&mut self) -> Option<usize> {
if let Some(next) = self.iter.next() {
self.len -= 1;
Some(next)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
}
impl DoubleEndedIterator for Indices<'_> {
fn next_back(&mut self) -> Option<usize> {
if let Some(next) = self.iter.next_back() {
self.len -= 1;
Some(next)
} else {
None
}
}
}
impl ExactSizeIterator for Indices<'_> {}
impl Default for Indices<'_> {
fn default() -> Self {
static EMPTY: [usize; 0] = [];
Indices {
iter: EMPTY[..].iter().cloned(),
len: 0,
}
}
}
#[track_caller]
fn unwrap_downcast_ref<T: Any + Clone + Send + Sync + 'static>(value: &AnyValue) -> &T {
value.downcast_ref().expect(INTERNAL_ERROR_MSG)
}
#[track_caller]
fn unwrap_downcast_into<T: Any + Clone + Send + Sync + 'static>(value: AnyValue) -> T {
value.downcast_into().expect(INTERNAL_ERROR_MSG)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ArgAction;
#[test]
fn check_auto_traits() {
static_assertions::assert_impl_all!(ArgMatches: Send, Sync, Unpin);
}
#[test]
fn test_default_raw_values() {
let mut values: RawValues<'_> = Default::default();
assert_eq!(values.next(), None);
}
#[test]
fn test_default_indices() {
let mut indices: Indices<'_> = Indices::default();
assert_eq!(indices.next(), None);
}
#[test]
fn test_default_indices_with_shorter_lifetime() {
let matches = ArgMatches::default();
let mut indices = matches.indices_of("").unwrap_or_default();
assert_eq!(indices.next(), None);
}
#[test]
fn values_exact_size() {
let l = crate::Command::new("test")
.arg(
crate::Arg::new("POTATO")
.action(ArgAction::Set)
.num_args(1..)
.required(true),
)
.try_get_matches_from(["test", "one"])
.unwrap()
.get_many::<String>("POTATO")
.expect("present")
.count();
assert_eq!(l, 1);
}
#[test]
fn os_values_exact_size() {
let l = crate::Command::new("test")
.arg(
crate::Arg::new("POTATO")
.action(ArgAction::Set)
.num_args(1..)
.value_parser(crate::builder::ValueParser::os_string())
.required(true),
)
.try_get_matches_from(["test", "one"])
.unwrap()
.get_many::<OsString>("POTATO")
.expect("present")
.count();
assert_eq!(l, 1);
}
#[test]
fn indices_exact_size() {
let l = crate::Command::new("test")
.arg(
crate::Arg::new("POTATO")
.action(ArgAction::Set)
.num_args(1..)
.required(true),
)
.try_get_matches_from(["test", "one"])
.unwrap()
.indices_of("POTATO")
.expect("present")
.len();
assert_eq!(l, 1);
}
#[test]
fn rev_iter() {
let mut matches = crate::Command::new("myprog")
.arg(crate::Arg::new("a").short('a').action(ArgAction::Append))
.arg(crate::Arg::new("b").short('b').action(ArgAction::Append))
.try_get_matches_from(vec!["myprog", "-a1", "-b1", "-b3"])
.unwrap();
let a_index = matches
.indices_of("a")
.expect("missing aopt indices")
.collect::<Vec<_>>();
dbg!(&a_index);
let a_value = matches
.remove_many::<String>("a")
.expect("missing aopt values");
dbg!(&a_value);
let a = a_index.into_iter().zip(a_value).rev().collect::<Vec<_>>();
dbg!(a);
let b_index = matches
.indices_of("b")
.expect("missing aopt indices")
.collect::<Vec<_>>();
dbg!(&b_index);
let b_value = matches
.remove_many::<String>("b")
.expect("missing aopt values");
dbg!(&b_value);
let b = b_index.into_iter().zip(b_value).rev().collect::<Vec<_>>();
dbg!(b);
}
#[test]
fn delete_id_without_returning() {
let mut matches = crate::Command::new("myprog")
.arg(crate::Arg::new("a").short('a').action(ArgAction::Append))
.arg(crate::Arg::new("b").short('b').action(ArgAction::Append))
.arg(crate::Arg::new("c").short('c').action(ArgAction::Append))
.try_get_matches_from(vec!["myprog", "-b1", "-a1", "-b2"])
.unwrap();
let matches_ids_count = matches.ids().count();
assert_eq!(matches_ids_count, 2);
let _ = matches
.try_clear_id("d")
.expect_err("should fail due to there is no arg 'd'");
let c_was_presented = matches
.try_clear_id("c")
.expect("doesn't fail because there is no matches for 'c' argument");
assert!(!c_was_presented);
let matches_ids_count = matches.ids().count();
assert_eq!(matches_ids_count, 2);
let b_was_presented = matches.try_clear_id("b").unwrap();
assert!(b_was_presented);
let matches_ids_count = matches.ids().count();
assert_eq!(matches_ids_count, 1);
let a_was_presented = matches.try_clear_id("a").unwrap();
assert!(a_was_presented);
let matches_ids_count = matches.ids().count();
assert_eq!(matches_ids_count, 0);
}
}