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_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()`")
)]
#[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()`")
)]
#[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()`")
)]
#[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(...)`"
)
)]
#[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`"
)
)]
#[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()`")
)]
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);
}
}