This commit is contained in:
Kevin K 2019-02-18 20:37:53 -05:00
parent 1498910971
commit de36cd18c0
No known key found for this signature in database
GPG key ID: 17218E4B3692F01A
22 changed files with 483 additions and 516 deletions

View file

@ -1,5 +1,4 @@
[package] [package]
name = "clap" name = "clap"
version = "3.0.0-beta.1" version = "3.0.0-beta.1"
authors = ["Kevin K. <kbknapp@gmail.com>"] authors = ["Kevin K. <kbknapp@gmail.com>"]

View file

@ -1,2 +1,4 @@
type_punctuation_density = "Compressed"
format_strings = false format_strings = false
fn_single_line = true fn_single_line = true
where_pred_indent = "Visual"

View file

@ -1,272 +0,0 @@
use std::collections::HashMap;
use std::collections::hash_map::Keys;
use std::ffi::{OsStr, OsString};
use std::slice::{Iter, IterMut};
use build::{ArgSettings, Arg};
use util::hash;
// LE
fn short_to_bytes(s: char) -> [u8; 8] {
let bytes = ['-', s];
let h = '-' as u32;
let c = s as u32;
let b1 : u8 = ((h >> 24) & 0xff) as u8;
let b2 : u8 = ((h >> 16) & 0xff) as u8;
let b3 : u8 = ((h >> 8) & 0xff) as u8;
let b4 : u8 = (h & 0xff) as u8;
let b5 : u8 = ((c >> 24) & 0xff) as u8;
let b6 : u8 = ((c >> 16) & 0xff) as u8;
let b7 : u8 = ((c >> 8) & 0xff) as u8;
let b8 : u8 = (c & 0xff) as u8;
[b1, b1, b3, b4, b5, b6, b7, b8]
}
// LE
fn u64_to_bytes(u: u64) -> [u8; 8] {
let b1 : u8 = ((u >> 56) & 0xff) as u8;
let b2 : u8 = ((u >> 48) & 0xff) as u8;
let b3 : u8 = ((u >> 40) & 0xff) as u8;
let b4 : u8 = ((u >> 32) & 0xff) as u8;
let b5 : u8 = ((u >> 24) & 0xff) as u8;
let b6 : u8 = ((u >> 16) & 0xff) as u8;
let b7 : u8 = ((u >> 8) & 0xff) as u8;
let b8 : u8 = (u & 0xff) as u8;
[b1, b1, b3, b4, b5, b6, b7, b8]
}
#[derive(Default, PartialEq, Debug, Clone)]
pub struct ArgsMap<'help> {
pub index_map: HashMap<u64, usize>,
pub args: Vec<Arg<'help>>,
built: bool, // mutation isn't possible after being built
}
impl<'help> ArgsMap<'help> {
pub fn new() -> Self { ArgsMap::default() }
//TODO ::from(x), ::with_capacity(n) etc
pub fn contains_long(&self, l: &str) -> bool { self.index_map.get(&hash(l.as_bytes())).is_some() }
pub fn contains_short(&self, c: char) -> bool { self.index_map.get(&hash(short_to_bytes(c))).is_some() }
pub fn insert(&mut self, arg: Arg<'help>) -> usize {
assert!(!self.built, "Cannot add Args to the map after the map is built");
let index = self.args.len();
self.insert_keys(&arg, index);
self.args.push(arg);
index
}
pub fn push(&mut self, arg: Arg<'help>) -> usize {
assert!(!self.built, "Cannot add Args to the map after the map is built");
let index = self.args.len();
self.args.push(arg);
index
}
//TODO ::push_many([x, y])
pub fn insert_short_key(&mut self, key: char, index: usize) {
self.index_map.insert(hash(short_to_bytes(key)), index);
}
pub fn insert_long_key(&mut self, key: &str, index: usize) {
self.index_map.insert(hash(key.as_bytes()), index);
}
pub fn insert_positional_key(&mut self, key: u64, index: usize) {
self.index_map.insert(hash(u64_to_bytes(key)), index);
}
pub fn get_by_id(&self, key: u64) -> Option<&Arg<'help>> {
self.args.get(*self.index_map.get(&key)?)
}
pub fn get_by_index(&self, key: usize) -> Option<&Arg<'help>> {
self.args.get(key)
}
pub fn get_by_short(&self, key: char) -> Option<&Arg<'help>> {
self.args.get(*self.index_map.get(&hash(short_to_bytes(key)))?)
}
// &[u8] better?
pub fn get_by_short_with_hyphen(&self, key: [u8; 8]) -> Option<&Arg<'help>> {
self.args.get(*self.index_map.get(&hash(&key))?)
}
pub fn get_by_long(&self, key: &str) -> Option<&Arg<'help>> {
self.args.get(*self.index_map.get(&hash(key.as_bytes()))?)
}
pub fn get_by_long_with_hyphen(&self, key: &[u8]) -> Option<&Arg<'help>> {
self.args.get(*self.index_map.get(&hash(key))?)
}
pub fn get_by_positional(&self, key: u64) -> Option<&Arg<'help>> {
self.args.get(*self.index_map.get(&hash(u64_to_bytes(key)))?)
}
pub fn get_mut_by_id(&mut self, key: u64) -> Option<&mut Arg<'help>> {
self.args.get_mut(*self.index_map.get(&key)?)
}
pub fn get_mut_by_index(&mut self, key: usize) -> Option<&mut Arg<'help>> {
self.args.get_mut(key)
}
pub fn get_mut_by_short(&mut self, key: char) -> Option<&mut Arg<'help>> {
self.args.get_mut(*self.index_map.get(&hash(short_to_bytes(key)))?)
}
// &[u8] better?
pub fn get_mut_by_short_with_hyphen(&mut self, key: [u8; 8]) -> Option<&mut Arg<'help>> {
self.args.get_mut(*self.index_map.get(&hash(&key))?)
}
pub fn get_mut_by_long(&mut self, key: &str) -> Option<&mut Arg<'help>> {
self.args.get_mut(*self.index_map.get(&hash(key.as_bytes()))?)
}
pub fn get_mut_by_long_with_hyphen(&mut self, key: &[u8]) -> Option<&mut Arg<'help>> {
self.args.get_mut(*self.index_map.get(&hash(key))?)
}
pub fn get_mut_by_positional(&mut self, key: u64) -> Option<&mut Arg<'help>> {
self.args.get_mut(*self.index_map.get(&hash(u64_to_bytes(key)))?)
}
pub fn is_empty(&self) -> bool { self.args.is_empty() }
// Remove Key
pub fn remove_id_key(&mut self, key: u64) -> Option<usize> {
self.index_map.remove(&key)
}
pub fn remove_short_key(&mut self, key: char) -> Option<usize> {
self.index_map.remove(&hash(short_to_bytes(key)))
}
pub fn remove_short_key_with_hyphen(&mut self, key: [u8; 8]) -> Option<usize> {
self.index_map.remove(&hash(&key))
}
pub fn remove_long_key(&mut self, key: &str) -> Option<usize> {
self.index_map.remove(&hash(key.as_bytes()))
}
pub fn remove_long_key_with_hyphen(&mut self, key: &[u8]) -> Option<usize> {
self.index_map.remove(&hash(key))
}
pub fn remove_positional_key(&mut self, key: u64) -> Option<usize> {
self.index_map.remove(&hash(u64_to_bytes(key)))
}
pub fn remove_by_id(&mut self, id: u64) -> Option<Arg> {
assert!(!self.built, "Cannot remove args once built");
let i = self.index_map.remove(&id)?;
Some(self.args.swap_remove(i))
}
//TODO ::remove_keys([KeyA, KeyB])
fn insert_keys(&mut self, arg: &Arg, index: usize) {
self.index_map.insert(arg.id, index);
if let Some(p) = arg.index {
self.index_map.insert(hash(u64_to_bytes(p)), index);
} else {
if let Some(s) = arg.short {
self.index_map.insert(hash(short_to_bytes(s)), index);
}
if let Some(l) = arg.long {
self.index_map.insert(hash(l.as_bytes()), index);
}
}
}
pub fn _build(&mut self) {
self.built = true;
for (i, arg) in self.args.iter().enumerate() {
self.insert_keys(arg, i);
}
}
pub fn find_by_name(&mut self, name: u64) -> usize {
self.args
.iter()
.position(|x| x.id == name)
.expect("No such name found")
}
}
// Iter getters
impl<'help> ArgsMap<'help> {
pub fn iter_args(&self) -> Iter<Arg<'help>> {
self.args.iter()
}
pub fn iter_args_mut(&mut self) -> IterMut<Arg<'help>> {
self.args.iter_mut()
}
pub fn flags(&self) -> impl Iterator<Item=&Arg<'help>> {
self.args.iter().filter(|x| !x.is_set(ArgSettings::TakesValue) && x.has_switch())
}
pub fn opts(&self) -> impl Iterator<Item=&Arg<'help>> {
self.args.iter().filter(|x| x.is_set(ArgSettings::TakesValue) && x.has_switch())
}
pub fn positionals(&self) -> impl Iterator<Item=&Arg<'help>> {
self.args.iter().filter(|x| x.index.is_some())
}
pub fn global_args(&self) -> impl Iterator<Item=&Arg<'help>> {
self.args.iter().filter(|a| a.is_set(ArgSettings::Global))
}
}
#[cfg(test)]
mod tests {
use super::*;
use util::hash;
#[test]
fn get_some_value() {
let mut map: ArgsMap = ArgsMap::new();
map.insert(Arg::new("Value1").long("value"));
assert_eq!(
map.get_by_long_with_hyphen("--value".as_bytes()).unwrap().id,
hash("Value1")
);
}
#[test]
fn get_none_value() {
let mut map: ArgsMap = ArgsMap::new();
map.insert(Arg::new("Value1").long("value"));
assert_eq!(map.get_by_long("none"), None);
}
#[test]
fn insert_multiple_keys() {
let mut map: ArgsMap = ArgsMap::new();
let index = map.insert(Arg::new("Value1").long("value"));
map.insert_long_key("other", index);
assert_eq!(
map.get_by_long("value"),
map.get_by_long("other"),
);
assert_eq!(map.args.len(), 1);
}
#[test]
fn remove_key() {
let mut map: ArgsMap = ArgsMap::new();
let index = map.insert(Arg::new("Value1").long("value"));
map.insert_long_key("other", index);
map.remove_long_key("other");
assert_eq!(map.index_map.len(), 1);
assert_eq!(map.args.len(), 1);
}
}

