wip refactoring shorts and longs into an arg key

This commit is contained in:
Kevin K 2019-09-04 20:53:31 -04:00
parent dd441f8f1c
commit 4f48b3db63
No known key found for this signature in database
GPG key ID: 17218E4B3692F01A
14 changed files with 292 additions and 213 deletions

View file

@ -21,7 +21,7 @@ use crate::output::fmt::ColorWhen;
use crate::output::{Help, Usage};
use crate::parse::errors::Result as ClapResult;
use crate::parse::{ArgMatcher, ArgMatches, Parser};
use crate::util::{Key, HELP_HASH, VERSION_HASH};
use crate::util::{FnvHash, HELP_HASH, VERSION_HASH};
use crate::INTERNAL_ERROR_MSG;
type Id = u64;
@ -980,7 +980,7 @@ impl<'b> App<'b> {
pub fn mut_arg<T, F>(mut self, arg_id: T, f: F) -> Self
where
F: FnOnce(Arg<'b>) -> Arg<'b>,
T: Key + Into<&'b str>,
T: FnvHash + Into<&'b str>,
{
let id = arg_id.key();
let a = self.args.remove_by_name(id).unwrap_or_else(|| Arg {
@ -1511,16 +1511,11 @@ impl<'b> App<'b> {
$sc.max_w = $_self.max_w;
}
{
for a in $_self
.args
.args
.iter()
.filter(|a| a.global)
{
$sc.args.push(a.clone());
}
for a in $_self.args.args.iter().filter(|a| a.global) {
$sc.args.push(a.clone());
}
}
}}
}};
}
debugln!("App::_propagate:{}", self.name);
@ -1532,14 +1527,18 @@ impl<'b> App<'b> {
sc._propagate(prop);
}
}
},
}
Propagation::To(id) => {
let mut sc = self.subcommands.iter_mut().find(|sc| sc.id == id).expect(INTERNAL_ERROR_MSG);
let mut sc = self
.subcommands
.iter_mut()
.find(|sc| sc.id == id)
.expect(INTERNAL_ERROR_MSG);
propagate_subcmd!(self, sc);
},
}
Propagation::None => {
return;
},
}
}
}

View file

@ -1,4 +1,4 @@
pub(crate) struct Alias<'help> {
pub struct Alias<'help> {
name: &'help str,
vis: bool,
}

View file

