use std::borrow::Cow;
use std::ffi::{OsStr, OsString};
use std::iter::{Cloned, Map};
use std::slice::Iter;
use indexmap::IndexMap;
use crate::parse::{MatchedArg, SubCommand};
use crate::util::Key;
use crate::INVALID_UTF8;
type Id = u64;
#[derive(Debug, Clone)]
pub struct ArgMatches {
#[doc(hidden)]
pub args: IndexMap<Id, MatchedArg>,
#[doc(hidden)]
pub subcommand: Option<Box<SubCommand>>,
}
impl<'a> Default for ArgMatches {
fn default() -> Self {
ArgMatches {
args: IndexMap::new(),
subcommand: None,
}
}
}
impl ArgMatches {
#[doc(hidden)]
pub fn new() -> Self {
ArgMatches {
..Default::default()
}
}
pub fn value_of<T: Key>(&self, id: T) -> Option<&str> {
if let Some(arg) = self.args.get(&id.key()) {
if let Some(v) = arg.vals.get(0) {
return Some(v.to_str().expect(INVALID_UTF8));
}
}
None
}
#[cfg_attr(not(unix), doc = " ```ignore")]
#[cfg_attr(unix, doc = " ```")]
pub fn value_of_lossy<T: Key>(&self, id: T) -> Option<Cow<'_, str>> {
if let Some(arg) = self.args.get(&id.key()) {
if let Some(v) = arg.vals.get(0) {
return Some(v.to_string_lossy());
}
}
None
}
#[cfg_attr(not(unix), doc = " ```ignore")]
#[cfg_attr(unix, doc = " ```")]
pub fn value_of_os<T: Key>(&self, id: T) -> Option<&OsStr> {
self.args
.get(&id.key())
.and_then(|arg| arg.vals.get(0).map(OsString::as_os_str))
}
pub fn values_of<T: Key>(&self, id: T) -> Option<Values<'_>> {
self.args.get(&id.key()).map(|arg| {
fn to_str_slice(o: &OsString) -> &str {
o.to_str().expect(INVALID_UTF8)
}
let to_str_slice: fn(&OsString) -> &str = to_str_slice;
Values {
iter: arg.vals.iter().map(to_str_slice),
}
})
}
#[cfg_attr(not(unix), doc = " ```ignore")]
#[cfg_attr(unix, doc = " ```")]
pub fn values_of_lossy<T: Key>(&self, id: T) -> Option<Vec<String>> {
self.args.get(&id.key()).map(|arg| {
arg.vals
.iter()
.map(|v| v.to_string_lossy().into_owned())
.collect()
})
}
#[cfg_attr(not(unix), doc = " ```ignore")]
#[cfg_attr(unix, doc = " ```")]
pub fn values_of_os<'a, T: Key>(&'a self, id: T) -> Option<OsValues<'a>> {
fn to_str_slice(o: &OsString) -> &OsStr {
&*o
}
let to_str_slice: fn(&'a OsString) -> &'a OsStr = to_str_slice;
self.args.get(&id.key()).map(|arg| OsValues {
iter: arg.vals.iter().map(to_str_slice),
})
}
pub fn is_present<T: Key>(&self, id: T) -> bool {
self._id_is_present(id.key())
}
#[doc(hidden)]
pub fn _id_is_present(&self, arg_id: Id) -> bool {
if let Some(ref sc) = self.subcommand {
if sc.id == arg_id {
return true;
}
}
self.args.contains_key(&arg_id)
}
pub fn occurrences_of<T: Key>(&self, id: T) -> u64 {
self.args.get(&id.key()).map_or(0, |a| a.occurs)
}
pub fn index_of<T: Key>(&self, name: T) -> Option<usize> {
if let Some(arg) = self.args.get(&name.key()) {
if let Some(i) = arg.indices.get(0) {
return Some(*i);
}
}
None
}
pub fn indices_of<T: Key>(&self, id: T) -> Option<Indices<'_>> {
self.args.get(&id.key()).map(|arg| Indices {
iter: arg.indices.iter().cloned(),
})
}
pub fn subcommand_matches<T: Key>(&self, id: T) -> Option<&ArgMatches> {
if let Some(ref s) = self.subcommand {
if s.id == id.key() {
return Some(&s.matches);
}
}
None
}
pub fn subcommand_name(&self) -> Option<&str> {
self.subcommand.as_ref().map(|sc| &*sc.name)
}
pub fn subcommand(&self) -> (&str, Option<&ArgMatches>) {
self.subcommand
.as_ref()
.map_or(("", None), |sc| (&sc.name[..], Some(&sc.matches)))
}
}
#[derive(Clone)]
#[allow(missing_debug_implementations)]
pub struct Values<'a> {
iter: Map<Iter<'a, OsString>, fn(&'a OsString) -> &'a str>,
}
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.iter.size_hint()
}
}
impl<'a> DoubleEndedIterator for Values<'a> {
fn next_back(&mut self) -> Option<&'a str> {
self.iter.next_back()
}
}
impl<'a> ExactSizeIterator for Values<'a> {}
impl<'a> Default for Values<'a> {
fn default() -> Self {
static EMPTY: [OsString; 0] = [];
fn to_str_slice(_: &OsString) -> &str {
unreachable!()
};
Values {
iter: EMPTY[..].iter().map(to_str_slice),
}
}
}
#[cfg_attr(not(unix), doc = " ```ignore")]
#[cfg_attr(unix, doc = " ```")]
#[derive(Clone)]
#[allow(missing_debug_implementations)]
pub struct OsValues<'a> {
iter: Map<Iter<'a, OsString>, fn(&'a OsString) -> &'a OsStr>,
}
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.iter.size_hint()
}
}
impl<'a> DoubleEndedIterator for OsValues<'a> {
fn next_back(&mut self) -> Option<&'a OsStr> {
self.iter.next_back()
}
}
impl<'a> ExactSizeIterator for OsValues<'a> {}
impl<'a> Default for OsValues<'a> {
fn default() -> Self {
static EMPTY: [OsString; 0] = [];
fn to_str_slice(_: &OsString) -> &OsStr {
unreachable!()
};
OsValues {
iter: EMPTY[..].iter().map(to_str_slice),
}
}
}
#[derive(Clone)]
#[allow(missing_debug_implementations)]
pub struct Indices<'a> {
iter: Cloned<Iter<'a, 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.iter.size_hint()
}
}
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(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_values() {
let mut values: Values = Values::default();
assert_eq!(values.next(), None);
}
#[test]
fn test_default_values_with_shorter_lifetime() {
let matches = ArgMatches::new();
let mut values = matches.values_of("").unwrap_or_default();
assert_eq!(values.next(), None);
}
#[test]
fn test_default_osvalues() {
let mut values: OsValues = OsValues::default();
assert_eq!(values.next(), None);
}
#[test]
fn test_default_osvalues_with_shorter_lifetime() {
let matches = ArgMatches::new();
let mut values = matches.values_of_os("").unwrap_or_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::new();
let mut indices = matches.indices_of("").unwrap_or_default();
assert_eq!(indices.next(), None);
}
}