View file

@ -17,13 +17,14 @@ use std::process;
use yaml_rust::Yaml; use yaml_rust::Yaml;
// Internal // Internal
use build::{Arg, ArgGroup, ArgSettings, Terminal, HelpMsg, VersionMsg, Aliases}; use crate::build::{Arg, ArgGroup, ArgSettings, Terminal, HelpMsg, VersionMsg, Aliases};
use args_map::ArgsMap; use crate::build::args::Args;
use output::fmt::ColorWhen; use crate::output::fmt::ColorWhen;
use output::{Help, Usage}; use crate::output::{Help, Usage};
use parse::errors::Result as ClapResult; use crate::parse::errors::Result as ClapResult;
use parse::{ArgMatcher, ArgMatches, Parser}; use crate::parse::{ArgMatcher, ArgMatches, Parser};
use util::hash; use crate::util::hash;
use crate::build::args::Find;
use INTERNAL_ERROR_MSG; use INTERNAL_ERROR_MSG;
#[doc(hidden)] #[doc(hidden)]
@ -91,7 +92,7 @@ pub struct App<'help> {
pub g_settings: AppFlags, pub g_settings: AppFlags,
// The list of valid arguments // The list of valid arguments
#[doc(hidden)] #[doc(hidden)]
pub args: ArgsMap<'help>, pub args: Args<'help>,
// A list of valid subcommands // A list of valid subcommands
#[doc(hidden)] #[doc(hidden)]
pub subcommands: Vec<App<'help>>, pub subcommands: Vec<App<'help>>,
@ -127,6 +128,40 @@ impl<'help> App<'help> {
} }
} }
/// Preallocate `args` number of Arguments
pub fn with_args<S: AsRef<str>>(n: S, args: usize) -> Self where S: 'help {
let name = n.as_ref();
App {
id: hash(name),
name,
args: Args::with_capacity(args),
..Default::default()
}
}
/// Preallocate `scs` number of SubCommands
pub fn with_subcommands<S: AsRef<str>>(n: S, scs: usize) -> Self where S: 'help {
let name = n.as_ref();
App {
id: hash(name),
name,
subcommands: Vec::with_capacity(scs),
..Default::default()
}
}
/// Preallocate `args` number of Arguments and `scs` number of SubCommands (not recursive)
pub fn with_args_and_subcommands<S: AsRef<str>>(n: S, args: usize, scs: usize) -> Self where S: 'help {
let name = n.as_ref();
App {
id: hash(name),
name,
args: Args::with_capacity(args),
subcommands: Vec::with_capacity(scs),
..Default::default()
}
}
/// Get the name of the app /// Get the name of the app
pub fn get_name(&self) -> &str { &self.name } pub fn get_name(&self) -> &str { &self.name }
@ -962,7 +997,7 @@ impl<'help> App<'help> {
{ {
let a = self let a = self
.args .args
.remove_by_id(hash(arg)) .remove(hash(arg))
.unwrap_or_else(|| Arg::new(arg)); .unwrap_or_else(|| Arg::new(arg));
self.args.push(f(a)); self.args.push(f(a));
@ -1365,8 +1400,7 @@ impl<'a, 'help> App<'help> {
let global_arg_vec: Vec<u64> = self let global_arg_vec: Vec<u64> = self
.args .args
.args .args()
.iter()
.filter(|a| a.is_set(ArgSettings::Global)) .filter(|a| a.is_set(ArgSettings::Global))
.map(|ga| ga.id) .map(|ga| ga.id)
.collect(); .collect();
@ -1401,8 +1435,7 @@ impl<'a, 'help> App<'help> {
true true
}); });
let mut pos_counter = 1; for a in self.args.args_mut() {
for a in self.args.args.iter_mut() {
// Figure out implied settings // Figure out implied settings
if a.is_set(ArgSettings::Last) { if a.is_set(ArgSettings::Last) {
// if an arg has `Last` set, we need to imply DontCollapseArgsInUsage so that args // if an arg has `Last` set, we need to imply DontCollapseArgsInUsage so that args
@ -1411,10 +1444,6 @@ impl<'a, 'help> App<'help> {
self.set(AppSettings::ContainsLast); self.set(AppSettings::ContainsLast);
} }
a._build(); a._build();
if a.short.is_none() && a.long.is_none() && a.index.is_none() {
a.index = Some(pos_counter);
pos_counter += 1;
}
} }
debug_assert!(self._app_debug_asserts()); debug_assert!(self._app_debug_asserts());
@ -1425,8 +1454,8 @@ impl<'a, 'help> App<'help> {
// Perform some expensive assertions on the Parser itself // Perform some expensive assertions on the Parser itself
fn _app_debug_asserts(&mut self) -> bool { fn _app_debug_asserts(&mut self) -> bool {
debugln!("App::_app_debug_asserts;"); debugln!("App::_app_debug_asserts;");
for id in self.args.args.iter().map(|x| x.id) { for id in self.args.args.args().map(|x| x.id) {
if self.args.args.iter().filter(|x| x.id == id).count() > 1 { if self.args.args.args().filter(|x| x.id == id).count() > 1 {
panic!("Arg names must be unique"); panic!("Arg names must be unique");
} }
} }
@ -1471,7 +1500,7 @@ impl<'a, 'help> App<'help> {
pub(crate) fn _create_help_and_version(&mut self) { pub(crate) fn _create_help_and_version(&mut self) {
debugln!("App::_create_help_and_version;"); debugln!("App::_create_help_and_version;");
// @TODO @perf hardcode common hashes? // @TODO @perf hardcode common hashes?
if !(self.args.get_by_long("help").is_some() || self.args.get_by_id(hash("help")).is_some()) if !(self.args.find("help").is_some() || self.args.get_by_id(hash("help")).is_some())
{ {
debugln!("App::_create_help_and_version: Building --help"); debugln!("App::_create_help_and_version: Building --help");
let mut help = Arg::new("help") let mut help = Arg::new("help")
@ -1541,31 +1570,27 @@ impl<'a, 'help> App<'help> {
debugln!("App::_arg_debug_asserts:{}", a.name); debugln!("App::_arg_debug_asserts:{}", a.name);
// Long conflicts // Long conflicts
if let Some(l) = a.long { for l in a.longs() {
assert!( assert!(
self.args.args.iter().filter(|x| x.long == Some(l)).count() < 2, self.args.args().filter(|x| x.uses_long(l)).count() < 2,
"Argument long must be unique\n\n\t--{} is already in use", "Argument long must be unique\n\n\t--{} is already in use",
l l
); );
} }
// Short conflicts // Short conflicts
if let Some(s) = a.short { if let Some(s) = a.get_short() {
assert!( assert!(
self.args.args.iter().filter(|x| x.short == Some(s)).count() < 2, self.args.args().filter(|x| x.uses_short(s)).count() < 2,
"Argument short must be unique\n\n\t-{} is already in use", "Argument short must be unique\n\n\t-{} is already in use",
s s
); );
} }
if let Some(idx) = a.index { if let Some(idx) = a.get_position() {
// No index conflicts // No index conflicts
assert!( assert!(
self.args.positionals().fold(0, |acc, p| if p.index == Some(idx as u64) { self.args.positionals().filter(|x| x.uses_position(idx)).count() < 2,
acc + 1
} else {
acc
}) < 2,
"Argument '{}' has the same index as another positional \ "Argument '{}' has the same index as another positional \
argument\n\n\tUse Arg::setting(ArgSettings::MultipleValues) to allow one \ argument\n\n\tUse Arg::setting(ArgSettings::MultipleValues) to allow one \
positional argument to take multiple values", positional argument to take multiple values",
@ -1574,14 +1599,8 @@ impl<'a, 'help> App<'help> {
} }
if a.is_set(ArgSettings::Last) { if a.is_set(ArgSettings::Last) {
assert!( assert!(
a.long.is_none(), a.has_switch(),
"Flags or Options may not have last(true) set. {} has both a long and \ "Flags or Options may not have last(true) set. {} has either a long or short and \
last(true) set.",
a.id
);
assert!(
a.short.is_none(),
"Flags or Options may not have last(true) set. {} has both a short and \
last(true) set.", last(true) set.",
a.id a.id
); );
@ -1690,20 +1709,6 @@ impl<'help> App<'help> {
} }
} }
pub(crate) fn contains_long(&self, l: &str) -> bool {
if !self.is_set(AppSettings::Propagated) {
panic!("If App::_build hasn't been called, manually search through Arg longs");
}
self.args.contains_long(l)
}
pub(crate) fn contains_short(&self, s: char) -> bool {
if !self.is_set(AppSettings::Propagated) {
panic!("If App::_build hasn't been called, manually search through Arg shorts");
}
self.args.contains_short(s)
}
pub fn is_set(&self, s: AppSettings) -> bool { pub fn is_set(&self, s: AppSettings) -> bool {
self.settings.is_set(s) || self.g_settings.is_set(s) self.settings.is_set(s) || self.g_settings.is_set(s)
} }
@ -1718,28 +1723,6 @@ impl<'help> App<'help> {
pub fn has_subcommands(&self) -> bool { !self.subcommands.is_empty() } pub fn has_subcommands(&self) -> bool { !self.subcommands.is_empty() }
pub fn has_args(&self) -> bool { !self.args.is_empty() }
pub fn has_opts(&self) -> bool { self.args.has_opts() }
pub fn has_flags(&self) -> bool { self.args.has_flags() }
pub fn has_positionals(&self) -> bool { self.args.has_positionals() }
pub fn has_visible_opts(&self) -> bool { self.args.opts().any(|o| !o.is_set(ArgSettings::Hidden)) }
pub fn has_visible_flags(&self) -> bool { self.args.flags().any(|o| !o.is_set(ArgSettings::Hidden)) }
pub fn has_visible_positionals(&self) -> bool {
self.args.positionals().any(|o| !o.is_set(ArgSettings::Hidden))
}
pub fn has_visible_subcommands(&self) -> bool {
self.subcommands.iter()
.filter(|sc| sc.name != "help")
.any(|sc| !sc.is_set(AppSettings::Hidden))
}
pub(crate) fn unroll_args_in_group(&self, group: u64) -> Vec<u64> { pub(crate) fn unroll_args_in_group(&self, group: u64) -> Vec<u64> {
let mut g_vec = vec![group]; let mut g_vec = vec![group];
let mut args = vec![]; let mut args = vec![];
@ -1754,7 +1737,7 @@ impl<'help> App<'help> {
.iter() .iter()
{ {
if !args.contains(n) { if !args.contains(n) {
if self.find(*n).is_some() { if self.args.find(*n).is_some() {
args.push(*n) args.push(*n)
} else { } else {
g_vec.push(*n); g_vec.push(*n);

View file

@ -1,37 +1,31 @@
// @TODO @p2 @docs remove Arg::setting(foo) in examples, we are sticking with Arg::foo(true) isntead // @TODO @p2 @docs remove Arg::setting(foo) in examples, we are sticking with Arg::foo(true) instead
mod settings; mod settings;
mod key; mod key;
mod short;
mod long;
pub use self::settings::{ArgFlags, ArgSettings};
// Std
#[cfg(any(target_os = "windows", target_arch = "wasm32"))]
use osstringext::OsStrExt3;
use std::borrow::Cow; use std::borrow::Cow;
use std::env; use std::env;
use std::ffi::{OsStr, OsString}; use std::ffi::{OsStr, OsString};
use std::fmt::{self, Display, Formatter}; use std::fmt::{self, Display, Formatter};
use std::hash::Hash;
#[cfg(not(any(target_os = "windows", target_arch = "wasm32")))] #[cfg(not(any(target_os = "windows", target_arch = "wasm32")))]
use std::os::unix::ffi::OsStrExt; use std::os::unix::ffi::OsStrExt;
use std::rc::Rc; use std::rc::Rc;
use std::str; use std::str;
use std::hash::Hash;
// Third Party
use util::VecMap;
#[cfg(feature = "yaml")] #[cfg(feature = "yaml")]
use yaml_rust; use yaml_rust;
// Internal
use build::UsageParser; use build::UsageParser;
use INTERNAL_ERROR_MSG; use INTERNAL_ERROR_MSG;
#[cfg(any(target_os = "windows", target_arch = "wasm32"))]
use osstringext::OsStrExt3;
use util::hash; use util::hash;
use self::key::Key; use util::VecMap;
type Validator = Rc<Fn(String) -> Result<(), String>>; pub use self::key::{Key, Position, Short, Long};
type ValidatorOs = Rc<Fn(&OsStr) -> Result<(), String>>; pub use self::settings::{ArgFlags, ArgSettings};
pub type ArgId = u64;
/// The abstract representation of a command line argument. Used to set all the options and /// The abstract representation of a command line argument. Used to set all the options and
/// relationships that define a valid argument for the program. /// relationships that define a valid argument for the program.
@ -59,13 +53,16 @@ type ValidatorOs = Rc<Fn(&OsStr) -> Result<(), String>>;
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub struct Arg<'help> { pub struct Arg<'help> {
#[doc(hidden)] #[doc(hidden)]
pub id: u64, pub id: ArgId,
#[doc(hidden)] #[doc(hidden)]
key: Key<'help>, key: Key<'help>,
#[doc(hidden)] #[doc(hidden)]
pub settings: ArgFlags, settings: ArgFlags,
#[doc(hidden)] value: Option<Value>,
pub env: Option<(&'help OsStr, Option<OsString>)>, help: HelpMessage,
occurrence: Occurrence,
validation: ValidationRules<'help>,
} }
impl<'help> Arg<'help> { impl<'help> Arg<'help> {
@ -89,32 +86,12 @@ impl<'help> Arg<'help> {
pub fn new<T>(id: T) -> Self where T: Hash{ pub fn new<T>(id: T) -> Self where T: Hash{
Arg { Arg {
id: hash(id), id: hash(id),
disp_ord: 999,
unified_ord: 999,
help: None,
long_help: None,
blacklist: None,
settings: ArgFlags::default(), settings: ArgFlags::default(),
r_unless: None,
overrides: None,
requires: None,
key: Key::new(), key: Key::new(),
possible_vals: None, value: None,
val_names: None, help: HelpMessage::new(),
num_vals: None, occurrence: Occurrence::new(),
num_vals_per_occ: None, validation: ValidationRules::new(),
max_vals: None,
min_vals: None,
validator: None,
validator_os: None,
val_delim: None,
default_val: None,
default_vals_ifs: None,
env: None,
terminator: None,
index: None,
r_ifs: None,
help_heading: None,
} }
} }
@ -351,7 +328,7 @@ impl<'help> Arg<'help> {
/// ``` /// ```
/// [`Arg::long_help`]: ./struct.Arg.html#method.long_help /// [`Arg::long_help`]: ./struct.Arg.html#method.long_help
pub fn help(mut self, h: &'help str) -> Self { pub fn help(mut self, h: &'help str) -> Self {
self.help = Some(h); self.help.short_message(h);
self self
} }
@ -422,7 +399,7 @@ impl<'help> Arg<'help> {
/// ``` /// ```
/// [`Arg::help`]: ./struct.Arg.html#method.help /// [`Arg::help`]: ./struct.Arg.html#method.help
pub fn long_help(mut self, h: &'help str) -> Self { pub fn long_help(mut self, h: &'help str) -> Self {
self.long_help = Some(h); self.help.long_message(h);
self self
} }
@ -484,11 +461,10 @@ impl<'help> Arg<'help> {
/// [`Arg::required_unless(name)`]: ./struct.Arg.html#method.required_unless /// [`Arg::required_unless(name)`]: ./struct.Arg.html#method.required_unless
pub fn required_unless<T>(mut self, other: T) -> Self where T: Hash { pub fn required_unless<T>(mut self, other: T) -> Self where T: Hash {
let id = hash(other); let id = hash(other);
if let Some(ref mut vec) = self.r_unless { self.validation.self_required_rule(
vec.push(id); Rule::new()
} else { .rule_modifier(RuleModifier::Unless)
self.r_unless = Some(vec![id]); .condition(Condition::new(id)));
}
self self
} }
@ -556,14 +532,13 @@ impl<'help> Arg<'help> {
/// [`Arg::required_unless_one`]: ./struct.Arg.html#method.required_unless_one /// [`Arg::required_unless_one`]: ./struct.Arg.html#method.required_unless_one
/// [`Arg::required_unless_all(names)`]: ./struct.Arg.html#method.required_unless_all /// [`Arg::required_unless_all(names)`]: ./struct.Arg.html#method.required_unless_all
pub fn required_unless_all<T>(mut self, others: &[T]) -> Self where T: Hash { pub fn required_unless_all<T>(mut self, others: &[T]) -> Self where T: Hash {
if let Some(ref mut vec) = self.r_unless { self.validation.self_required_rule(
for s in others { Rule::new()
vec.push(hash(s)); .rule_modifier(RuleModifier::Unless)
} .conditions_modifier(ConditionsModifier::All)
} else { .conditions(
self.r_unless = Some(others.iter().map(hash).collect()); others.iter().map(|x| Condition::new(hash(x)))));
} self
self.setting(ArgSettings::RequiredUnlessAll)
} }
/// Sets args that override this arg's [required] setting. (i.e. this arg will be required /// Sets args that override this arg's [required] setting. (i.e. this arg will be required
@ -631,13 +606,11 @@ impl<'help> Arg<'help> {
/// [`Arg::required_unless_one(names)`]: ./struct.Arg.html#method.required_unless_one /// [`Arg::required_unless_one(names)`]: ./struct.Arg.html#method.required_unless_one
/// [`Arg::required_unless_all`]: ./struct.Arg.html#method.required_unless_all /// [`Arg::required_unless_all`]: ./struct.Arg.html#method.required_unless_all
pub fn required_unless_one<T>(mut self, others: &[T]) -> Self where T: Hash { pub fn required_unless_one<T>(mut self, others: &[T]) -> Self where T: Hash {
if let Some(ref mut vec) = self.r_unless { self.validation.self_required_rule(
for s in others { Rule::new()
vec.push(hash(s)); .rule_modifier(RuleModifier::Unless)
} .conditions(
} else { others.iter().map(|x| Condition::new(hash(x)))));
self.r_unless = Some(others.iter().map(hash).collect());
}
self self
} }
@ -680,11 +653,9 @@ impl<'help> Arg<'help> {
/// ``` /// ```
pub fn conflicts_with<T>(mut self, other: T) -> Self where T: Hash { pub fn conflicts_with<T>(mut self, other: T) -> Self where T: Hash {
let id = hash(other); let id = hash(other);
if let Some(ref mut vec) = self.blacklist { self.validation.conflicts_rule(
vec.push(id); Rule::new()
} else { .condition(Condition::new(id)));
self.blacklist = Some(vec![id]);
}
self self
} }
@ -730,13 +701,10 @@ impl<'help> Arg<'help> {
/// ``` /// ```
/// [`Arg::conflicts_with`]: ./struct.Arg.html#method.conflicts_with /// [`Arg::conflicts_with`]: ./struct.Arg.html#method.conflicts_with
pub fn conflicts_with_all<T>(mut self, others: &[T]) -> Self where T: Hash { pub fn conflicts_with_all<T>(mut self, others: &[T]) -> Self where T: Hash {
if let Some(ref mut vec) = self.blacklist { self.validation.conflicts_rule(
for s in others { Rule::new()
vec.push(hash(s)); .conditions_modifier(ConditionsModifier::All)
} .conditions(otheres.iter().map(|x| Condition::new(hash(x)))));
} else {
self.blacklist = Some(others.iter().map(hash).collect());
}
self self
} }
@ -842,12 +810,9 @@ impl<'help> Arg<'help> {
/// [`Multiple*`]: ./enum.ArgSettings.html#variant.MultipleValues /// [`Multiple*`]: ./enum.ArgSettings.html#variant.MultipleValues
/// [`UseValueDelimiter`]: ./enum.ArgSettings.html#variant.UseValueDelimiter /// [`UseValueDelimiter`]: ./enum.ArgSettings.html#variant.UseValueDelimiter
pub fn overrides_with<T>(mut self, other: T) -> Self where T: Hash { pub fn overrides_with<T>(mut self, other: T) -> Self where T: Hash {
let id = hash(other); self.validation.overrides_rule(
if let Some(ref mut vec) = self.overrides { Rule::new()
vec.push(id); .condition(Condition::new(hash(other))));
} else {
self.overrides = Some(vec![id]);
}
self self
} }
@ -879,13 +844,10 @@ impl<'help> Arg<'help> {
/// assert!(!m.is_present("flag")); /// assert!(!m.is_present("flag"));
/// ``` /// ```
pub fn overrides_with_all<T>(mut self, others: &[T]) -> Self where T: Hash { pub fn overrides_with_all<T>(mut self, others: &[T]) -> Self where T: Hash {
if let Some(ref mut vec) = self.overrides { self.validation.overrides_rule(
for s in others { Rule::new()
vec.push(hash(s)); .conditions_modifier(ConditionsModifier::All)
} .conditions(others.iter().map(|x| Condition::new(hash(x)))));
} else {
self.overrides = Some(others.iter().map(hash).collect());
}
self self
} }
@ -945,14 +907,9 @@ impl<'help> Arg<'help> {
/// [Conflicting]: ./struct.Arg.html#method.conflicts_with /// [Conflicting]: ./struct.Arg.html#method.conflicts_with
/// [override]: ./struct.Arg.html#method.overrides_with /// [override]: ./struct.Arg.html#method.overrides_with
pub fn requires<T>(mut self, other: T) -> Self where T: Hash { pub fn requires<T>(mut self, other: T) -> Self where T: Hash {
let id = hash(other); self.validation.requirements_rule(
if let Some(ref mut vec) = self.requires { Rule::new()
vec.push((None, id)); .condition(Condition::new(hash(other))));
} else {
let mut vec = vec![];
vec.push((None, id));
self.requires = Some(vec);
}
self self
} }
@ -1016,12 +973,10 @@ impl<'help> Arg<'help> {
/// [Conflicting]: ./struct.Arg.html#method.conflicts_with /// [Conflicting]: ./struct.Arg.html#method.conflicts_with
/// [override]: ./struct.Arg.html#method.overrides_with /// [override]: ./struct.Arg.html#method.overrides_with
pub fn requires_if<T>(mut self, val: &'help str, other: T) -> Self where T: Hash { pub fn requires_if<T>(mut self, val: &'help str, other: T) -> Self where T: Hash {
let id = hash(other); // need self val and other val...have to re-think
if let Some(ref mut vec) = self.requires { self.validation.requirements_rule(
vec.push((Some(val), id)); Rule::new()
} else { .condition(Condition::new(hash(other))));
self.requires = Some(vec![(Some(val), id)]);
}
self self
} }
@ -1384,7 +1339,7 @@ impl<'help> Arg<'help> {
/// [`App`]: ./struct.App.html /// [`App`]: ./struct.App.html
/// [`panic!`]: https://doc.rust-lang.org/std/macro.panic!.html /// [`panic!`]: https://doc.rust-lang.org/std/macro.panic!.html
pub fn index(mut self, idx: u64) -> Self { pub fn index(mut self, idx: u64) -> Self {
self.index = Some(idx); self.key.index(idx);
self self
} }
@ -1434,8 +1389,7 @@ impl<'help> Arg<'help> {
/// [`number_of_values`]: ./struct.Arg.html#method.number_of_values /// [`number_of_values`]: ./struct.Arg.html#method.number_of_values
/// [`max_values`]: ./struct.Arg.html#method.max_values /// [`max_values`]: ./struct.Arg.html#method.max_values
pub fn value_terminator(mut self, term: &'help str) -> Self { pub fn value_terminator(mut self, term: &'help str) -> Self {
self.setb(ArgSettings::TakesValue); self.value.terminator(term);
self.terminator = Some(term);
self self
} }
@ -1487,7 +1441,6 @@ impl<'help> Arg<'help> {
/// [options]: ./struct.Arg.html#method.takes_value /// [options]: ./struct.Arg.html#method.takes_value
/// [positional arguments]: ./struct.Arg.html#method.index /// [positional arguments]: ./struct.Arg.html#method.index
pub fn possible_values(mut self, values: &[&'help str]) -> Self { pub fn possible_values(mut self, values: &[&'help str]) -> Self {
self.setb(ArgSettings::TakesValue);
if let Some(ref mut vec) = self.possible_vals { if let Some(ref mut vec) = self.possible_vals {
for s in values { for s in values {
vec.push(s); vec.push(s);
@ -1552,7 +1505,6 @@ impl<'help> Arg<'help> {
/// [options]: ./struct.Arg.html#method.takes_value /// [options]: ./struct.Arg.html#method.takes_value
/// [positional arguments]: ./struct.Arg.html#method.index /// [positional arguments]: ./struct.Arg.html#method.index
pub fn possible_value(mut self, value: &'help str) -> Self { pub fn possible_value(mut self, value: &'help str) -> Self {
self.setb(ArgSettings::TakesValue);
if let Some(ref mut vec) = self.possible_vals { if let Some(ref mut vec) = self.possible_vals {
vec.push(value); vec.push(value);
} else { } else {
@ -1598,7 +1550,6 @@ impl<'help> Arg<'help> {
/// ``` /// ```
/// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
pub fn number_of_values(mut self, qty: u64) -> Self { pub fn number_of_values(mut self, qty: u64) -> Self {
self.setb(ArgSettings::TakesValue);
self.num_vals = Some(qty); self.num_vals = Some(qty);
self self
} }
@ -1639,7 +1590,6 @@ impl<'help> Arg<'help> {
/// ``` /// ```
/// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
pub fn number_of_values_per_occurrence(mut self, qty: u64) -> Self { pub fn number_of_values_per_occurrence(mut self, qty: u64) -> Self {
self.setb(ArgSettings::TakesValue);
self.num_vals_per_occ = Some(qty); self.num_vals_per_occ = Some(qty);
self self
} }
@ -1786,8 +1736,6 @@ impl<'help> Arg<'help> {
/// ``` /// ```
/// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
pub fn max_values(mut self, qty: u64) -> Self { pub fn max_values(mut self, qty: u64) -> Self {
self.setb(ArgSettings::TakesValue);
self.setb(ArgSettings::MultipleValues);
self.max_vals = Some(qty); self.max_vals = Some(qty);
self self
} }
@ -1851,7 +1799,7 @@ impl<'help> Arg<'help> {
/// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
pub fn min_values(mut self, qty: u64) -> Self { pub fn min_values(mut self, qty: u64) -> Self {
self.min_vals = Some(qty); self.min_vals = Some(qty);
self.setting(ArgSettings::TakesValue) self
} }
/// Specifies the separator to use when values are clumped together, defaults to `,` (comma). /// Specifies the separator to use when values are clumped together, defaults to `,` (comma).
@ -1878,9 +1826,6 @@ impl<'help> Arg<'help> {
/// [`Arg::use_delimiter(true)`]: ./struct.Arg.html#method.use_delimiter /// [`Arg::use_delimiter(true)`]: ./struct.Arg.html#method.use_delimiter
/// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
pub fn value_delimiter(mut self, d: &str) -> Self { pub fn value_delimiter(mut self, d: &str) -> Self {
self.unsetb(ArgSettings::ValueDelimiterNotSet);
self.setb(ArgSettings::TakesValue);
self.setb(ArgSettings::UseValueDelimiter);
self.val_delim = Some( self.val_delim = Some(
d.chars() d.chars()
.nth(0) .nth(0)
@ -1949,11 +1894,6 @@ impl<'help> Arg<'help> {
/// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
/// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
pub fn value_names(mut self, names: &[&'help str]) -> Self { pub fn value_names(mut self, names: &[&'help str]) -> Self {
self.setb(ArgSettings::TakesValue);
if self.is_set(ArgSettings::ValueDelimiterNotSet) {
self.unsetb(ArgSettings::ValueDelimiterNotSet);
self.setb(ArgSettings::UseValueDelimiter);
}
if let Some(ref mut vals) = self.val_names { if let Some(ref mut vals) = self.val_names {
let mut l = vals.len(); let mut l = vals.len();
for s in names { for s in names {
@ -2017,7 +1957,6 @@ impl<'help> Arg<'help> {
/// [positional]: ./struct.Arg.html#method.index /// [positional]: ./struct.Arg.html#method.index
/// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
pub fn value_name(mut self, name: &'help str) -> Self { pub fn value_name(mut self, name: &'help str) -> Self {
self.setb(ArgSettings::TakesValue);
if let Some(ref mut vals) = self.val_names { if let Some(ref mut vals) = self.val_names {
let l = vals.len(); let l = vals.len();
vals.insert(l, name); vals.insert(l, name);
@ -2101,7 +2040,6 @@ impl<'help> Arg<'help> {
/// [`Arg::default_value`]: ./struct.Arg.html#method.default_value /// [`Arg::default_value`]: ./struct.Arg.html#method.default_value
/// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html /// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html
pub fn default_value_os(mut self, val: &'help OsStr) -> Self { pub fn default_value_os(mut self, val: &'help OsStr) -> Self {
self.setb(ArgSettings::TakesValue);
self.default_val = Some(val); self.default_val = Some(val);
self self
} }
@ -2221,7 +2159,6 @@ impl<'help> Arg<'help> {
default: &'help OsStr, default: &'help OsStr,
) -> Self where T: Hash { ) -> Self where T: Hash {
let id = hash(arg); let id = hash(arg);
self.setb(ArgSettings::TakesValue);
if let Some(ref mut vm) = self.default_vals_ifs { if let Some(ref mut vm) = self.default_vals_ifs {
let l = vm.len(); let l = vm.len();
vm.insert(l, (id, val, default)); vm.insert(l, (id, val, default));
@ -2445,8 +2382,6 @@ impl<'help> Arg<'help> {
/// from the environment if available in the exact same manner as [`Arg::env`] only using /// from the environment if available in the exact same manner as [`Arg::env`] only using
/// [`OsStr`]s instead. /// [`OsStr`]s instead.
pub fn env_os(mut self, name: &'help OsStr) -> Self { pub fn env_os(mut self, name: &'help OsStr) -> Self {
self.setb(ArgSettings::TakesValue);
self.env = Some((name, env::var_os(name))); self.env = Some((name, env::var_os(name)));
self self
} }
@ -3831,7 +3766,7 @@ impl<'help> Arg<'help> {
#[doc(hidden)] #[doc(hidden)]
pub fn _build(&mut self) { pub fn _build(&mut self) {
self.set_default_delimiter(); self.set_default_delimiter();
if self.key.is_positional() { if self.is_positional() {
if self.max_vals.is_some() if self.max_vals.is_some()
|| self.min_vals.is_some() || self.min_vals.is_some()
|| (self.num_vals.is_some() && self.num_vals.unwrap() > 1) || (self.num_vals.is_some() && self.num_vals.unwrap() > 1)
@ -4137,16 +4072,16 @@ impl<'help> From<&'help yaml_rust::Yaml> for Arg<'help> {
a a
} }
} }
// Flags // Flags
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::Arg;
use build::ArgSettings; use build::ArgSettings;
use util::VecMap; use util::VecMap;
use super::Arg;
#[test] #[test]
fn flag_display() { fn flag_display() {
let mut f = Arg::new("flg"); let mut f = Arg::new("flg");

View file

@ -1,8 +1,25 @@
#[derive(Default)]
pub struct HelpMessage<'help> { pub struct HelpMessage<'help> {
short_message: &'help str, short: Option<&'help str>,
long_message: &'help str, long: Option<&'help str>,
value_names: VecMap<ValueName>, value_names: VecMap<ValueName>,
display_order: DisplayOrder, display_order: DisplayOrder,
unified_order: DisplayOrder, // @TODO remove? unified_order: DisplayOrder, // @TODO remove?
heading: &'help str, // @TODO multiple? heading: &'help str, // @TODO multiple?
} }
impl<'help> HelpMessage<'help> {
pub fn new() -> Self {
HelpMessage::default()
}
#[inline(always)]
pub fn short_message(&mut self, m: &'help str) {
self.short = Some(m);
}
#[inline(always)]
pub fn long_message(&mut self, m: &'help str) {
self.long = Some(m);
}
}

View file

@ -1,4 +1,10 @@
use build::arg::{Short, Long, Position}; mod long;
mod short;
mod position;
pub use self::long::Long;
pub use self::short::Short;
pub use self::position::Position;
pub struct Key<'help> { pub struct Key<'help> {
short: Option<Short>, short: Option<Short>,
@ -20,12 +26,16 @@ impl<'help> Key<'help> {
} }
pub fn short(&mut self, short: char) { pub fn short(&mut self, short: char) {
self.short.replace(short); self.short.replace(Short(short));
} }
pub fn long(&mut self, l: &'help str) { pub fn long(&mut self, l: &'help str) {
self.long.add_long(l); self.long.add_long(l);
} }
pub fn index(&mut self, i: u64) {
self.index = Some(Position::at(i));
}
pub fn hidden_long(&mut self, l: &'help str) { pub fn hidden_long(&mut self, l: &'help str) {
self.long.add_hidden_long(l); self.long.add_hidden_long(l);
} }

View file

@ -7,7 +7,11 @@ impl Default for Position {
} }
impl Position { impl Position {
fn new() -> Self { pub fn new() -> Self {
Position(1) Position(1)
} }
pub fn at(i: u64) -> Self {
assert!(i>0, "Positional Index cannot be less than 1");
Position(i)
}
} }

View file

@ -1,3 +1 @@
pub struct Short { pub struct Short(char);
short: char
}

View file

@ -1,5 +1,34 @@
#[derive(Default, Copy, Clone, PartialEq, Eq)] use std::u64;
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Occurrence { pub struct Occurrence {
min: u64, min: u64,
max: u64 max: u64
} }
impl Default for Occurrence {
fn default() -> Self {
Occurrence {
min: 1,
max: u64::MAX
}
}
}
impl Occurrence {
#[inline(always)]
pub fn min(&mut self, num: u64) {
self.min = num;
}
#[inline(always)]
pub fn max(&mut self, num: u64) {
self.max = num;
}
#[inline]
pub fn exact(&mut self, num: u64) {
self.max = num;
self.min = num;
}
}

View file

@ -1,17 +1,49 @@
pub struct Rule<'help> { #[derive(Default)]
other_arg: u64,
self_value: Option<&'help str>,
other_value: Option<&'help str>,
}
pub struct Rules<'help> {
rules: Vec<Rule<'help>>,
}
pub struct ValidationRules<'help> { pub struct ValidationRules<'help> {
occurrence: Occurrence, occurrence: Occurrence,
conflicts: Rules<'help>, conflicts: Vec<Rule<'help>>,
requirements: Rules<'help>, requirements: Vec<Rule<'help>>,
overrides: Rules<'help>, self_required: Vec<Rule<'help>>,
requirements_unless: Rules<'help>, overrides: Vec<Rule<'help>>,
}
impl<'help> ValidationRules<'help> {
pub fn new() -> Self {
ValidationRules::default()
}
#[inline(always)]
pub fn requirement_rule(&mut self, r: Rule) {
self.requirements.push(r);
}
#[inline(always)]
pub fn self_required_rule(&mut self, r: Rule) {
self.self_required.push(r);
}
#[inline(always)]
pub fn conflicts_rule(&mut self, r: Rule) {
self.conflicts.push(r);
}
#[inline(always)]
pub fn overrides_rule(&mut self, r: Rule) {
self.overrides.push(r);
}
#[inline(always)]
pub fn max_occurs(&mut self, num: usize) {
self.occurrence.max(num);
}
#[inline(always)]
pub fn min_occurs(&mut self, num: usize) {
self.occurrence.min(num);
}
#[inline]
pub fn exact_occurs(&mut self, num: usize) {
self.occurrence.exact(num);
}
} }

View file

@ -0,0 +1,43 @@
pub enum ConditionsModifier {
All,
Any,
None,
}
impl Default for ConditionsModifer {
fn default() -> Self {
ConditionsModifier::Any
}
}
pub struct Condition<'help> {
arg: u64,
arg_value: Option<&'help str>,
other_value: Option<&'help str>,
}
impl<'help> Condition<'help> {
pub fn new(id: ArgId) -> Self {
Condition {
arg: id,
arg_value: None,
other_value: None,
}
}
pub fn arg(mut self, id: ArgId) -> Self {
self.arg = id;
self
}
pub fn arg_value(mut self, val: &'help str) -> Self {
self.arg_value = Some(val);
self
}
pub fn other_value(mut self, val: &'help str) -> Self {
self.other_value = Some(val);
self
}
}

View file

@ -0,0 +1,52 @@
use super::ConditionsModifier;
pub enum RuleModifer {
Unless,
With,
}
impl Default for RuleModifer {
fn default() -> Self {
RuleModifer::With
}
}
#[derive(Default)]
pub struct Rule<'help> {
rule_mod: RuleModifer,
conditions_mod: ConditionsModifier,
conditions: Vec<Condition<'help>>,
}
impl<'help> Rule<'help> {
pub fn new() -> Self {
Rule::default()
}
pub fn rule_modifier(mut self, rm: RuleModifer) -> Self {
self.rule_mod = rm;
self
}
pub fn conditions_mod(mut self, cm: ConditionsModifier) -> Self {
self.conditions_mod = cm;
self
}
pub fn condition(mut self, c: Condition) -> Self {
self.conditions.push(c);
self
}
pub fn conditions(mut self, conds: &dyn Iterator<Item=Condition>) -> Self {
for c in conds {
self.conditions.push(cond);
}
self
}
pub fn clear_conditions(&mut self) {
self.conditions.clear()
}
}

View file

@ -1,3 +1,10 @@
mod default_values;
mod delimiter;
mod filter;
mod possible_values;
mod terminator;
mod value_name;
pub struct Value<'help> { pub struct Value<'help> {
defaults: Option<DefaultValues>, defaults: Option<DefaultValues>,
filter: Filter, filter: Filter,
@ -5,3 +12,9 @@ pub struct Value<'help> {
requires_equals: bool, requires_equals: bool,
delimiter: Delimiter, delimiter: Delimiter,
} }
impl<'help> Value<'help> {
fn new() -> Self {
}
}

View file

@ -0,0 +1,4 @@
pub type Validator = Rc<Fn(String) -> Result<(), String>>;
pub type ValidatorOs = Rc<Fn(&OsStr) -> Result<(), String>>;

View file

@ -1,3 +1,5 @@
// Maybe move to help message? Or keep here in case we integrate into Value at some point?
use std::io; use std::io;
pub struct ValueName<'help>(&'help str); pub struct ValueName<'help>(&'help str);

113
src/build/args.rs Normal file
View file

@ -0,0 +1,113 @@
use std::ops::Index;
use crate::Arg;
use crate::build::arg::{ArgId, Position};
pub trait Find<By> {
type Output;
fn find(&self, by: By) -> Option<<Self as Find<By>>::Output>;
}
pub trait FindMut<By> {
type Output;
fn find(&mut self, by: By) -> Option<<Self as FindMut<By>>::Output>;
}
pub struct Args<'help> {
inner: Vec<Arg<'help>>,
}
impl<'help> Args<'help> {
pub fn contains_short(&self, s: char) -> bool {
self.args().any(|x| x.uses_short(c))
}
pub fn contains_long(&self, l: &str) -> bool {
self.args().any(|x| x.uses_long(l))
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn has_flags(&self) -> bool {
self.flags().any(|x| x.is_flag())
}
pub fn has_options(&self) -> bool {
self.options().any(|x| x.is_option())
}
pub fn has_positionals(&self) -> bool {
self.positionals().any(|x| x.is_positional())
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn push(&mut self, arg: Arg<'help>) {
self.inner.push(arg)
}
pub fn remove(&mut self, id: ArgId) -> Option<Arg<'help>> {
let opt_i = self.args().enumerate().find(|(x, i)| x.id == id).map(|x| x.0);
if let Some(i) = opt_i {
Some(self.inner.swap_remove(i))
} else {
None
}
}
pub fn find(&self, id: ArgId) -> Option<&Arg<'help>> {
self.args().find(|x| x.id == id)
}
pub fn find_short(&self, s: char) -> Option<&Arg<'help>> {
self.args().find(|x| x.uses_short(s))
}
pub fn find_long(&self, l: &str) -> Option<&Arg<'help>> {
self.args().find(|x| x.uses_long(l))
}
pub fn find_position(&self, p: Position) -> Option<&Arg<'help>> {
self.positionals().find(|x| x.uses_position(p))
}
pub fn find_mut(&mut self, id: ArgId) -> Option<&mut Arg<'help>> {
self.args_mut().find(|x| x.id == id)
}
pub fn find_short_mut(&mut self, s: char) -> Option<&mut Arg<'help>> {
self.args_mut().find(|x| x.uses_short(s))
}
pub fn find_long_mut(&mut self, l: &str) -> Option<&mut Arg<'help>> {
self.args_mut().find(|x| x.uses_long(l))
}
pub fn find_position_mut(&mut self, p: Position) -> Option<&mut Arg<'help>> {
self.positionals_mut().find(|x| x.uses_position(p))
}
}
// Iterator Getters
impl<'help> Args<'help> {
pub fn args(&self) -> impl Iterator<Item=&Arg> {
self.inner.iter()
}
pub fn flags(&self) -> impl Iterator<Item=&Arg> {
self.args().filter(|x| x.is_flat())
}
pub fn options(&self) -> impl Iterator<Item=&Arg> {
self.args().filter(|x| x.is_option())
}
pub fn positionals(&self) -> impl Iterator<Item=&Arg> {
self.args().filter(|x| x.is_positional())
}
pub fn args_mut(&mut self) -> impl Iterator<Item=&mut Arg> {
self.inner.iter_mut()
}
pub fn flags_mut(&mut self) -> impl Iterator<Item=&mut Arg> {
self.args_mut().filter(|x| x.is_flat())
}
pub fn options_mut(&mut self) -> impl Iterator<Item=&mut Arg> {
self.args_mut().filter(|x| x.is_option())
}
pub fn positionals_mut(&mut self) -> impl Iterator<Item=&mut Arg> {
self.args_mut().filter(|x| x.is_positional())
}
}
impl<'a, 'help> Index<usize> for Args<'help> {
type Output = &'a Arg<'help>;
fn index(&'a self, index: usize) -> &'a Arg<'help> {
self.inner[index]
}
}

View file

@ -7,6 +7,7 @@ mod aliases;
pub mod app; pub mod app;
pub mod arg; pub mod arg;
pub mod args;
mod arg_group; mod arg_group;
mod usage_parser; mod usage_parser;

View file

@ -578,7 +578,6 @@ use std::result::Result as StdResult;
mod macros; mod macros;
mod build; mod build;
mod args_map;
mod output; mod output;
mod parse; mod parse;
mod util; mod util;

View file

@ -1,7 +1,12 @@
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
const MAGIC_INIT: u64 = 0x811C9DC5;
#[inline] #[inline]
pub(crate) fn hash<T>(t: T) -> u64 where T: Hash { pub(crate) fn hash<T>(t: T) -> u64
where
T: Hash,
{
let mut hasher = FnvHasher::new(); let mut hasher = FnvHasher::new();
t.hash(&mut hasher); t.hash(&mut hasher);
hasher.finish() hasher.finish()
@ -10,9 +15,7 @@ pub(crate) fn hash<T>(t: T) -> u64 where T: Hash {
pub(crate) struct FnvHasher(u64); pub(crate) struct FnvHasher(u64);
impl FnvHasher { impl FnvHasher {
pub(crate) fn new() -> Self { pub(crate) fn new() -> Self { FnvHasher(MAGIC_INIT) }
FnvHasher(0x811C9DC5)
}
} }
impl Hasher for FnvHasher { impl Hasher for FnvHasher {