@ -1,88 +1,100 @@
use crate::INTERNAL_ERR_MSG;
use crate::build::Alias;
#[derive(Default)]
struct SwitchData<'help> {
pub struct Key<'help> {
kind: KeyKind<'help>,
}
#[derive(Default)]
pub struct SwitchData<'help> {
longs: Vec<Alias<'help>>,
short: Option<char>,
}
pub(crate) enum ArgKey<'help> {
pub(crate) enum KeyKind<'help> {
Unset,
Index(usize),
Switch(SwitchData),
Switch(SwitchData<'help>),
}
impl Default for ArgKey<'help> {
fn default() -> Self {
ArgKey::Unset
}
impl<'help> Default for KeyKind<'help> {
fn default() -> Self { KeyKind::Unset }
}
impl<'help> ArgKey {
fn long(&mut self, l: &'help str) {
match *self {
ArgKey::Unset => *self = ArgKey::Switch(SwitchData::default()),
ArgKey::Index => panic!("You cannot add both an index and switch (short or long) to an Arg"),
_ => (),
}
impl<'help> Key<'help> {
fn set_short(&mut self, c: char) { self.switch_mut().short = Some(c); }
fn add_long(&mut self, l: &'help str) {
self.switch_mut()
.expect(INTERNAL_ERR_MSG)
.longs
.push(Alias::visible(l.trim_left_matches(|c| c == '-')));
}
fn longs(&mut self, longs: &[&'help str]) {
fn add_longs(&mut self, longs: &[&'help str]) {
for l in longs {
self.long(l);
}
}
fn hidden_long(&mut self, l: &'help str) {
fn add_hidden_long(&mut self, l: &'help str) {
self.switch_mut()
.longs
.push(Alias::hidden(l.trim_left_matches(|c| c == '-')));
}
fn hidden_longs(&mut self, longs: &[&'help str]) {
fn add_hidden_longs(&mut self, longs: &[&'help str]) {
for l in longs {
self.switch_mut()
.longs
.push(Alias::hidden(l.trim_left_matches(|c| c == '-')));
}
}
fn has_index(&self) -> bool {
use ArgKey::*;
match *self {
Index(_) => true,
Switch(_) => false,
fn set_index(&mut self, i: usize) {
assert!(i > 0, "Argument index cannot be zero (0)");
self.kind = KeyKind::Index(i);
}
fn has_index(&self) -> bool { self.index().is_some() }
/// # Panics
///
/// Panics if `*self != KeyKind::Index`
fn index(&self) -> usize {
use KeyKind::*;
match self.kind {
Index(i) => i,
_ => panic!("Argument is not positional"),
}
}
fn index(&self) -> Option<&usize>> {
/// # Panics
///
/// Panics if `*self != KeyKind::Index`
fn index_mut(&mut self) -> usize {
use KeyKind::*;
match *self {
Index(i) => Some(i),
_ => None,
}
}
fn index_mut(&mut self) -> Option<&mut usize> {
match *self {
Index(i) => Some(i),
_ => None,
Index(i) => i,
_ => panic!("Argument is not positional"),
}
}
fn has_switch(&self) -> bool {
use ArgKey::*;
use KeyKind::*;
match *self {
Index(_) => false,
Switch(_) => true,
_ => false,
}
}
fn switch(&self) -> Option<&SwitchData<'help>> {
/// # Panics
///
/// Panics if `*self != KeyKind::Switch`
fn switch(&self) -> &SwitchData<'help> {
use KeyKind::*;
match *self {
Switch(s) => Some(s),
_ => None,
Switch(s) => s,
_ => panic!("Argument has no switch"),
}
}
fn switch_mut(&mut self) -> Option<&mut SwitchData<'help>> {
/// # Panics
///
/// Panics if `*self != KeyKind::Switch`
fn switch_mut(&mut self) -> &mut SwitchData<'help> {
use KeyKind::*;
match *self {
Switch(s) => Some(s),
_ => None,
Switch(s) => s,
_ => panic!("Argument has no switch"),
}
}
}

View file

@ -1,3 +1,5 @@
use crate::build::arg::Alias;
pub(crate) struct Long<'help> {
aliases: Vec<Alias<'help>>,
}

View file

@ -1,4 +1,10 @@
mod alias;
mod key;
mod long;
mod settings;
pub use self::alias::Alias;
pub use self::key::{Key, SwitchData};
pub use self::settings::{ArgFlags, ArgSettings};
// Std
@ -18,9 +24,8 @@ use crate::util::VecMap;
use yaml_rust;
// Internal
use crate::build::arg::{ArgKey, SwitchData};
use crate::build::UsageParser;
use crate::util::Key;
use crate::util::FnvHash;
#[cfg(any(target_os = "windows", target_arch = "wasm32"))]
use crate::util::OsStrExt3;
use crate::INTERNAL_ERROR_MSG;
@ -127,14 +132,14 @@ pub struct Arg<'help> {
pub val_names: Option<VecMap<&'help str>>,
// switch
pub key: ArgKey<'help>,
pub key: Key<'help>,
}
impl<'help> Arg<'help> {
/// @TODO @p2 @docs @v3-beta1: Write Docs
pub fn new<T: Key>(t: T) -> Self {
pub fn new<T: FnvHash>(t: T) -> Self {
Arg {
id: t.key(),
id: t.fnv_hash(),
disp_ord: 999,
unified_ord: 999,
..Default::default()
@ -159,7 +164,7 @@ impl<'help> Arg<'help> {
/// [`Arg`]: ./struct.Arg.html
pub fn with_name(n: &'help str) -> Self {
Arg {
id: n.key(),
id: n.fnv_hash(),
name: n,
disp_ord: 999,
unified_ord: 999,
@ -280,7 +285,7 @@ impl<'help> Arg<'help> {
/// ```
/// [`short`]: ./struct.Arg.html#method.short
pub fn short(mut self, s: char) -> Self {
self.key.short(s);
self.key.set_short(s);
self
}
@ -320,7 +325,7 @@ impl<'help> Arg<'help> {
/// assert!(m.is_present("cfg"));
/// ```
pub fn long(mut self, l: &'help str) -> Self {
self.key.long(l);
self.key.add_long(l);
self
}
@ -342,7 +347,7 @@ impl<'help> Arg<'help> {
/// [`Arg`]: ./struct.Arg.html
/// [`App::aliases`]: ./struct.Arg.html#method.aliases
pub fn longs(mut self, names: &[&'help str]) -> Self {
self.key.longs(names);
self.key.add_longs(names);
self
}
@ -372,7 +377,7 @@ impl<'help> Arg<'help> {
/// [`Arg`]: ./struct.Arg.html
/// [long]: ./struct.Arg.html#method.long
pub fn hidden_long<S: Into<&'help str>>(mut self, name: S) -> Self {
self.key.hidden_long(name);
self.key.add_hidden_long(name);
self
}
@ -396,7 +401,8 @@ impl<'help> Arg<'help> {
/// [`Arg`]: ./struct.Arg.html
/// [hidden longs]: ./struct.Arg.html#method.hidden_long
pub fn hidden_longs(mut self, names: &[&'help str]) -> Self {
self.key.hidden_longs(names): self
self.key.add_hidden_longs(names);
self
}
/// Sets the short help text of the argument that will be displayed to the user when they print
@ -581,8 +587,8 @@ impl<'help> Arg<'help> {
/// [`Arg::required_unless`]: ./struct.Arg.html#method.required_unless
/// [`Arg::required`]: ./struct.Arg.html#method.required
/// [`Arg::required_unless(name)`]: ./struct.Arg.html#method.required_unless
pub fn required_unless<T: Key>(mut self, arg_id: T) -> Self {
let name = arg_id.key();
pub fn required_unless<T: FnvHash>(mut self, arg_id: T) -> Self {
let name = arg_id.fnv_hash();
if let Some(ref mut vec) = self.r_unless {
vec.push(name);
} else {
@ -657,10 +663,10 @@ impl<'help> Arg<'help> {
pub fn required_unless_all(mut self, names: &[&str]) -> Self {
if let Some(ref mut vec) = self.r_unless {
for s in names {
vec.push(s.key());
vec.push(s.fnv_hash());
}
} else {
self.r_unless = Some(names.iter().map(Key::key).collect());
self.r_unless = Some(names.iter().map(FnvHash::id).collect());
}
self.setting(ArgSettings::RequiredUnlessAll)
}
@ -732,10 +738,10 @@ impl<'help> Arg<'help> {
pub fn required_unless_one(mut self, names: &[&str]) -> Self {
if let Some(ref mut vec) = self.r_unless {
for s in names {
vec.push(s.key());
vec.push(s.fnv_hash());
}
} else {
self.r_unless = Some(names.iter().map(Key::key).collect());
self.r_unless = Some(names.iter().map(FnvHash::id).collect());
}
self
}
@ -777,8 +783,8 @@ impl<'help> Arg<'help> {
/// assert!(res.is_err());
/// assert_eq!(res.unwrap_err().kind, ErrorKind::ArgumentConflict);
/// ```
pub fn conflicts_with<T: Key>(mut self, arg_id: T) -> Self {
let name = arg_id.key();
pub fn conflicts_with<T: FnvHash>(mut self, arg_id: T) -> Self {
let name = arg_id.fnv_hash();
if let Some(ref mut vec) = self.blacklist {
vec.push(name);
} else {
@ -831,10 +837,10 @@ impl<'help> Arg<'help> {
pub fn conflicts_with_all(mut self, names: &[&str]) -> Self {
if let Some(ref mut vec) = self.blacklist {
for s in names {
vec.push(s.key());
vec.push(s.fnv_hash());
}
} else {
self.blacklist = Some(names.iter().map(Key::key).collect());
self.blacklist = Some(names.iter().map(FnvHash::id).collect());
}
self
}
@ -940,8 +946,8 @@ impl<'help> Arg<'help> {
/// ```
/// [`Multiple*`]: ./enum.ArgSettings.html#variant.MultipleValues
/// [`UseValueDelimiter`]: ./enum.ArgSettings.html#variant.UseValueDelimiter
pub fn overrides_with<T: Key>(mut self, arg_id: T) -> Self {
let name = arg_id.key();
pub fn overrides_with<T: FnvHash>(mut self, arg_id: T) -> Self {
let name = arg_id.fnv_hash();
if let Some(ref mut vec) = self.overrides {
vec.push(name);
} else {
@ -977,13 +983,13 @@ impl<'help> Arg<'help> {
/// assert!(!m.is_present("debug"));
/// assert!(!m.is_present("flag"));
/// ```
pub fn overrides_with_all<T: Key>(mut self, names: &[T]) -> Self {
pub fn overrides_with_all<T: FnvHash>(mut self, names: &[T]) -> Self {
if let Some(ref mut vec) = self.overrides {
for s in names {
vec.push(s.key());
vec.push(s.fnv_hash());
}
} else {
self.overrides = Some(names.iter().map(Key::key).collect());
self.overrides = Some(names.iter().map(FnvHash::id).collect());
}
self
}
@ -1043,8 +1049,8 @@ impl<'help> Arg<'help> {
/// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires
/// [Conflicting]: ./struct.Arg.html#method.conflicts_with
/// [override]: ./struct.Arg.html#method.overrides_with
pub fn requires<T: Key>(mut self, arg_id: T) -> Self {
let name = arg_id.key();
pub fn requires<T: FnvHash>(mut self, arg_id: T) -> Self {
let name = arg_id.fnv_hash();
if let Some(ref mut vec) = self.requires {
vec.push((None, name));
} else {
@ -1114,8 +1120,8 @@ impl<'help> Arg<'help> {
/// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires
/// [Conflicting]: ./struct.Arg.html#method.conflicts_with
/// [override]: ./struct.Arg.html#method.overrides_with
pub fn requires_if<T: Key>(mut self, val: &'help str, arg_id: T) -> Self {
let arg = arg_id.key();
pub fn requires_if<T: FnvHash>(mut self, val: &'help str, arg_id: T) -> Self {
let arg = arg_id.fnv_hash();
if let Some(ref mut vec) = self.requires {
vec.push((Some(val), arg));
} else {
@ -1175,15 +1181,15 @@ impl<'help> Arg<'help> {
/// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires
/// [Conflicting]: ./struct.Arg.html#method.conflicts_with
/// [override]: ./struct.Arg.html#method.overrides_with
pub fn requires_ifs<T: Key>(mut self, ifs: &[(&'help str, T)]) -> Self {
pub fn requires_ifs<T: FnvHash>(mut self, ifs: &[(&'help str, T)]) -> Self {
if let Some(ref mut vec) = self.requires {
for (val, arg) in ifs {
vec.push((Some(val), arg.key()));
vec.push((Some(val), arg.fnv_hash()));
}
} else {
let mut vec = vec![];
for (val, arg) in ifs {
vec.push((Some(*val), arg.key()));
vec.push((Some(*val), arg.fnv_hash()));
}
self.requires = Some(vec);
}
@ -1253,8 +1259,8 @@ impl<'help> Arg<'help> {
/// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires
/// [Conflicting]: ./struct.Arg.html#method.conflicts_with
/// [required]: ./struct.Arg.html#method.required
pub fn required_if<T: Key>(mut self, arg_id: T, val: &'help str) -> Self {
let arg = arg_id.key();
pub fn required_if<T: FnvHash>(mut self, arg_id: T, val: &'help str) -> Self {
let arg = arg_id.fnv_hash();
if let Some(ref mut vec) = self.r_ifs {
vec.push((arg, val));
} else {
@ -1343,15 +1349,15 @@ impl<'help> Arg<'help> {
/// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires
/// [Conflicting]: ./struct.Arg.html#method.conflicts_with
/// [required]: ./struct.Arg.html#method.required
pub fn required_ifs<T: Key>(mut self, ifs: &[(T, &'help str)]) -> Self {
pub fn required_ifs<T: FnvHash>(mut self, ifs: &[(T, &'help str)]) -> Self {
if let Some(ref mut vec) = self.r_ifs {
for r_if in ifs {
vec.push((r_if.0.key(), r_if.1));
vec.push((r_if.0.fnv_hash(), r_if.1));
}
} else {
let mut vec = vec![];
for r_if in ifs {
vec.push((r_if.0.key(), r_if.1));
vec.push((r_if.0.fnv_hash(), r_if.1));
}
self.r_ifs = Some(vec);
}
@ -1420,15 +1426,15 @@ impl<'help> Arg<'help> {
/// [Conflicting]: ./struct.Arg.html#method.conflicts_with
/// [override]: ./struct.Arg.html#method.overrides_with
/// [`Arg::requires_all(&[arg, arg2])`]: ./struct.Arg.html#method.requires_all
pub fn requires_all<T: Key>(mut self, names: &[T]) -> Self {
pub fn requires_all<T: FnvHash>(mut self, names: &[T]) -> Self {
if let Some(ref mut vec) = self.requires {
for s in names {
vec.push((None, s.key()));
vec.push((None, s.fnv_hash()));
}
} else {
let mut vec = vec![];
for s in names {
vec.push((None, s.key()));
vec.push((None, s.fnv_hash()));
}
self.requires = Some(vec);
}
@ -1483,7 +1489,7 @@ impl<'help> Arg<'help> {
/// [`App`]: ./struct.App.html
/// [`panic!`]: https://doc.rust-lang.org/std/macro.panic!.html
pub fn index(mut self, idx: u64) -> Self {
self.key.index = ArgKey::Index(idx);
self.key.set_index(idx);
self
}
@ -1690,8 +1696,8 @@ impl<'help> Arg<'help> {
/// assert!(m.is_present("mode"));
/// ```
/// [`ArgGroup`]: ./struct.ArgGroup.html
pub fn group<T: Key>(mut self, group_id: T) -> Self {
let name = group_id.key();
pub fn group<T: FnvHash>(mut self, group_id: T) -> Self {
let name = group_id.fnv_hash();
if let Some(ref mut vec) = self.groups {
vec.push(name);
} else {
@ -1731,13 +1737,13 @@ impl<'help> Arg<'help> {
/// assert!(m.is_present("verbosity"));
/// ```
/// [`ArgGroup`]: ./struct.ArgGroup.html
pub fn groups<T: Key>(mut self, group_ids: &[T]) -> Self {
pub fn groups<T: FnvHash>(mut self, group_ids: &[T]) -> Self {
if let Some(ref mut vec) = self.groups {
for s in group_ids {
vec.push(s.key());
vec.push(s.fnv_hash());
}
} else {
self.groups = Some(group_ids.iter().map(Key::key).collect());
self.groups = Some(group_ids.iter().map(FnvHash::id).collect());
}
self
}
@ -2342,7 +2348,7 @@ impl<'help> Arg<'help> {
/// ```
/// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
/// [`Arg::default_value`]: ./struct.Arg.html#method.default_value
pub fn default_value_if<T: Key>(
pub fn default_value_if<T: FnvHash>(
self,
arg_id: T,
val: Option<&'help str>,
@ -2359,13 +2365,13 @@ impl<'help> Arg<'help> {
/// only using [`OsStr`]s instead.
/// [`Arg::default_value_if`]: ./struct.Arg.html#method.default_value_if
/// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html
pub fn default_value_if_os<T: Key>(
pub fn default_value_if_os<T: FnvHash>(
mut self,
arg_id: T,
val: Option<&'help OsStr>,
default: &'help OsStr,
) -> Self {
let arg = arg_id.key();
let arg = arg_id.fnv_hash();
self.setb(ArgSettings::TakesValue);
if let Some(ref mut vm) = self.default_vals_ifs {
let l = vm.len();
@ -2462,7 +2468,7 @@ impl<'help> Arg<'help> {
/// ```
/// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
/// [`Arg::default_value`]: ./struct.Arg.html#method.default_value
pub fn default_value_ifs<T: Key>(
pub fn default_value_ifs<T: FnvHash>(
mut self,
ifs: &[(T, Option<&'help str>, &'help str)],
) -> Self {
@ -2481,12 +2487,12 @@ impl<'help> Arg<'help> {
/// [`Arg::default_value_ifs`]: ./struct.Arg.html#method.default_value_ifs
/// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html
#[cfg_attr(feature = "lints", allow(explicit_counter_loop))]
pub fn default_value_ifs_os<T: Key>(
pub fn default_value_ifs_os<T: FnvHash>(
mut self,
ifs: &[(T, Option<&'help OsStr>, &'help OsStr)],
) -> Self {
for (arg, val, default) in ifs {
self = self.default_value_if_os(arg.key(), *val, default);
self = self.default_value_if_os(arg.fnv_hash(), *val, default);
}
self
}

View file

@ -6,7 +6,7 @@ use std::fmt::{Debug, Formatter, Result};
use yaml_rust;
// Internal
use crate::util::Key;
use crate::util::FnvHash;
type Id = u64;
@ -107,7 +107,7 @@ impl<'a> ArgGroup<'a> {
}
}
/// @TODO @p2 @docs @v3-beta1: Write Docs
pub fn new<T: Key>(id: T) -> Self { ArgGroup::_with_id(id.key()) }
pub fn new<T: FnvHash>(id: T) -> Self { ArgGroup::_with_id(id.fnv_hash()) }
/// Creates a new instance of `ArgGroup` using a unique string name. The name will be used to
/// get values from the group or refer to the group inside of conflict and requirement rules.
///
@ -120,7 +120,7 @@ impl<'a> ArgGroup<'a> {
/// ```
pub fn with_name(n: &'a str) -> Self {
ArgGroup {
id: n.key(),
id: n.fnv_hash(),
name: n,
..ArgGroup::default()
}
@ -166,8 +166,8 @@ impl<'a> ArgGroup<'a> {
/// ```
/// [argument]: ./struct.Arg.html
#[cfg_attr(feature = "lints", allow(should_assert_eq))]
pub fn arg<T: Key>(mut self, arg_id: T) -> Self {
self.args.push(arg_id.key());
pub fn arg<T: FnvHash>(mut self, arg_id: T) -> Self {
self.args.push(arg_id.fnv_hash());
self
}
@ -191,7 +191,7 @@ impl<'a> ArgGroup<'a> {
/// assert!(m.is_present("flag"));
/// ```
/// [arguments]: ./struct.Arg.html
pub fn args<T: Key>(mut self, ns: &[T]) -> Self {
pub fn args<T: FnvHash>(mut self, ns: &[T]) -> Self {
for n in ns {
self = self.arg(n);
}
@ -312,8 +312,8 @@ impl<'a> ArgGroup<'a> {
/// ```
/// [required group]: ./struct.ArgGroup.html#method.required
/// [argument requirement rules]: ./struct.Arg.html#method.requires
pub fn requires<T: Key>(mut self, id: T) -> Self {
let arg_id = id.key();
pub fn requires<T: FnvHash>(mut self, id: T) -> Self {
let arg_id = id.fnv_hash();
if let Some(ref mut reqs) = self.requires {
reqs.push(arg_id);
} else {
@ -388,8 +388,8 @@ impl<'a> ArgGroup<'a> {
/// assert_eq!(err.kind, ErrorKind::ArgumentConflict);
/// ```
/// [argument exclusion rules]: ./struct.Arg.html#method.conflicts_with
pub fn conflicts_with<T: Key>(mut self, id: T) -> Self {
let arg_id = id.key();
pub fn conflicts_with<T: FnvHash>(mut self, id: T) -> Self {
let arg_id = id.fnv_hash();
if let Some(ref mut confs) = self.conflicts {
confs.push(arg_id);
} else {
@ -519,7 +519,7 @@ impl<'a> From<&'a yaml_rust::yaml::Hash> for ArgGroup<'a> {
#[cfg(test)]
mod test {
use super::ArgGroup;
use super::Key;
use super::FnvHash;
#[cfg(feature = "yaml")]
use yaml_rust::YamlLoader;
@ -537,9 +537,24 @@ mod test {
.requires_all(&["r2", "r3"])
.requires("r4");
let args = vec!["a1".key(), "a4".key(), "a2".key(), "a3".key()];
let reqs = vec!["r1".key(), "r2".key(), "r3".key(), "r4".key()];
let confs = vec!["c1".key(), "c2".key(), "c3".key(), "c4".key()];
let args = vec![
"a1".fnv_hash(),
"a4".fnv_hash(),
"a2".fnv_hash(),
"a3".fnv_hash(),
];
let reqs = vec![
"r1".fnv_hash(),
"r2".fnv_hash(),
"r3".fnv_hash(),
"r4".fnv_hash(),
];
let confs = vec![
"c1".fnv_hash(),
"c2".fnv_hash(),
"c3".fnv_hash(),
"c4".fnv_hash(),
];
assert_eq!(g.args, args);
assert_eq!(g.requires, Some(reqs));
@ -560,9 +575,24 @@ mod test {
.requires_all(&["r2", "r3"])
.requires("r4");
let args = vec!["a1".key(), "a4".key(), "a2".key(), "a3".key()];
let reqs = vec!["r1".key(), "r2".key(), "r3".key(), "r4".key()];
let confs = vec!["c1".key(), "c2".key(), "c3".key(), "c4".key()];
let args = vec![
"a1".fnv_hash(),
"a4".fnv_hash(),
"a2".fnv_hash(),
"a3".fnv_hash(),
];
let reqs = vec![
"r1".fnv_hash(),
"r2".fnv_hash(),
"r3".fnv_hash(),
"r4".fnv_hash(),
];
let confs = vec![
"c1".fnv_hash(),
"c2".fnv_hash(),
"c3".fnv_hash(),
"c4".fnv_hash(),
];
let debug_str = format!(
"{{\n\
@ -594,9 +624,24 @@ mod test {
.requires_all(&["r2", "r3"])
.requires("r4");
let args = vec!["a1".key(), "a4".key(), "a2".key(), "a3".key()];
let reqs = vec!["r1".key(), "r2".key(), "r3".key(), "r4".key()];
let confs = vec!["c1".key(), "c2".key(), "c3".key(), "c4".key()];
let args = vec![
"a1".fnv_hash(),
"a4".fnv_hash(),
"a2".fnv_hash(),
"a3".fnv_hash(),
];
let reqs = vec![
"r1".fnv_hash(),
"r2".fnv_hash(),
"r3".fnv_hash(),
"r4".fnv_hash(),
];
let confs = vec![
"c1".fnv_hash(),
"c2".fnv_hash(),
"c3".fnv_hash(),
"c4".fnv_hash(),
];
let g2 = ArgGroup::from(&g);
assert_eq!(g2.args, args);
@ -625,9 +670,24 @@ requires:
- r4";
let yml = &YamlLoader::load_from_str(g_yaml).expect("failed to load YAML file")[0];
let g = ArgGroup::from_yaml(yml);
let args = vec!["a1".key(), "a4".key(), "a2".key(), "a3".key()];
let reqs = vec!["r1".key(), "r2".key(), "r3".key(), "r4".key()];
let confs = vec!["c1".key(), "c2".key(), "c3".key(), "c4".key()];
let args = vec![
"a1".fnv_hash(),
"a4".fnv_hash(),
"a2".fnv_hash(),
"a3".fnv_hash(),
];
let reqs = vec![
"r1".fnv_hash(),
"r2".fnv_hash(),
"r3".fnv_hash(),
"r4".fnv_hash(),
];
let confs = vec![
"c1".fnv_hash(),
"c2".fnv_hash(),
"c3".fnv_hash(),
"c4".fnv_hash(),
];
assert_eq!(g.args, args);
assert_eq!(g.requires, Some(reqs));
assert_eq!(g.conflicts, Some(confs));

View file

@ -8,6 +8,6 @@ mod arg_group;
mod usage_parser;
pub use self::app::{App, AppFlags, AppSettings, Propagation};
pub use self::arg::{Arg, ArgFlags, ArgKey, ArgSettings};
pub use self::arg::{Alias, Arg, ArgFlags, ArgSettings, Key};
pub use self::arg_group::ArgGroup;
pub use self::usage_parser::UsageParser;

View file

@ -1,6 +1,6 @@
// Internal
use crate::build::{Arg, ArgSettings};
use crate::util::{Key, VecMap};
use crate::util::{FnvHash, VecMap};
use crate::INTERNAL_ERROR_MSG;
#[derive(PartialEq, Debug)]
@ -89,7 +89,7 @@ impl<'a> UsageParser<'a> {
let name = &self.usage[self.start..self.pos];
if self.prev == UsageToken::Unknown {
debugln!("UsageParser::name: setting name...{}", name);
arg.id = name.key();
arg.id = name.fnv_hash();
arg.name = name;
if arg.long.is_none() && arg.short.is_none() {
debugln!("UsageParser::name: explicit name set...");
@ -146,7 +146,7 @@ impl<'a> UsageParser<'a> {
let name = &self.usage[self.start..self.pos];
if !self.explicit_name_set {
debugln!("UsageParser::long: setting name...{}", name);
arg.id = name.key();
arg.id = name.fnv_hash();
arg.name = name;
}
debugln!("UsageParser::long: setting long...{}", name);
@ -164,7 +164,7 @@ impl<'a> UsageParser<'a> {
// --long takes precedence but doesn't set self.explicit_name_set
let name = &start[..short.len_utf8()];
debugln!("UsageParser::short: setting name...{}", name);
arg.id = name.key();
arg.id = name.fnv_hash();
arg.name = name;
}
self.prev = UsageToken::Short;

View file

@ -1000,9 +1000,9 @@ macro_rules! find_subcmd {
macro_rules! longs {
($app:expr) => {{
use crate::mkeymap::KeyType;
use crate::mkeymap::MapKeyKind;
$app.args.keys.iter().map(|x| &x.key).filter_map(|a| {
if let KeyType::Long(v) = a {
if let MapKeyKind::Long(v) = a {
Some(v)
} else {
None

View file

@ -2,8 +2,8 @@
use bstr::{BStr, BString};
// Internal
use crate::build::Arg;
use crate::util::Key;
use crate::build::arg::{Arg, Key};
use crate::util::FnvHash;
type Id = u64;
@ -15,74 +15,74 @@ pub struct MKeyMap<'b> {
#[derive(PartialEq, Debug, Clone)]
pub struct MapKey {
pub key: MapKeyType,
pub key: MapKeyKind,
pub index: usize,
}
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum MapKeyType {
pub enum MapKeyKind {
Id(Id),
Short(char),
Long(BString),
Position(usize),
}
impl MapKeyType {
impl MapKeyKind {
pub(crate) fn is_position(&self) -> bool {
match *self {
MapKeyType::Position(_) => true,
MapKeyKind::Position(_) => true,
_ => false,
}
}
}
impl PartialEq<usize> for MapKeyType {
impl PartialEq<usize> for MapKeyKind {
fn eq(&self, rhs: &usize) -> bool {
match self {
MapKeyType::Position(i) => i == rhs,
MapKeyKind::Position(i) => i == rhs,
_ => false,
}
}
}
impl PartialEq<Id> for MapKeyType {
impl PartialEq<Id> for MapKeyKind {
fn eq(&self, rhs: &Id) -> bool {
match self {
MapKeyType::Id(i) => i == rhs,
MapKeyKind::Id(i) => i == rhs,
_ => false,
}
}
}
impl PartialEq<str> for MapKeyType {
impl PartialEq<str> for MapKeyKind {
fn eq(&self, rhs: &str) -> bool {
match self {
MapKeyType::Long(ref l) => l == rhs,
MapKeyType::Id(i) => i == rhs.key(),
MapKeyKind::Long(ref l) => l == rhs,
MapKeyKind::Id(i) => i == rhs.fnv_hash(),
_ => false,
}
}
}
impl PartialEq<char> for MapKeyType {
impl PartialEq<char> for MapKeyKind {
fn eq(&self, rhs: &char) -> bool {
match self {
MapKeyType::Short(c) => c == rhs,
MapKeyKind::Short(c) => c == rhs,
_ => false,
}
}
}
impl From<usize> for MapKeyType {
fn from(us: usize) -> Self { MapKeyType::Position(us) }
impl From<usize> for MapKeyKind {
fn from(us: usize) -> Self { MapKeyKind::Position(us) }
}
impl From<char> for MapKeyType {
fn from(c: char) -> Self { MapKeyType::Short(c) }
impl From<char> for MapKeyKind {
fn from(c: char) -> Self { MapKeyKind::Short(c) }
}
impl From<Id> for MapKeyType {
fn from(i: Id) -> Self { MapKeyType::Id(i) }
impl From<Id> for MapKeyKind {
fn from(i: Id) -> Self { MapKeyKind::Id(i) }
}
impl<'b> MKeyMap<'b> {
@ -97,12 +97,12 @@ impl<'b> MKeyMap<'b> {
index
}
pub fn contains<K: Into<MapKeyType>>(&self, k: K) -> bool {
pub fn contains<K: Into<MapKeyKind>>(&self, k: K) -> bool {
let key = k.into();
self.keys.iter().any(|x| x.key == key)
}
pub fn find<K: Into<MapKeyType>>(&self, k: K) -> Option<&Arg<'b>> {
pub fn find<K: Into<MapKeyKind>>(&self, k: K) -> Option<&Arg<'b>> {
let key = k.into();
self.keys
.iter()
@ -110,7 +110,7 @@ impl<'b> MKeyMap<'b> {
.map(|mk| self.args.get(mk.index))
}
pub fn remove_key<K: Into<MapKeyType>>(&mut self, k: K) {
pub fn remove_key<K: Into<MapKeyKind>>(&mut self, k: K) {
let key = k.into();
let mut idx = None;
for k in self.keys.iter() {
@ -124,7 +124,7 @@ impl<'b> MKeyMap<'b> {
}
}
pub fn remove<K: Into<MapKeyType>>(&mut self, k: K) -> Option<Arg<'b>> {
pub fn remove<K: Into<MapKeyKind>>(&mut self, k: K) -> Option<Arg<'b>> {
let key = k.into();
let mut idx = None;
for k in self.keys.iter() {
@ -149,15 +149,15 @@ impl<'b> MKeyMap<'b> {
for k in get_keys(arg) {
self.keys.push(MapKey { key: k, index: i });
}
if arg.arg_key() == ArgKey::Unset {
a.index(counter);
if arg.key() == Key::Unset {
arg.index(counter);
counter += 1;
}
}
}
pub fn find_by_name(&self, name: &str) -> Option<&Arg<'b>> {
let key: MapKeyType = name.key().into();
let key: MapKeyKind = name.key().into();
self.keys
.iter()
.find(|x| x.key == key)
@ -165,7 +165,7 @@ impl<'b> MKeyMap<'b> {
}
pub fn remove_by_name(&mut self, name: &str) -> Option<Arg<'b>> {
let key: MapKeyType = name.key().into();
let key: MapKeyKind = name.key().into();
let mut index = None;
for k in self.keys.iter() {
if k.key == key {
@ -184,7 +184,7 @@ impl<'b> MKeyMap<'b> {
}
}
fn get_keys(arg: &Arg) -> Vec<MapKeyType> {
fn get_keys(arg: &Arg) -> Vec<MapKeyKind> {
let mut keys = vec![arg.id.into()];
if let Some(index) = arg.index {
keys.push(index.into());
@ -203,7 +203,7 @@ fn get_keys(arg: &Arg) -> Vec<MapKeyType> {
#[cfg(test)]
mod tests {
use self::MapKeyType::*;
use self::MapKeyKind::*;
use super::*;
#[test]

View file

@ -9,7 +9,7 @@ use indexmap::IndexMap;
// Internal
use crate::parse::{MatchedArg, SubCommand};
use crate::util::Key;
use crate::util::FnvHash;
use crate::INVALID_UTF8;
type Id = u64;
@ -113,8 +113,8 @@ impl ArgMatches {
/// [positional]: ./struct.Arg.html#method.index
/// [`ArgMatches::values_of`]: ./struct.ArgMatches.html#method.values_of
/// [`panic!`]: https://doc.rust-lang.org/std/macro.panic!.html
pub fn value_of<T: Key>(&self, id: T) -> Option<&str> {
if let Some(arg) = self.args.get(&id.key()) {
pub fn value_of<T: FnvHash>(&self, id: T) -> Option<&str> {
if let Some(arg) = self.args.get(&id.fnv_hash()) {
if let Some(v) = arg.vals.get(0) {
return Some(v.to_str().expect(INVALID_UTF8));
}
@ -145,8 +145,8 @@ impl ArgMatches {
/// assert_eq!(&*m.value_of_lossy("arg").unwrap(), "Hi \u{FFFD}!");
/// ```
/// [`Arg::values_of_lossy`]: ./struct.ArgMatches.html#method.values_of_lossy
pub fn value_of_lossy<T: Key>(&self, id: T) -> Option<Cow<'_, str>> {
if let Some(arg) = self.args.get(&id.key()) {
pub fn value_of_lossy<T: FnvHash>(&self, id: T) -> Option<Cow<'_, str>> {
if let Some(arg) = self.args.get(&id.fnv_hash()) {
if let Some(v) = arg.vals.get(0) {
return Some(v.to_string_lossy());
}
@ -181,9 +181,9 @@ impl ArgMatches {
/// ```
/// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html
/// [`ArgMatches::values_of_os`]: ./struct.ArgMatches.html#method.values_of_os
pub fn value_of_os<T: Key>(&self, id: T) -> Option<&OsStr> {
pub fn value_of_os<T: FnvHash>(&self, id: T) -> Option<&OsStr> {
self.args
.get(&id.key())
.get(&id.fnv_hash())
.and_then(|arg| arg.vals.get(0).map(OsString::as_os_str))
}
@ -212,8 +212,8 @@ impl ArgMatches {
/// ```
/// [`Values`]: ./struct.Values.html
/// [`Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html
pub fn values_of<T: Key>(&self, id: T) -> Option<Values<'_>> {
self.args.get(&id.key()).map(|arg| {
pub fn values_of<T: FnvHash>(&self, id: T) -> Option<Values<'_>> {
self.args.get(&id.fnv_hash()).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; // coerce to fn pointer
@ -247,8 +247,8 @@ impl ArgMatches {
/// assert_eq!(&itr.next().unwrap()[..], "\u{FFFD}!");
/// assert_eq!(itr.next(), None);
/// ```
pub fn values_of_lossy<T: Key>(&self, id: T) -> Option<Vec<String>> {
self.args.get(&id.key()).map(|arg| {
pub fn values_of_lossy<T: FnvHash>(&self, id: T) -> Option<Vec<String>> {
self.args.get(&id.fnv_hash()).map(|arg| {
arg.vals
.iter()
.map(|v| v.to_string_lossy().into_owned())
@ -287,11 +287,11 @@ impl ArgMatches {
/// [`Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html
/// [`OsString`]: https://doc.rust-lang.org/std/ffi/struct.OsString.html
/// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html
pub fn values_of_os<'a, T: Key>(&'a self, id: T) -> Option<OsValues<'a>> {
pub fn values_of_os<'a, T: FnvHash>(&'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; // coerce to fn pointer
self.args.get(&id.key()).map(|arg| OsValues {
self.args.get(&id.fnv_hash()).map(|arg| OsValues {
iter: arg.vals.iter().map(to_str_slice),
})
}
@ -311,7 +311,7 @@ impl ArgMatches {
///
/// assert!(m.is_present("debug"));
/// ```
pub fn is_present<T: Key>(&self, id: T) -> bool { self._id_is_present(id.key()) }
pub fn is_present<T: FnvHash>(&self, id: T) -> bool { self._id_is_present(id.fnv_hash()) }
#[doc(hidden)]
pub fn _id_is_present(&self, arg_id: Id) -> bool {
@ -362,8 +362,8 @@ impl ArgMatches {
/// assert_eq!(m.occurrences_of("debug"), 3);
/// assert_eq!(m.occurrences_of("flag"), 1);
/// ```
pub fn occurrences_of<T: Key>(&self, id: T) -> u64 {
self.args.get(&id.key()).map_or(0, |a| a.occurs)
pub fn occurrences_of<T: FnvHash>(&self, id: T) -> u64 {
self.args.get(&id.fnv_hash()).map_or(0, |a| a.occurs)
}
/// Gets the starting index of the argument in respect to all other arguments. Indices are
@ -496,8 +496,8 @@ impl ArgMatches {
/// ```
/// [`ArgMatches`]: ./struct.ArgMatches.html
/// [delimiter]: ./struct.Arg.html#method.value_delimiter
pub fn index_of<T: Key>(&self, name: T) -> Option<usize> {
if let Some(arg) = self.args.get(&name.key()) {
pub fn index_of<T: FnvHash>(&self, name: T) -> Option<usize> {
if let Some(arg) = self.args.get(&name.fnv_hash()) {
if let Some(i) = arg.indices.get(0) {
return Some(*i);
}
@ -578,8 +578,8 @@ impl ArgMatches {
/// [`ArgMatches`]: ./struct.ArgMatches.html
/// [`ArgMatches::index_of`]: ./struct.ArgMatches.html#method.index_of
/// [delimiter]: ./struct.Arg.html#method.value_delimiter
pub fn indices_of<T: Key>(&self, id: T) -> Option<Indices<'_>> {
self.args.get(&id.key()).map(|arg| Indices {
pub fn indices_of<T: FnvHash>(&self, id: T) -> Option<Indices<'_>> {
self.args.get(&id.fnv_hash()).map(|arg| Indices {
iter: arg.indices.iter().cloned(),
})
}
@ -615,9 +615,9 @@ impl ArgMatches {
/// [`Subcommand`]: ./struct..html
/// [`App`]: ./struct.App.html
/// [`ArgMatches`]: ./struct.ArgMatches.html
pub fn subcommand_matches<T: Key>(&self, id: T) -> Option<&ArgMatches> {
pub fn subcommand_matches<T: FnvHash>(&self, id: T) -> Option<&ArgMatches> {
if let Some(ref s) = self.subcommand {
if s.id == id.key() {
if s.id == id.fnv_hash() {
return Some(&s.matches);
}
}

View file

@ -11,7 +11,7 @@ use bstr::{BStr, BString};
use crate::build::app::Propagation;
use crate::build::AppSettings as AS;
use crate::build::{App, Arg, ArgSettings};
use crate::mkeymap::KeyType;
use crate::mkeymap::MapKeyKind;
use crate::output::Help;
use crate::output::Usage;
use crate::parse::errors::Error as ClapError;
@ -20,7 +20,7 @@ use crate::parse::errors::Result as ClapResult;
use crate::parse::features::suggestions;
use crate::parse::Validator;
use crate::parse::{ArgMatcher, SubCommand};
use crate::util::{self, ChildGraph, Key, EMPTY_HASH};
use crate::util::{self, ChildGraph, FnvHash, EMPTY_HASH};
use crate::INTERNAL_ERROR_MSG;
use crate::INVALID_UTF8;
@ -99,7 +99,7 @@ where
.iter()
.map(|x| &x.key)
.filter_map(|x| {
if let KeyType::Position(n) = x {
if let MapKeyKind::Position(n) = x {
Some(n)
} else {
None
@ -117,7 +117,7 @@ where
.iter()
.map(|x| &x.key)
.filter(|x| {
if let KeyType::Position(_) = x {
if let MapKeyKind::Position(_) = x {
true
} else {
false
@ -235,7 +235,7 @@ where
let mut found = false;
for p in (1..=num_p)
.rev()
.filter_map(|n| self.app.args.get(&KeyType::Position(n as u64)))
.filter_map(|n| self.app.args.get(&MapKeyKind::Position(n as u64)))
{
if found {
assert!(
@ -284,13 +284,13 @@ where
debugln!("Parser::_build;");
//I wonder whether this part is even needed if we insert all Args using make_entries
let mut key: Vec<(KeyType, usize)> = Vec::new();
let mut key: Vec<(MapKeyKind, usize)> = Vec::new();
let mut counter = 0;
for (i, a) in self.app.args.args.iter_mut().enumerate() {
if a.index == None && a.short == None && a.long == None {
counter += 1;
a.index = Some(counter);
key.push((KeyType::Position(counter), i));
key.push((MapKeyKind::Position(counter), i));
}
// Add args with default requirements
@ -492,7 +492,7 @@ where
.iter()
.map(|x| &x.key)
.filter(|x| {
if let KeyType::Position(_) = x {
if let MapKeyKind::Position(_) = x {
true
} else {
false
@ -553,7 +553,7 @@ where
.iter()
.map(|x| &x.key)
.filter(|x| {
if let KeyType::Position(_) = x {
if let MapKeyKind::Position(_) = x {
true
} else {
false
@ -625,7 +625,7 @@ where
}
sc_m.add_val_to(EMPTY_HASH, &a);
}
let id = sc_name.key();
let id = sc_name.fnv_hash();
matcher.subcommand(SubCommand {
name: sc_name,
id,
@ -903,7 +903,7 @@ where
p.get_matches_with(&mut sc_matcher, it)?;
}
let name = sc.name.clone();
let sc_id = name.key();
let sc_id = name.fnv_hash();
matcher.subcommand(SubCommand {
id: sc_id, // @TODO @maybe: should be sc.id?
name,
@ -1004,7 +1004,7 @@ where
sdebugln!("No");
full_arg.trim_left_matches(b'-')
};
if let Some(opt) = self.app.args.get(&KeyType::Long(arg.into())) {
if let Some(opt) = self.app.args.get(&MapKeyKind::Long(arg.into())) {
debugln!(
"Parser::parse_long_arg: Found valid opt or flag '{}'",
opt.to_string()
@ -1069,7 +1069,7 @@ where
// concatenated value: -oval
// Option: -o
// Value: val
if let Some(opt) = self.app.args.get(&KeyType::Short(c)) {
if let Some(opt) = self.app.args.get(&MapKeyKind::Short(c)) {
debugln!(
"Parser::parse_short_arg:iter:{}: Found valid opt or flag",
c
@ -1448,7 +1448,7 @@ where
.iter()
.map(|x| &x.key)
.filter_map(|x| match x {
KeyType::Long(l) => Some(l.to_string_lossy().into_owned()),
MapKeyKind::Long(l) => Some(l.to_string_lossy().into_owned()),
_ => None,
})
.collect::<Vec<_>>();
@ -1462,7 +1462,7 @@ where
// Add the arg to the matches to build a proper usage string
if let Some(ref name) = suffix.1 {
if let Some(opt) = self.app.args.get(&KeyType::Long(BString::from(name))) {
if let Some(opt) = self.app.args.get(&MapKeyKind::Long(BString::from(name))) {
for g in groups_for_arg!(self.app, opt.id) {
matcher.inc_occurrence_of(g);
}

View file

@ -6,15 +6,15 @@ pub static VERSION_HASH: u64 = 0x30FF_0B7C_4D07_9478;
pub static EMPTY_HASH: u64 = 0x1C9D_3ADB_639F_298E;
const MAGIC_INIT: u64 = 0x811C_9DC5;
pub trait Key: Hash {
fn key(&self) -> u64;
pub trait FnvHash: Hash {
fn fnv_hash(&self) -> u64;
}
impl<T> Key for T
impl<T> FnvHash for T
where
T: Hash,
{
fn key(&self) -> u64 {
fn fnv_hash(&self) -> u64 {
let mut hasher = FnvHasher::new();
self.hash(&mut hasher);
hasher.finish()

View file

@ -4,7 +4,7 @@ mod map;
mod osstringext;
mod strext;
pub use self::fnv::{Key, EMPTY_HASH, HELP_HASH, VERSION_HASH};
pub use self::fnv::{FnvHash, EMPTY_HASH, HELP_HASH, VERSION_HASH};
pub use self::graph::ChildGraph;
pub use self::map::{Values, VecMap};
pub use self::osstringext::OsStrExt2;