use std::any::Any;
use std::borrow::Cow;
use std::ffi::{OsStr, OsString};
use std::fmt::{Debug, Display};
use std::iter::{Cloned, Flatten, Map};
use std::slice::Iter;
use std::str::FromStr;
use indexmap::IndexMap;
use crate::parser::AnyValue;
use crate::parser::AnyValueId;
use crate::parser::MatchedArg;
use crate::parser::MatchesError;
use crate::parser::ValueSource;
use crate::util::{Id, Key};
use crate::Error;
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<Id>,
#[cfg(debug_assertions)]
pub(crate) disable_asserts: bool,
pub(crate) args: IndexMap<Id, MatchedArg>,
pub(crate) subcommand: Option<Box<SubCommand>>,
}
impl ArgMatches {
#[track_caller]
pub fn get_one<T: Any + Clone + Send + Sync + 'static>(&self, id: &str) -> Option<&T> {
let internal_id = Id::from(id);
MatchesError::unwrap(&internal_id, self.try_get_one(id))
}
#[track_caller]
pub fn get_count(&self, id: &str) -> u8 {
*self
.get_one::<u8>(id)
.expect("ArgAction::Count is defaulted")
}
#[track_caller]
pub fn get_flag(&self, id: &str) -> bool {
*self
.get_one::<bool>(id)
.expect("ArgAction::SetTrue / ArgAction::SetFalse is defaulted")
}
#[track_caller]
pub fn get_many<T: Any + Clone + Send + Sync + 'static>(
&self,
id: &str,
) -> Option<ValuesRef<T>> {
let internal_id = Id::from(id);
MatchesError::unwrap(&internal_id, self.try_get_many(id))
}
#[cfg_attr(not(unix), doc = " ```ignore")]
#[cfg_attr(unix, doc = " ```")]
#[track_caller]
pub fn get_raw(&self, id: &str) -> Option<RawValues<'_>> {
let internal_id = Id::from(id);
MatchesError::unwrap(&internal_id, self.try_get_raw(id))
}
#[track_caller]
pub fn remove_one<T: Any + Clone + Send + Sync + 'static>(&mut self, id: &str) -> Option<T> {
let internal_id = Id::from(id);
MatchesError::unwrap(&internal_id, self.try_remove_one(id))
}
#[track_caller]
pub fn remove_many<T: Any + Clone + Send + Sync + 'static>(
&mut self,
id: &str,
) -> Option<Values2<T>> {
let internal_id = Id::from(id);
MatchesError::unwrap(&internal_id, self.try_remove_many(id))
}
pub fn contains_id(&self, id: &str) -> bool {
let internal_id = Id::from(id);
MatchesError::unwrap(&internal_id, self.try_contains_id(id))
}
pub fn args_present(&self) -> bool {
!self.args.is_empty()
}
#[cfg_attr(
feature = "deprecated",
deprecated(
since = "3.2.0",
note = "Replaced with `ArgMatches::get_one()`
Replace `m.value_of(...)` with `m.get_one::<String>(...).map(|s| s.as_str())`
"
)
)]
#[cfg_attr(debug_assertions, track_caller)]
pub fn value_of<T: Key>(&self, id: T) -> Option<&str> {
let id = Id::from(id);
let arg = self.get_arg(&id)?;
let v = unwrap_string_arg(&id, arg.first()?);
Some(v)
}
#[cfg_attr(
feature = "deprecated",
deprecated(
since = "3.2.0",
note = "Replaced with `ArgMatches::get_one()`
Replace `m.value_of(...)` with `m.get_one::<String>(...).map(|s| s.as_str())`
"
)
)]
#[cfg_attr(debug_assertions, track_caller)]
pub fn value_of_lossy<T: Key>(&self, id: T) -> Option<Cow<'_, str>> {
let id = Id::from(id);
let arg = self.get_arg(&id)?;
let v = unwrap_os_string_arg(&id, arg.first()?);
Some(v.to_string_lossy())
}
#[cfg_attr(
feature = "deprecated",
deprecated(
since = "3.2.0",
note = "Replaced with `ArgMatches::get_one()`
Replace `m.value_of(...)` with `m.get_one::<OsString>(...).map(|s| s.as_os_str())`
"
)
)]
#[cfg_attr(debug_assertions, track_caller)]
pub fn value_of_os<T: Key>(&self, id: T) -> Option<&OsStr> {
let id = Id::from(id);
let arg = self.get_arg(&id)?;
let v = unwrap_os_string_arg(&id, arg.first()?);
Some(v)
}
#[cfg_attr(
feature = "deprecated",
deprecated(
since = "3.2.0",
note = "Replaced with `ArgMatches::get_many()`
"
)
)]
#[cfg_attr(debug_assertions, track_caller)]
pub fn values_of<T: Key>(&self, id: T) -> Option<Values> {
#![allow(deprecated)]
let id = Id::from(id);
let arg = self.get_arg(&id)?;
let v = Values {
iter: arg.vals_flatten().map(unwrap_string),
len: arg.num_vals(),
};
Some(v)
}
#[cfg(feature = "unstable-grouped")]
#[cfg_attr(debug_assertions, track_caller)]
pub fn grouped_values_of<T: Key>(&self, id: T) -> Option<GroupedValues> {
let id = Id::from(id);
let arg = self.get_arg(&id)?;
let v = GroupedValues {
iter: arg.vals().map(|g| g.iter().map(unwrap_string).collect()),
len: arg.vals().len(),
};
Some(v)
}
#[cfg_attr(
feature = "deprecated",
deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::get_many()`")
)]
#[cfg_attr(debug_assertions, track_caller)]
pub fn values_of_lossy<T: Key>(&self, id: T) -> Option<Vec<String>> {
let id = Id::from(id);
let arg = self.get_arg(&id)?;
let v = arg
.vals_flatten()
.map(|v| unwrap_os_string_arg(&id, v).to_string_lossy().into_owned())
.collect();
Some(v)
}
#[cfg_attr(
feature = "deprecated",
deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::get_many()`")
)]
#[cfg_attr(debug_assertions, track_caller)]
pub fn values_of_os<T: Key>(&self, id: T) -> Option<OsValues> {
#![allow(deprecated)]
let id = Id::from(id);
let arg = self.get_arg(&id)?;
let v = OsValues {
iter: arg.vals_flatten().map(unwrap_os_string),
len: arg.num_vals(),
};
Some(v)
}
#[cfg_attr(
feature = "deprecated",
deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::get_one()`")
)]
#[cfg_attr(debug_assertions, track_caller)]
pub fn value_of_t<R>(&self, name: &str) -> Result<R, Error>
where
R: FromStr,
<R as FromStr>::Err: Display,
{
#![allow(deprecated)]
let v = self
.value_of(name)
.ok_or_else(|| Error::argument_not_found_auto(name.to_string()))?;
v.parse::<R>().map_err(|e| {
let message = format!(
"The argument '{}' isn't a valid value for '{}': {}",
v, name, e
);
Error::value_validation(name.to_string(), v.to_string(), message.into())
})
}
#[cfg_attr(
feature = "deprecated",
deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::get_one()`")
)]
#[cfg_attr(debug_assertions, track_caller)]
pub fn value_of_t_or_exit<R>(&self, name: &str) -> R
where
R: FromStr,
<R as FromStr>::Err: Display,
{
#![allow(deprecated)]
self.value_of_t(name).unwrap_or_else(|e| e.exit())
}
#[cfg_attr(
feature = "deprecated",
deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::get_many()`")
)]
#[cfg_attr(debug_assertions, track_caller)]
pub fn values_of_t<R>(&self, name: &str) -> Result<Vec<R>, Error>
where
R: FromStr,
<R as FromStr>::Err: Display,
{
#![allow(deprecated)]
let v = self
.values_of(name)
.ok_or_else(|| Error::argument_not_found_auto(name.to_string()))?;
v.map(|v| {
v.parse::<R>().map_err(|e| {
let message = format!("The argument '{}' isn't a valid value: {}", v, e);
Error::value_validation(name.to_string(), v.to_string(), message.into())
})
})
.collect()
}
#[cfg_attr(
feature = "deprecated",
deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::get_many()`")
)]
#[cfg_attr(debug_assertions, track_caller)]
pub fn values_of_t_or_exit<R>(&self, name: &str) -> Vec<R>
where
R: FromStr,
<R as FromStr>::Err: Display,
{
#![allow(deprecated)]
self.values_of_t(name).unwrap_or_else(|e| e.exit())
}
#[cfg_attr(
feature = "deprecated",
deprecated(
since = "3.2.0",
note = "Replaced with either `ArgAction::SetTrue` or `ArgMatches::contains_id(...)` to avoid confusion over new semantics
With `ArgAction::SetTrue` becoming the new flag default in clap v4, flags will always be present.
To make the migration easier, we've renamed this function so people can identify when they actually
care about an arg being present or if they need to update to the new way to check a flag's
presence.
For flags, call `arg.action(ArgAction::SetTrue)` and lookup the value with `matches.get_flag(...)`
For presence, replace `matches.is_present(...)` with `matches.contains_id(...)`
"
)
)]
#[cfg_attr(debug_assertions, track_caller)]
pub fn is_present<T: Key>(&self, id: T) -> bool {
let id = Id::from(id);
#[cfg(debug_assertions)]
self.get_arg(&id);
self.args.contains_key(&id)
}
#[cfg_attr(debug_assertions, track_caller)]
pub fn value_source<T: Key>(&self, id: T) -> Option<ValueSource> {
let id = Id::from(id);
let value = self.get_arg(&id);
value.and_then(MatchedArg::source)
}
#[cfg_attr(
feature = "deprecated",
deprecated(
since = "3.2.0",
note = "Replaced with either `ArgAction::Count`, `ArgMatches::get_many(...).len()`, or `ArgMatches::value_source`
`occurrences_of`s meaning was overloaded and we are replacing it with more direct approaches.
For counting flags, call `arg.action(ArgAction::Count)` and lookup the value with `matches.get_count(...)`
To check if a user explicitly passed in a value, check the source with `matches.value_source(...)`
To see how many values there are, call `matches.get_many::<T>(...).map(|v| v.len())`
"
)
)]
#[cfg_attr(debug_assertions, track_caller)]
pub fn occurrences_of<T: Key>(&self, id: T) -> u64 {
#![allow(deprecated)]
self.get_arg(&Id::from(id))
.map_or(0, |a| a.get_occurrences())
}
#[cfg_attr(debug_assertions, track_caller)]
pub fn index_of<T: Key>(&self, id: T) -> Option<usize> {
let arg = self.get_arg(&Id::from(id))?;
let i = arg.get_index(0)?;
Some(i)
}
#[cfg_attr(debug_assertions, track_caller)]
pub fn indices_of<T: Key>(&self, id: T) -> Option<Indices<'_>> {
let arg = self.get_arg(&Id::from(id))?;
let i = Indices {
iter: arg.indices(),
len: arg.num_vals(),
};
Some(i)
}
#[inline]
#[doc(hidden)]
#[cfg_attr(
feature = "deprecated",
deprecated(
since = "3.2.0",
note = "Replaced with `ArgMatches::try_get_one()`
When helping to catch mistyped argument IDs, we overlooked the use cases for more dynamic lookups
of arguments, so we added `is_valid_arg` as a short-term hack. Since then, we've generalized
`value_of` as `try_get_one` to give callers all the relevant information they need.
So replace
```
if matches.is_valid_arg(...) {
matches.value_of(...)
}
```
with
```
if let Ok(value) = matches.try_get_one::<T>(...) {
}
```
"
)
)]
pub fn is_valid_arg(&self, _id: impl Key) -> bool {
#[cfg(debug_assertions)]
{
let id = Id::from(_id);
self.disable_asserts || id == Id::empty_hash() || self.valid_args.contains(&id)
}
#[cfg(not(debug_assertions))]
{
true
}
}
}
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<T: Key>(&self, id: T) -> Option<&ArgMatches> {
self.get_subcommand(&id.into()).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, _id: impl Key) -> bool {
#[cfg(debug_assertions)]
{
let id = Id::from(_id);
self.disable_asserts || id == Id::empty_hash() || self.valid_subcommands.contains(&id)
}
#[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 id = Id::from(id);
let arg = 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 id = Id::from(id);
let arg = match 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(|v| v.downcast_ref::<T>().expect(INTERNAL_ERROR_MSG)),
len,
};
Ok(Some(values))
}
pub fn try_get_raw(&self, id: &str) -> Result<Option<RawValues<'_>>, MatchesError> {
let id = Id::from(id);
let arg = match 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_remove_one<T: Any + Clone + Send + Sync + 'static>(
&mut self,
id: &str,
) -> Result<Option<T>, MatchesError> {
let id = Id::from(id);
match self.try_remove_arg_t::<T>(&id)? {
Some(values) => Ok(values
.into_vals_flatten()
.map(|v| v.downcast_into::<T>().expect(INTERNAL_ERROR_MSG))
.next()),
None => Ok(None),
}
}
pub fn try_remove_many<T: Any + Clone + Send + Sync + 'static>(
&mut self,
id: &str,
) -> Result<Option<Values2<T>>, MatchesError> {
let id = Id::from(id);
let arg = match 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 = Values2 {
iter: values.map(|v| v.downcast_into::<T>().expect(INTERNAL_ERROR_MSG)),
len,
};
Ok(Some(values))
}
pub fn try_contains_id(&self, id: &str) -> Result<bool, MatchesError> {
let id = Id::from(id);
self.verify_arg(&id)?;
let presence = self.args.contains_key(&id);
Ok(presence)
}
}
impl ArgMatches {
#[inline]
fn try_get_arg(&self, arg: &Id) -> Result<Option<&MatchedArg>, MatchesError> {
self.verify_arg(arg)?;
Ok(self.args.get(arg))
}
#[inline]
fn try_get_arg_t<T: Any + Send + Sync + 'static>(
&self,
arg: &Id,
) -> Result<Option<&MatchedArg>, MatchesError> {
let arg = match self.try_get_arg(arg)? {
Some(arg) => arg,
None => {
return Ok(None);
}
};
self.verify_arg_t::<T>(arg)?;
Ok(Some(arg))
}
#[inline]
fn try_remove_arg_t<T: Any + Send + Sync + 'static>(
&mut self,
arg: &Id,
) -> Result<Option<MatchedArg>, MatchesError> {
self.verify_arg(arg)?;
let matched = match self.args.remove(arg) {
Some(matched) => 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(arg.clone(), 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: &Id) -> Result<(), MatchesError> {
#[cfg(debug_assertions)]
{
if self.disable_asserts || *_arg == Id::empty_hash() || self.valid_args.contains(_arg) {
} else if self.valid_subcommands.contains(_arg) {
debug!(
"Subcommand `{:?}` used where an argument or group name was expected.",
_arg
);
return Err(MatchesError::UnknownArgument {});
} 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(&self, arg: &Id) -> Option<&MatchedArg> {
#[cfg(debug_assertions)]
{
if self.disable_asserts || *arg == Id::empty_hash() || self.valid_args.contains(arg) {
} else if self.valid_subcommands.contains(arg) {
panic!(
"Subcommand `{:?}` used where an argument or group name was expected.",
arg
);
} else {
panic!(
"`{:?}` 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
);
}
}
self.args.get(arg)
}
#[inline]
#[cfg_attr(debug_assertions, track_caller)]
fn get_subcommand(&self, id: &Id) -> Option<&SubCommand> {
#[cfg(debug_assertions)]
{
if self.disable_asserts
|| *id == Id::empty_hash()
|| self.valid_subcommands.contains(id)
{
} else if self.valid_args.contains(id) {
panic!(
"Argument or group `{:?}` used where a subcommand name was expected.",
id
);
} else {
panic!("`{:?}` is not a name of a subcommand.", id);
}
}
if let Some(ref sc) = self.subcommand {
if sc.id == *id {
return Some(sc);
}
}
None
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct SubCommand {
pub(crate) id: Id,
pub(crate) name: String,
pub(crate) matches: ArgMatches,
}
#[derive(Clone, Debug)]
pub struct Values2<T> {
#[allow(clippy::type_complexity)]
iter: Map<Flatten<std::vec::IntoIter<Vec<AnyValue>>>, fn(AnyValue) -> T>,
len: usize,
}
impl<T> Iterator for Values2<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
}
impl<T> DoubleEndedIterator for Values2<T> {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back()
}
}
impl<T> ExactSizeIterator for Values2<T> {}
impl<T> Default for Values2<T> {
fn default() -> Self {
let empty: Vec<Vec<AnyValue>> = Default::default();
Values2 {
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> {
self.iter.next()
}
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> {
self.iter.next_back()
}
}
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,
}
}
}
#[cfg_attr(not(unix), doc = " ```ignore")]
#[cfg_attr(unix, doc = " ```")]
#[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> {
self.iter.next()
}
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> {
self.iter.next_back()
}
}
impl<'a> ExactSizeIterator for RawValues<'a> {}
impl Default for RawValues<'_> {
fn default() -> Self {
static EMPTY: [Vec<OsString>; 0] = [];
RawValues {
iter: EMPTY[..].iter().flatten().map(|_| unreachable!()),
len: 0,
}
}
}
#[cfg_attr(
feature = "deprecated",
deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::get_many()`")
)]
#[derive(Clone, Debug)]
pub struct Values<'a> {
#[allow(clippy::type_complexity)]
iter: Map<Flatten<Iter<'a, Vec<AnyValue>>>, for<'r> fn(&'r AnyValue) -> &'r str>,
len: usize,
}
#[allow(deprecated)]
impl<'a> Iterator for Values<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<&'a str> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
}
#[allow(deprecated)]
impl<'a> DoubleEndedIterator for Values<'a> {
fn next_back(&mut self) -> Option<&'a str> {
self.iter.next_back()
}
}
#[allow(deprecated)]
impl<'a> ExactSizeIterator for Values<'a> {}
#[allow(deprecated)]
impl<'a> Default for Values<'a> {
fn default() -> Self {
static EMPTY: [Vec<AnyValue>; 0] = [];
Values {
iter: EMPTY[..].iter().flatten().map(|_| unreachable!()),
len: 0,
}
}
}
#[derive(Clone)]
#[allow(missing_debug_implementations)]
pub struct GroupedValues<'a> {
#[allow(clippy::type_complexity)]
iter: Map<Iter<'a, Vec<AnyValue>>, fn(&Vec<AnyValue>) -> Vec<&str>>,
len: usize,
}
impl<'a> Iterator for GroupedValues<'a> {
type Item = Vec<&'a str>;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
}
impl<'a> DoubleEndedIterator for GroupedValues<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back()
}
}
impl<'a> ExactSizeIterator for GroupedValues<'a> {}
impl<'a> Default for GroupedValues<'a> {
fn default() -> Self {
#![allow(deprecated)]
static EMPTY: [Vec<AnyValue>; 0] = [];
GroupedValues {
iter: EMPTY[..].iter().map(|_| unreachable!()),
len: 0,
}
}
}
#[cfg_attr(
feature = "deprecated",
deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::get_many()`")
)]
#[derive(Clone, Debug)]
pub struct OsValues<'a> {
#[allow(clippy::type_complexity)]
iter: Map<Flatten<Iter<'a, Vec<AnyValue>>>, fn(&AnyValue) -> &OsStr>,
len: usize,
}
#[allow(deprecated)]
impl<'a> Iterator for OsValues<'a> {
type Item = &'a OsStr;
fn next(&mut self) -> Option<&'a OsStr> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
}
#[allow(deprecated)]
impl<'a> DoubleEndedIterator for OsValues<'a> {
fn next_back(&mut self) -> Option<&'a OsStr> {
self.iter.next_back()
}
}
#[allow(deprecated)]
impl<'a> ExactSizeIterator for OsValues<'a> {}
#[allow(deprecated)]
impl Default for OsValues<'_> {
fn default() -> Self {
static EMPTY: [Vec<AnyValue>; 0] = [];
OsValues {
iter: EMPTY[..].iter().flatten().map(|_| unreachable!()),
len: 0,
}
}
}
#[derive(Clone, Debug)]
pub struct Indices<'a> {
iter: Cloned<Iter<'a, usize>>,
len: usize,
}
impl<'a> Iterator for Indices<'a> {
type Item = usize;
fn next(&mut self) -> Option<usize> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
}
impl<'a> DoubleEndedIterator for Indices<'a> {
fn next_back(&mut self) -> Option<usize> {
self.iter.next_back()
}
}
impl<'a> ExactSizeIterator for Indices<'a> {}
impl<'a> Default for Indices<'a> {
fn default() -> Self {
static EMPTY: [usize; 0] = [];
Indices {
iter: EMPTY[..].iter().cloned(),
len: 0,
}
}
}
#[cfg_attr(debug_assertions, track_caller)]
#[inline]
fn unwrap_string(value: &AnyValue) -> &str {
match value.downcast_ref::<String>() {
Some(value) => value,
None => {
panic!("Must use `_os` lookups with `Arg::allow_invalid_utf8`",)
}
}
}
#[cfg_attr(debug_assertions, track_caller)]
#[inline]
fn unwrap_string_arg<'v>(id: &Id, value: &'v AnyValue) -> &'v str {
match value.downcast_ref::<String>() {
Some(value) => value,
None => {
panic!(
"Must use `_os` lookups with `Arg::allow_invalid_utf8` at `{:?}`",
id
)
}
}
}
#[cfg_attr(debug_assertions, track_caller)]
#[inline]
fn unwrap_os_string(value: &AnyValue) -> &OsStr {
match value.downcast_ref::<OsString>() {
Some(value) => value,
None => {
panic!("Must use `Arg::allow_invalid_utf8` with `_os` lookups",)
}
}
}
#[cfg_attr(debug_assertions, track_caller)]
#[inline]
fn unwrap_os_string_arg<'v>(id: &Id, value: &'v AnyValue) -> &'v OsStr {
match value.downcast_ref::<OsString>() {
Some(value) => value,
None => {
panic!(
"Must use `Arg::allow_invalid_utf8` with `_os` lookups at `{:?}`",
id
)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn check_auto_traits() {
static_assertions::assert_impl_all!(ArgMatches: Send, Sync, Unpin);
}
#[test]
fn test_default_values() {
#![allow(deprecated)]
let mut values: Values = Values::default();
assert_eq!(values.next(), None);
}
#[test]
fn test_default_osvalues() {
#![allow(deprecated)]
let mut values: OsValues = OsValues::default();
assert_eq!(values.next(), None);
}
#[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")
.takes_value(true)
.multiple_values(true)
.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")
.takes_value(true)
.multiple_values(true)
.value_parser(crate::builder::ValueParser::os_string())
.required(true),
)
.try_get_matches_from(["test", "one"])
.unwrap()
.get_many::<std::ffi::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")
.takes_value(true)
.multiple_values(true)
.required(true),
)
.try_get_matches_from(["test", "one"])
.unwrap()
.indices_of("POTATO")
.expect("present")
.len();
assert_eq!(l, 1);
}
}