mirror of
https://github.com/clap-rs/clap
synced 2025-01-18 23:53:54 +00:00
perf: debloats clap by deduplicating logic and refactors
This commit removes heavy use of macros in certain functions which drastically increased code size. Some of the macros could be turned into functions, while others could be removed entirely. Examples were removing arg_post_processing! which did things like checked overrides, requirements, groups, etc. This would happen after every argument was parsed. This macro also had several other macros inside it, and would expand to several tens or hundreds of lines of code. Then add that due to borrowck and branch issues, this macro may be included in multiple parts of a function. Unlike traditional functions each of these uses expanded into TONS of code (just like agressive inlining). This commit primarily removes those arg_post_processing! calls and breaks up the functionality into two types. The first must happen at ever new argument (not new value, but new argument). This is pretty cheap. The next type was moved to the end of parsing validation section which is more expensive, but only happens once. i.e. clap was validating each argument/value as it saw them, now it's lazy and validates them all at once at the end. This MUCH more efficient!
This commit is contained in:
parent
d26ab2b97c
commit
03e413d717
6 changed files with 325 additions and 359 deletions
|
@ -1,165 +0,0 @@
|
|||
macro_rules! remove_overriden {
|
||||
(@remove_requires $rem_from:expr, $a:ident.$ov:ident) => {
|
||||
if let Some(ora) = $a.$ov() {
|
||||
for i in (0 .. $rem_from.len()).rev() {
|
||||
let should_remove = ora.iter().any(|&(_, ref name)| name == &$rem_from[i]);
|
||||
if should_remove { $rem_from.swap_remove(i); }
|
||||
}
|
||||
}
|
||||
};
|
||||
(@remove $rem_from:expr, $a:ident.$ov:ident) => {
|
||||
if let Some(ora) = $a.$ov() {
|
||||
vec_remove_all!($rem_from, ora.iter());
|
||||
}
|
||||
};
|
||||
(@arg $_self:ident, $arg:ident) => {
|
||||
remove_overriden!(@remove_requires $_self.required, $arg.requires);
|
||||
remove_overriden!(@remove $_self.blacklist, $arg.blacklist);
|
||||
remove_overriden!(@remove $_self.overrides, $arg.overrides);
|
||||
};
|
||||
($_self:ident, $name:expr) => {
|
||||
debugln!("remove_overriden!;");
|
||||
if let Some(o) = $_self.opts.iter() .find(|o| o.b.name == *$name) {
|
||||
remove_overriden!(@arg $_self, o);
|
||||
} else if let Some(f) = $_self.flags.iter() .find(|f| f.b.name == *$name) {
|
||||
remove_overriden!(@arg $_self, f);
|
||||
} else {
|
||||
let p = $_self.positionals.values()
|
||||
.find(|p| p.b.name == *$name)
|
||||
.expect(INTERNAL_ERROR_MSG);
|
||||
remove_overriden!(@arg $_self, p);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! arg_post_processing {
|
||||
($me:ident, $arg:ident, $matcher:ident) => {
|
||||
debugln!("arg_post_processing!;");
|
||||
// Handle POSIX overrides
|
||||
debug!("arg_post_processing!: Is '{}' in overrides...", $arg.to_string());
|
||||
if $me.overrides.contains(&$arg.name()) {
|
||||
if let Some(ref name) = find_name_from!($me, &$arg.name(), overrides, $matcher) {
|
||||
sdebugln!("Yes by {}", name);
|
||||
$matcher.remove(name);
|
||||
remove_overriden!($me, name);
|
||||
}
|
||||
} else { sdebugln!("No"); }
|
||||
|
||||
// Add overrides
|
||||
debug!("arg_post_processing!: Does '{}' have overrides...", $arg.to_string());
|
||||
if let Some(or) = $arg.overrides() {
|
||||
sdebugln!("Yes");
|
||||
$matcher.remove_all(or);
|
||||
for pa in or { remove_overriden!($me, pa); }
|
||||
$me.overrides.extend(or);
|
||||
vec_remove_all!($me.required, or.iter());
|
||||
} else { sdebugln!("No"); }
|
||||
|
||||
// Handle conflicts
|
||||
debug!("arg_post_processing!: Does '{}' have conflicts...", $arg.to_string());
|
||||
if let Some(bl) = $arg.blacklist() {
|
||||
sdebugln!("Yes");
|
||||
|
||||
for c in bl {
|
||||
// Inject two-way conflicts
|
||||
debug!("arg_post_processing!: Has '{}' already been matched...", c);
|
||||
if $matcher.contains(c) {
|
||||
sdebugln!("Yes");
|
||||
// find who blacklisted us...
|
||||
$me.blacklist.push(&$arg.b.name);
|
||||
} else {
|
||||
sdebugln!("No");
|
||||
}
|
||||
}
|
||||
|
||||
$me.blacklist.extend_from_slice(bl);
|
||||
vec_remove_all!($me.overrides, bl.iter());
|
||||
// vec_remove_all!($me.required, bl.iter());
|
||||
} else { sdebugln!("No"); }
|
||||
|
||||
// Add all required args which aren't already found in matcher to the master
|
||||
// list
|
||||
debug!("arg_post_processing!: Does '{}' have requirements...", $arg.to_string());
|
||||
if let Some(reqs) = $arg.requires() {
|
||||
for n in reqs.iter()
|
||||
.filter(|&&(val, _)| val.is_none())
|
||||
.filter(|&&(_, req)| !$matcher.contains(&req))
|
||||
.map(|&(_, name)| name) {
|
||||
|
||||
$me.required.push(n);
|
||||
}
|
||||
} else { sdebugln!("No"); }
|
||||
|
||||
_handle_group_reqs!($me, $arg);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! _handle_group_reqs{
|
||||
($me:ident, $arg:ident) => ({
|
||||
use args::AnyArg;
|
||||
debugln!("_handle_group_reqs!;");
|
||||
for grp in &$me.groups {
|
||||
let found = if grp.args.contains(&$arg.name()) {
|
||||
if let Some(ref reqs) = grp.requires {
|
||||
debugln!("_handle_group_reqs!: Adding {:?} to the required list", reqs);
|
||||
$me.required.extend(reqs);
|
||||
}
|
||||
if let Some(ref bl) = grp.conflicts {
|
||||
$me.blacklist.extend(bl);
|
||||
}
|
||||
true // What if arg is in more than one group with different reqs?
|
||||
} else {
|
||||
false
|
||||
};
|
||||
debugln!("_handle_group_reqs!:iter: grp={}, found={:?}", grp.name, found);
|
||||
if found {
|
||||
for i in (0 .. $me.required.len()).rev() {
|
||||
let should_remove = grp.args.contains(&$me.required[i]);
|
||||
if should_remove { $me.required.swap_remove(i); }
|
||||
}
|
||||
debugln!("_handle_group_reqs!:iter: Adding args from group to blacklist...{:?}", grp.args);
|
||||
if !grp.multiple {
|
||||
$me.blacklist.extend(&grp.args);
|
||||
debugln!("_handle_group_reqs!: removing {:?} from blacklist", $arg.name());
|
||||
for i in (0 .. $me.blacklist.len()).rev() {
|
||||
let should_remove = $me.blacklist[i] == $arg.name();
|
||||
if should_remove { $me.blacklist.swap_remove(i); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
macro_rules! parse_positional {
|
||||
(
|
||||
$_self:ident,
|
||||
$p:ident,
|
||||
$arg_os:ident,
|
||||
$pos_counter:ident,
|
||||
$matcher:ident
|
||||
) => {
|
||||
debugln!("parse_positional!;");
|
||||
|
||||
if !$_self.is_set(AS::TrailingValues) &&
|
||||
($_self.is_set(AS::TrailingVarArg) &&
|
||||
$pos_counter == $_self.positionals.len()) {
|
||||
$_self.settings.set(AS::TrailingValues);
|
||||
}
|
||||
let _ = $_self.add_val_to_arg($p, &$arg_os, $matcher)?;
|
||||
|
||||
$matcher.inc_occurrence_of($p.b.name);
|
||||
let _ = $_self.groups_for_arg($p.b.name)
|
||||
.and_then(|vec| Some($matcher.inc_occurrences_of(&*vec)));
|
||||
if $_self.cache.map_or(true, |name| name != $p.b.name) {
|
||||
arg_post_processing!($_self, $p, $matcher);
|
||||
$_self.cache = Some($p.b.name);
|
||||
}
|
||||
|
||||
$_self.settings.set(AS::ValidArgFound);
|
||||
// Only increment the positional counter if it doesn't allow multiples
|
||||
if !$p.b.settings.is_set(ArgSettings::Multiple) {
|
||||
$pos_counter += 1;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -61,8 +61,7 @@ where
|
|||
pub global_args: Vec<Arg<'a, 'b>>,
|
||||
pub required: Vec<&'a str>,
|
||||
pub r_ifs: Vec<(&'a str, &'b str, &'a str)>,
|
||||
pub blacklist: Vec<&'b str>,
|
||||
pub overrides: Vec<&'b str>,
|
||||
pub overrides: Vec<(&'b str, &'a str)>,
|
||||
help_short: Option<char>,
|
||||
version_short: Option<char>,
|
||||
cache: Option<&'a str>,
|
||||
|
@ -346,9 +345,9 @@ where
|
|||
if let Some(ref reqs) = group.requires {
|
||||
self.required.extend_from_slice(reqs);
|
||||
}
|
||||
if let Some(ref bl) = group.conflicts {
|
||||
self.blacklist.extend_from_slice(bl);
|
||||
}
|
||||
// if let Some(ref bl) = group.conflicts {
|
||||
// self.blacklist.extend_from_slice(bl);
|
||||
// }
|
||||
}
|
||||
if self.groups.iter().any(|g| g.name == group.name) {
|
||||
let grp = self.groups
|
||||
|
@ -773,12 +772,8 @@ where
|
|||
|
||||
// allow wrong self convention due to self.valid_neg_num = true and it's a private method
|
||||
#[cfg_attr(feature = "lints", allow(wrong_self_convention))]
|
||||
fn is_new_arg(&mut self, arg_os: &OsStr, needs_val_of: ParseResult<'a>) -> bool {
|
||||
debugln!(
|
||||
"Parser::is_new_arg: arg={:?}, Needs Val of={:?}",
|
||||
arg_os,
|
||||
needs_val_of
|
||||
);
|
||||
fn is_new_arg(&mut self, arg_os: &OsStr, needs_val_of: ParseResult) -> bool {
|
||||
debugln!( "Parser::is_new_arg:{:?}:{:?}", arg_os, needs_val_of);
|
||||
let app_wide_settings = if self.is_set(AS::AllowLeadingHyphen) {
|
||||
true
|
||||
} else if self.is_set(AS::AllowNegativeNumbers) {
|
||||
|
@ -807,12 +802,10 @@ where
|
|||
.expect(INTERNAL_ERROR_MSG);
|
||||
(p.is_set(ArgSettings::AllowLeadingHyphen) || app_wide_settings)
|
||||
}
|
||||
ParseResult::ValuesDone => return true,
|
||||
_ => false,
|
||||
};
|
||||
debugln!(
|
||||
"Parser::is_new_arg: Arg::allow_leading_hyphen({:?})",
|
||||
arg_allows_tac
|
||||
);
|
||||
debugln!( "Parser::is_new_arg: arg_allows_tac={:?}", arg_allows_tac );
|
||||
|
||||
// Is this a new argument, or values from a previous option?
|
||||
let mut ret = if arg_os.starts_with(b"--") {
|
||||
|
@ -913,7 +906,52 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
if !starts_new_arg {
|
||||
if starts_new_arg {
|
||||
{
|
||||
let any_arg = find_any_by_name!(self, self.cache.unwrap_or(""));
|
||||
matcher.process_arg_overrides(any_arg, &mut self.overrides, &mut self.required);
|
||||
}
|
||||
|
||||
if arg_os.starts_with(b"--") {
|
||||
needs_val_of = self.parse_long_arg(matcher, &arg_os)?;
|
||||
debugln!( "Parser:get_matches_with: After parse_long_arg {:?}", needs_val_of );
|
||||
match needs_val_of {
|
||||
ParseResult::Flag | ParseResult::Opt(..) | ParseResult::ValuesDone => {
|
||||
continue
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
} else if arg_os.starts_with(b"-") && arg_os.len_() != 1 {
|
||||
// Try to parse short args like normal, if AllowLeadingHyphen or
|
||||
// AllowNegativeNumbers is set, parse_short_arg will *not* throw
|
||||
// an error, and instead return Ok(None)
|
||||
needs_val_of = self.parse_short_arg(matcher, &arg_os)?;
|
||||
// If it's None, we then check if one of those two AppSettings was set
|
||||
debugln!(
|
||||
"Parser:get_matches_with: After parse_short_arg {:?}",
|
||||
needs_val_of
|
||||
);
|
||||
match needs_val_of {
|
||||
ParseResult::MaybeNegNum => {
|
||||
if !(arg_os.to_string_lossy().parse::<i64>().is_ok()
|
||||
|| arg_os.to_string_lossy().parse::<f64>().is_ok())
|
||||
{
|
||||
return Err(Error::unknown_argument(
|
||||
&*arg_os.to_string_lossy(),
|
||||
"",
|
||||
&*usage::create_error_usage(self, matcher, None),
|
||||
self.color(),
|
||||
));
|
||||
}
|
||||
},
|
||||
ParseResult::Opt(..) | ParseResult::Flag | ParseResult::ValuesDone => {
|
||||
continue
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if let ParseResult::Opt(name) = needs_val_of {
|
||||
// Check to see if parsing a value from a previous arg
|
||||
let arg = self.opts
|
||||
|
@ -925,62 +963,20 @@ where
|
|||
// get the next value from the iterator
|
||||
continue;
|
||||
}
|
||||
} else if arg_os.starts_with(b"--") {
|
||||
needs_val_of = self.parse_long_arg(matcher, &arg_os)?;
|
||||
debugln!(
|
||||
"Parser:get_matches_with: After parse_long_arg {:?}",
|
||||
needs_val_of
|
||||
);
|
||||
match needs_val_of {
|
||||
ParseResult::Flag | ParseResult::Opt(..) | ParseResult::ValuesDone => {
|
||||
continue
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
} else if arg_os.starts_with(b"-") && arg_os.len_() != 1 {
|
||||
// Try to parse short args like normal, if AllowLeadingHyphen or
|
||||
// AllowNegativeNumbers is set, parse_short_arg will *not* throw
|
||||
// an error, and instead return Ok(None)
|
||||
needs_val_of = self.parse_short_arg(matcher, &arg_os)?;
|
||||
// If it's None, we then check if one of those two AppSettings was set
|
||||
debugln!(
|
||||
"Parser:get_matches_with: After parse_short_arg {:?}",
|
||||
needs_val_of
|
||||
);
|
||||
match needs_val_of {
|
||||
ParseResult::MaybeNegNum => {
|
||||
if !(arg_os.to_string_lossy().parse::<i64>().is_ok()
|
||||
|| arg_os.to_string_lossy().parse::<f64>().is_ok())
|
||||
{
|
||||
return Err(Error::unknown_argument(
|
||||
&*arg_os.to_string_lossy(),
|
||||
"",
|
||||
&*usage::create_error_usage(self, matcher, None),
|
||||
self.color(),
|
||||
));
|
||||
}
|
||||
}
|
||||
ParseResult::Opt(..) | ParseResult::Flag | ParseResult::ValuesDone => {
|
||||
continue
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !(self.is_set(AS::ArgsNegateSubcommands) && self.is_set(AS::ValidArgFound))
|
||||
&& !self.is_set(AS::InferSubcommands)
|
||||
{
|
||||
if let Some(cdate) =
|
||||
suggestions::did_you_mean(&*arg_os.to_string_lossy(), sc_names!(self))
|
||||
{
|
||||
return Err(Error::invalid_subcommand(
|
||||
arg_os.to_string_lossy().into_owned(),
|
||||
cdate,
|
||||
self.meta.bin_name.as_ref().unwrap_or(&self.meta.name),
|
||||
&*usage::create_error_usage(self, matcher, None),
|
||||
self.color(),
|
||||
));
|
||||
}
|
||||
if !(self.is_set(AS::ArgsNegateSubcommands) && self.is_set(AS::ValidArgFound))
|
||||
&& !self.is_set(AS::InferSubcommands)
|
||||
{
|
||||
if let Some(cdate) = suggestions::did_you_mean(&*arg_os.to_string_lossy(), sc_names!(self)) {
|
||||
return Err(Error::invalid_subcommand(
|
||||
arg_os.to_string_lossy().into_owned(),
|
||||
cdate,
|
||||
self.meta.bin_name.as_ref().unwrap_or(&self.meta.name),
|
||||
&*usage::create_error_usage(self, matcher, None),
|
||||
self.color(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1035,7 +1031,29 @@ where
|
|||
self.color(),
|
||||
));
|
||||
}
|
||||
parse_positional!(self, p, arg_os, pos_counter, matcher);
|
||||
if !self.is_set(AS::TrailingValues) &&
|
||||
(self.is_set(AS::TrailingVarArg) &&
|
||||
pos_counter == self.positionals.len()) {
|
||||
self.settings.set(AS::TrailingValues);
|
||||
}
|
||||
if self.cache.map_or(true, |name| name != p.b.name) {
|
||||
{
|
||||
let any_arg = find_any_by_name!(self, self.cache.unwrap_or(""));
|
||||
matcher.process_arg_overrides(any_arg, &mut self.overrides, &mut self.required);
|
||||
}
|
||||
self.cache = Some(p.b.name);
|
||||
}
|
||||
let _ = self.add_val_to_arg(p, &arg_os, matcher)?;
|
||||
|
||||
matcher.inc_occurrence_of(p.b.name);
|
||||
let _ = self.groups_for_arg(p.b.name)
|
||||
.and_then(|vec| Some(matcher.inc_occurrences_of(&*vec)));
|
||||
|
||||
self.settings.set(AS::ValidArgFound);
|
||||
// Only increment the positional counter if it doesn't allow multiples
|
||||
if !p.b.settings.is_set(ArgSettings::Multiple) {
|
||||
pos_counter += 1;
|
||||
}
|
||||
self.settings.set(AS::ValidArgFound);
|
||||
} else if self.is_set(AS::AllowExternalSubcommands) {
|
||||
// Get external subcommand name
|
||||
|
@ -1136,9 +1154,34 @@ where
|
|||
});
|
||||
}
|
||||
|
||||
// In case the last arg was new, we need to process it's overrides
|
||||
{
|
||||
let any_arg = find_any_by_name!(self, self.cache.unwrap_or(""));
|
||||
matcher.process_arg_overrides(any_arg, &mut self.overrides, &mut self.required);
|
||||
}
|
||||
|
||||
self.remove_overrides(matcher);
|
||||
|
||||
Validator::new(self).validate(needs_val_of, subcmd_name, matcher)
|
||||
}
|
||||
|
||||
fn remove_overrides(&mut self, matcher: &mut ArgMatcher) {
|
||||
debugln!("Parser::remove_overrides:{:?};", self.overrides);
|
||||
for &(overr, name) in &self.overrides {
|
||||
debugln!("Parser::remove_overrides:iter:({},{});", overr, name);
|
||||
if matcher.is_present(overr) {
|
||||
debugln!("Parser::remove_overrides:iter:({},{}): removing {};", overr, name, name);
|
||||
matcher.remove(name);
|
||||
for i in (0 .. self.required.len()).rev() {
|
||||
debugln!("Parser::remove_overrides:iter:({},{}): removing required {};", overr, name, name);
|
||||
if self.required[i] == name {
|
||||
self.required.swap_remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn propagate_help_version(&mut self) {
|
||||
debugln!("Parser::propagate_help_version;");
|
||||
|
@ -1483,7 +1526,6 @@ where
|
|||
self.settings.set(AS::ValidArgFound);
|
||||
let ret = self.parse_opt(val, opt, val.is_some(), matcher)?;
|
||||
if self.cache.map_or(true, |name| name != opt.b.name) {
|
||||
arg_post_processing!(self, opt, matcher);
|
||||
self.cache = Some(opt.b.name);
|
||||
}
|
||||
|
||||
|
@ -1501,10 +1543,9 @@ where
|
|||
self.parse_flag(flag, matcher)?;
|
||||
|
||||
// Handle conflicts, requirements, etc.
|
||||
// if self.cache.map_or(true, |name| name != flag.b.name) {
|
||||
arg_post_processing!(self, flag, matcher);
|
||||
// self.cache = Some(flag.b.name);
|
||||
// }
|
||||
if self.cache.map_or(true, |name| name != flag.b.name) {
|
||||
self.cache = Some(flag.b.name);
|
||||
}
|
||||
|
||||
return Ok(ParseResult::Flag);
|
||||
} else if self.is_set(AS::AllowLeadingHyphen) {
|
||||
|
@ -1580,7 +1621,6 @@ where
|
|||
let ret = self.parse_opt(val, opt, false, matcher)?;
|
||||
|
||||
if self.cache.map_or(true, |name| name != opt.b.name) {
|
||||
arg_post_processing!(self, opt, matcher);
|
||||
self.cache = Some(opt.b.name);
|
||||
}
|
||||
|
||||
|
@ -1595,7 +1635,6 @@ where
|
|||
// Handle conflicts, requirements, overrides, etc.
|
||||
// Must be called here due to mutablilty
|
||||
if self.cache.map_or(true, |name| name != flag.b.name) {
|
||||
arg_post_processing!(self, flag, matcher);
|
||||
self.cache = Some(flag.b.name);
|
||||
}
|
||||
} else {
|
||||
|
@ -1844,7 +1883,6 @@ where
|
|||
$_self.add_val_to_arg($a, OsStr::new(val), $m)?;
|
||||
|
||||
if $_self.cache.map_or(true, |name| name != $a.name()) {
|
||||
arg_post_processing!($_self, $a, $m);
|
||||
$_self.cache = Some($a.name());
|
||||
}
|
||||
} else if $m.get($a.b.name).is_some() {
|
||||
|
@ -1855,7 +1893,6 @@ where
|
|||
$_self.add_val_to_arg($a, OsStr::new(val), $m)?;
|
||||
|
||||
if $_self.cache.map_or(true, |name| name != $a.name()) {
|
||||
arg_post_processing!($_self, $a, $m);
|
||||
$_self.cache = Some($a.name());
|
||||
}
|
||||
}
|
||||
|
@ -1881,7 +1918,6 @@ where
|
|||
if add {
|
||||
$_self.add_val_to_arg($a, OsStr::new(default), $m)?;
|
||||
if $_self.cache.map_or(true, |name| name != $a.name()) {
|
||||
arg_post_processing!($_self, $a, $m);
|
||||
$_self.cache = Some($a.name());
|
||||
}
|
||||
done = true;
|
||||
|
@ -1920,7 +1956,6 @@ where
|
|||
$_self.add_val_to_arg($a, OsStr::new(val), $m)?;
|
||||
|
||||
if $_self.cache.map_or(true, |name| name != $a.name()) {
|
||||
arg_post_processing!($_self, $a, $m);
|
||||
$_self.cache = Some($a.name());
|
||||
}
|
||||
}
|
||||
|
@ -1929,7 +1964,6 @@ where
|
|||
$_self.add_val_to_arg($a, OsStr::new(val), $m)?;
|
||||
|
||||
if $_self.cache.map_or(true, |name| name != $a.name()) {
|
||||
arg_post_processing!($_self, $a, $m);
|
||||
$_self.cache = Some($a.name());
|
||||
}
|
||||
}
|
||||
|
@ -1972,7 +2006,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub fn find_any_arg(&self, name: &str) -> Option<&AnyArg> {
|
||||
pub fn find_any_arg(&self, name: &str) -> Option<&AnyArg<'a, 'b>> {
|
||||
if let Some(f) = find_by_name!(self, name, flags, iter) {
|
||||
return Some(f);
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_values<A>(
|
||||
fn validate_arg_values<A>(
|
||||
&self,
|
||||
arg: &A,
|
||||
ma: &MatchedArg,
|
||||
|
@ -87,11 +87,11 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
|||
where
|
||||
A: AnyArg<'a, 'b> + Display,
|
||||
{
|
||||
debugln!("Validator::validate_values: arg={:?}", arg.name());
|
||||
debugln!("Validator::validate_arg_values: arg={:?}", arg.name());
|
||||
for val in &ma.vals {
|
||||
if self.0.is_set(AS::StrictUtf8) && val.to_str().is_none() {
|
||||
debugln!(
|
||||
"Validator::validate_values: invalid UTF-8 found in val {:?}",
|
||||
"Validator::validate_arg_values: invalid UTF-8 found in val {:?}",
|
||||
val
|
||||
);
|
||||
return Err(Error::invalid_utf8(
|
||||
|
@ -100,7 +100,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
|||
));
|
||||
}
|
||||
if let Some(p_vals) = arg.possible_vals() {
|
||||
debugln!("Validator::validate_values: possible_vals={:?}", p_vals);
|
||||
debugln!("Validator::validate_arg_values: possible_vals={:?}", p_vals);
|
||||
let val_str = val.to_string_lossy();
|
||||
let ok = if arg.is_set(ArgSettings::CaseInsensitive) {
|
||||
p_vals.iter().any(|pv| pv.eq_ignore_ascii_case(&*val_str))
|
||||
|
@ -120,7 +120,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
|||
if !arg.is_set(ArgSettings::EmptyValues) && val.is_empty_()
|
||||
&& matcher.contains(&*arg.name())
|
||||
{
|
||||
debugln!("Validator::validate_values: illegal empty val found");
|
||||
debugln!("Validator::validate_arg_values: illegal empty val found");
|
||||
return Err(Error::empty_value(
|
||||
arg,
|
||||
&*usage::create_error_usage(self.0, matcher, None),
|
||||
|
@ -128,7 +128,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
|||
));
|
||||
}
|
||||
if let Some(vtor) = arg.validator() {
|
||||
debug!("Validator::validate_values: checking validator...");
|
||||
debug!("Validator::validate_arg_values: checking validator...");
|
||||
if let Err(e) = vtor(val.to_string_lossy().into_owned()) {
|
||||
sdebugln!("error");
|
||||
return Err(Error::value_validation(Some(arg), e, self.0.color()));
|
||||
|
@ -137,7 +137,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
|||
}
|
||||
}
|
||||
if let Some(vtor) = arg.validator_os() {
|
||||
debug!("Validator::validate_values: checking validator_os...");
|
||||
debug!("Validator::validate_arg_values: checking validator_os...");
|
||||
if let Err(e) = vtor(val) {
|
||||
sdebugln!("error");
|
||||
return Err(Error::value_validation(
|
||||
|
@ -153,44 +153,83 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_blacklist(&self, matcher: &mut ArgMatcher) -> ClapResult<()> {
|
||||
debugln!(
|
||||
"Validator::validate_blacklist: blacklist={:?}",
|
||||
self.0.blacklist
|
||||
fn build_err(&self, name: &str, matcher: &ArgMatcher) -> ClapResult<()> {
|
||||
debugln!("build_err!: name={}", name);
|
||||
let mut c_with = find_from!(self.0, &name, blacklist, &matcher);
|
||||
c_with = c_with.or(
|
||||
self.0.find_any_arg(&name).map_or(None, |aa| aa.blacklist())
|
||||
.map_or(None,
|
||||
|bl| bl.iter().find(|arg| matcher.contains(arg)))
|
||||
.map_or(None, |an| self.0.find_any_arg(an))
|
||||
.map_or(None, |aa| Some(format!("{}", aa)))
|
||||
);
|
||||
macro_rules! build_err {
|
||||
($p:expr, $name:expr, $matcher:ident) => ({
|
||||
debugln!("build_err!: name={}", $name);
|
||||
let mut c_with = find_from!($p, &$name, blacklist, &$matcher);
|
||||
c_with = c_with.or(
|
||||
$p.find_any_arg(&$name).map_or(None, |aa| aa.blacklist())
|
||||
.map_or(None,
|
||||
|bl| bl.iter().find(|arg| $matcher.contains(arg)))
|
||||
.map_or(None, |an| $p.find_any_arg(an))
|
||||
.map_or(None, |aa| Some(format!("{}", aa)))
|
||||
);
|
||||
debugln!("build_err!: '{:?}' conflicts with '{}'", c_with, &$name);
|
||||
$matcher.remove(&$name);
|
||||
let usg = usage::create_error_usage($p, $matcher, None);
|
||||
if let Some(f) = find_by_name!($p, $name, flags, iter) {
|
||||
debugln!("build_err!: It was a flag...");
|
||||
Error::argument_conflict(f, c_with, &*usg, self.0.color())
|
||||
} else if let Some(o) = find_by_name!($p, $name, opts, iter) {
|
||||
debugln!("build_err!: It was an option...");
|
||||
Error::argument_conflict(o, c_with, &*usg, self.0.color())
|
||||
} else {
|
||||
match find_by_name!($p, $name, positionals, values) {
|
||||
Some(p) => {
|
||||
debugln!("build_err!: It was a positional...");
|
||||
Error::argument_conflict(p, c_with, &*usg, self.0.color())
|
||||
},
|
||||
None => panic!(INTERNAL_ERROR_MSG)
|
||||
debugln!("build_err!: '{:?}' conflicts with '{}'", c_with, &name);
|
||||
// matcher.remove(&name);
|
||||
let usg = usage::create_error_usage(self.0, matcher, None);
|
||||
if let Some(f) = find_by_name!(self.0, name, flags, iter) {
|
||||
debugln!("build_err!: It was a flag...");
|
||||
Err(Error::argument_conflict(f, c_with, &*usg, self.0.color()))
|
||||
} else if let Some(o) = find_by_name!(self.0, name, opts, iter) {
|
||||
debugln!("build_err!: It was an option...");
|
||||
Err(Error::argument_conflict(o, c_with, &*usg, self.0.color()))
|
||||
} else {
|
||||
match find_by_name!(self.0, name, positionals, values) {
|
||||
Some(p) => {
|
||||
debugln!("build_err!: It was a positional...");
|
||||
Err(Error::argument_conflict(p, c_with, &*usg, self.0.color()))
|
||||
},
|
||||
None => panic!(INTERNAL_ERROR_MSG)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_blacklist(&self, matcher: &mut ArgMatcher) -> ClapResult<()> {
|
||||
debugln!("Validator::validate_blacklist;");
|
||||
let mut conflicts: Vec<&str> = vec![];
|
||||
for (&name, _) in matcher.iter() {
|
||||
debugln!("Validator::validate_blacklist:iter:{};", name);
|
||||
if let Some(grps) = self.0.groups_for_arg(name) {
|
||||
for grp in &grps {
|
||||
if let Some(g) = self.0.groups.iter().find(|g| &g.name == grp) {
|
||||
if !g.multiple {
|
||||
for arg in &g.args {
|
||||
if arg == &name {
|
||||
continue;
|
||||
}
|
||||
conflicts.push(arg);
|
||||
}
|
||||
}
|
||||
if let Some(ref gc) = g.conflicts {
|
||||
conflicts.extend(&*gc);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if let Some(arg) = find_any_by_name!(self.0, name) {
|
||||
if let Some(bl) = arg.blacklist() {
|
||||
for conf in bl {
|
||||
if matcher.get(conf).is_some() {
|
||||
conflicts.push(conf);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debugln!("Validator::validate_blacklist:iter:{}:group;", name);
|
||||
let args = self.0.arg_names_in_group(name);
|
||||
for arg in &args {
|
||||
debugln!("Validator::validate_blacklist:iter:{}:group:iter:{};", name, arg);
|
||||
if let Some(bl) = find_any_by_name!(self.0, *arg).unwrap().blacklist() {
|
||||
for conf in bl {
|
||||
if matcher.get(conf).is_some() {
|
||||
conflicts.push(conf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for name in &self.0.blacklist {
|
||||
for name in &conflicts {
|
||||
debugln!(
|
||||
"Validator::validate_blacklist:iter:{}: Checking blacklisted arg",
|
||||
name
|
||||
|
@ -213,7 +252,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
|||
name,
|
||||
n
|
||||
);
|
||||
return Err(build_err!(self.0, n, matcher));
|
||||
return self.build_err(n, matcher);
|
||||
}
|
||||
}
|
||||
} else if let Some(ma) = matcher.get(name) {
|
||||
|
@ -224,7 +263,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
|||
should_err = ma.occurs > 0;
|
||||
}
|
||||
if should_err {
|
||||
return Err(build_err!(self.0, *name, matcher));
|
||||
return self.build_err(*name, matcher);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
@ -240,7 +279,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
|||
);
|
||||
if let Some(opt) = find_by_name!(self.0, *name, opts, iter) {
|
||||
self.validate_arg_num_vals(opt, ma, matcher)?;
|
||||
self.validate_values(opt, ma, matcher)?;
|
||||
self.validate_arg_values(opt, ma, matcher)?;
|
||||
self.validate_arg_requires(opt, ma, matcher)?;
|
||||
self.validate_arg_num_occurs(opt, ma, matcher)?;
|
||||
} else if let Some(flag) = find_by_name!(self.0, *name, flags, iter) {
|
||||
|
@ -249,7 +288,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
|||
} else if let Some(pos) = find_by_name!(self.0, *name, positionals, values) {
|
||||
self.validate_arg_num_vals(pos, ma, matcher)?;
|
||||
self.validate_arg_num_occurs(pos, ma, matcher)?;
|
||||
self.validate_values(pos, ma, matcher)?;
|
||||
self.validate_arg_values(pos, ma, matcher)?;
|
||||
self.validate_arg_requires(pos, ma, matcher)?;
|
||||
} else {
|
||||
let grp = self.0
|
||||
|
@ -381,7 +420,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
|||
where
|
||||
A: AnyArg<'a, 'b> + Display,
|
||||
{
|
||||
debugln!("Validator::validate_arg_requires;");
|
||||
debugln!("Validator::validate_arg_requires:{};", a.name());
|
||||
if let Some(a_reqs) = a.requires() {
|
||||
for &(val, name) in a_reqs.iter().filter(|&&(val, _)| val.is_some()) {
|
||||
let missing_req =
|
||||
|
@ -390,6 +429,11 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
|||
return self.missing_required_error(matcher, None);
|
||||
}
|
||||
}
|
||||
for &(_, name) in a_reqs.iter().filter(|&&(val, _)| val.is_none()) {
|
||||
if !matcher.contains(name) {
|
||||
return self.missing_required_error(matcher, Some(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -399,20 +443,13 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
|||
"Validator::validate_required: required={:?};",
|
||||
self.0.required
|
||||
);
|
||||
|
||||
'outer: for name in &self.0.required {
|
||||
debugln!("Validator::validate_required:iter:{}:", name);
|
||||
if matcher.contains(name) {
|
||||
continue 'outer;
|
||||
}
|
||||
if let Some(a) = find_by_name!(self.0, *name, flags, iter) {
|
||||
if self.is_missing_required_ok(a, matcher) {
|
||||
continue 'outer;
|
||||
}
|
||||
} else if let Some(a) = find_by_name!(self.0, *name, opts, iter) {
|
||||
if self.is_missing_required_ok(a, matcher) {
|
||||
continue 'outer;
|
||||
}
|
||||
} else if let Some(a) = find_by_name!(self.0, *name, positionals, values) {
|
||||
if let Some(a) = find_any_by_name!(self.0, *name) {
|
||||
if self.is_missing_required_ok(a, matcher) {
|
||||
continue 'outer;
|
||||
}
|
||||
|
@ -431,11 +468,8 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_conflicts<A>(&self, a: &A, matcher: &ArgMatcher) -> Option<bool>
|
||||
where
|
||||
A: AnyArg<'a, 'b>,
|
||||
{
|
||||
debugln!("Validator::validate_conflicts: a={:?};", a.name());
|
||||
fn validate_arg_conflicts(&self, a: &AnyArg, matcher: &ArgMatcher) -> Option<bool> {
|
||||
debugln!("Validator::validate_arg_conflicts: a={:?};", a.name());
|
||||
a.blacklist().map(|bl| {
|
||||
bl.iter().any(|conf| {
|
||||
matcher.contains(conf)
|
||||
|
@ -448,10 +482,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
|||
})
|
||||
}
|
||||
|
||||
fn validate_required_unless<A>(&self, a: &A, matcher: &ArgMatcher) -> Option<bool>
|
||||
where
|
||||
A: AnyArg<'a, 'b>,
|
||||
{
|
||||
fn validate_required_unless(&self, a: &AnyArg, matcher: &ArgMatcher) -> Option<bool> {
|
||||
debugln!("Validator::validate_required_unless: a={:?};", a.name());
|
||||
macro_rules! check {
|
||||
($how:ident, $_self:expr, $a:ident, $m:ident) => {{
|
||||
|
@ -506,12 +537,9 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn is_missing_required_ok<A>(&self, a: &A, matcher: &ArgMatcher) -> bool
|
||||
where
|
||||
A: AnyArg<'a, 'b>,
|
||||
{
|
||||
fn is_missing_required_ok(&self, a: &AnyArg, matcher: &ArgMatcher) -> bool {
|
||||
debugln!("Validator::is_missing_required_ok: a={}", a.name());
|
||||
self.validate_conflicts(a, matcher).unwrap_or(false)
|
||||
self.validate_arg_conflicts(a, matcher).unwrap_or(false)
|
||||
|| self.validate_required_unless(a, matcher).unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ use std::ffi::{OsStr, OsString};
|
|||
// Internal
|
||||
use args::settings::ArgSettings;
|
||||
use map::{self, VecMap};
|
||||
use INTERNAL_ERROR_MSG;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait AnyArg<'n, 'e>: std_fmt::Display {
|
||||
|
@ -41,3 +42,33 @@ pub trait AnyArg<'n, 'e>: std_fmt::Display {
|
|||
pub trait DispOrder {
|
||||
fn disp_ord(&self) -> usize;
|
||||
}
|
||||
|
||||
impl<'n, 'e, 'z, T: ?Sized> AnyArg<'n, 'e> for &'z T where T: AnyArg<'n, 'e> + 'z {
|
||||
fn name(&self) -> &'n str { (*self).name() }
|
||||
fn overrides(&self) -> Option<&[&'e str]> { (*self).overrides() }
|
||||
fn aliases(&self) -> Option<Vec<&'e str>> { (*self).aliases() }
|
||||
fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> { (*self).requires() }
|
||||
fn blacklist(&self) -> Option<&[&'e str]> { (*self).blacklist() }
|
||||
fn required_unless(&self) -> Option<&[&'e str]> { (*self).required_unless() }
|
||||
fn is_set(&self, a: ArgSettings) -> bool { (*self).is_set(a) }
|
||||
fn set(&mut self, _: ArgSettings) { panic!(INTERNAL_ERROR_MSG) }
|
||||
fn has_switch(&self) -> bool { (*self).has_switch() }
|
||||
fn max_vals(&self) -> Option<u64> { (*self).max_vals() }
|
||||
fn min_vals(&self) -> Option<u64> { (*self).min_vals() }
|
||||
fn num_vals(&self) -> Option<u64> { (*self).num_vals() }
|
||||
fn possible_vals(&self) -> Option<&[&'e str]> { (*self).possible_vals() }
|
||||
fn validator(&self) -> Option<&Rc<Fn(String) -> Result<(), String>>> { (*self).validator() }
|
||||
fn validator_os(&self) -> Option<&Rc<Fn(&OsStr) -> Result<(), OsString>>> { (*self).validator_os() }
|
||||
fn short(&self) -> Option<char> { (*self).short() }
|
||||
fn long(&self) -> Option<&'e str> { (*self).long() }
|
||||
fn val_delim(&self) -> Option<char> { (*self).val_delim() }
|
||||
fn takes_value(&self) -> bool { (*self).takes_value() }
|
||||
fn val_names(&self) -> Option<&VecMap<&'e str>> { (*self).val_names() }
|
||||
fn help(&self) -> Option<&'e str> { (*self).help() }
|
||||
fn long_help(&self) -> Option<&'e str> { (*self).long_help() }
|
||||
fn default_val(&self) -> Option<&'e OsStr> { (*self).default_val() }
|
||||
fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> { (*self).default_vals_ifs() }
|
||||
fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> { (*self).env() }
|
||||
fn longest_filter(&self) -> bool { (*self).longest_filter() }
|
||||
fn val_terminator(&self) -> Option<&'e str> { (*self).val_terminator() }
|
||||
}
|
||||
|
|
|
@ -21,11 +21,36 @@ impl<'a> Default for ArgMatcher<'a> {
|
|||
impl<'a> ArgMatcher<'a> {
|
||||
pub fn new() -> Self { ArgMatcher::default() }
|
||||
|
||||
pub fn process_arg_overrides<'b>(&mut self, a: Option<&AnyArg<'a, 'b>>, overrides: &mut Vec<(&'b str, &'a str)>, required: &mut Vec<&'a str>) {
|
||||
debugln!("ArgMatcher::process_arg_overrides:{:?};", a.map_or(None, |a| Some(a.name())));
|
||||
if let Some(aa) = a {
|
||||
if let Some(a_overrides) = aa.overrides() {
|
||||
for overr in a_overrides {
|
||||
debugln!("ArgMatcher::process_arg_overrides:iter:{};", overr);
|
||||
if self.is_present(overr) {
|
||||
debugln!("ArgMatcher::process_arg_overrides:iter:{}: removing from matches;", overr);
|
||||
self.remove(overr);
|
||||
for i in (0 .. required.len()).rev() {
|
||||
if &required[i] == overr {
|
||||
debugln!("ArgMatcher::process_arg_overrides:iter:{}: removing required;", overr);
|
||||
required.swap_remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
overrides.push((overr, aa.name()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_present(&self, name: &str) -> bool {
|
||||
self.0.is_present(name)
|
||||
}
|
||||
|
||||
pub fn propagate_globals(&mut self, global_arg_vec: &[&'a str]) {
|
||||
debugln!(
|
||||
"ArgMatcher::get_global_values: global_arg_vec={:?}",
|
||||
global_arg_vec
|
||||
);
|
||||
debugln!( "ArgMatcher::get_global_values: global_arg_vec={:?}", global_arg_vec );
|
||||
let mut vals_map = HashMap::new();
|
||||
self.fill_in_global_values(global_arg_vec, &mut vals_map);
|
||||
}
|
||||
|
|
|
@ -853,15 +853,15 @@ macro_rules! write_nspaces {
|
|||
}
|
||||
|
||||
// convenience macro for remove an item from a vec
|
||||
macro_rules! vec_remove_all {
|
||||
($vec:expr, $to_rem:expr) => {
|
||||
debugln!("vec_remove_all! to_rem={:?}", $to_rem);
|
||||
for i in (0 .. $vec.len()).rev() {
|
||||
let should_remove = $to_rem.any(|name| name == &$vec[i]);
|
||||
if should_remove { $vec.swap_remove(i); }
|
||||
}
|
||||
};
|
||||
}
|
||||
//macro_rules! vec_remove_all {
|
||||
// ($vec:expr, $to_rem:expr) => {
|
||||
// debugln!("vec_remove_all! to_rem={:?}", $to_rem);
|
||||
// for i in (0 .. $vec.len()).rev() {
|
||||
// let should_remove = $to_rem.any(|name| name == &$vec[i]);
|
||||
// if should_remove { $vec.swap_remove(i); }
|
||||
// }
|
||||
// };
|
||||
//}
|
||||
macro_rules! find_from {
|
||||
($_self:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{
|
||||
let mut ret = None;
|
||||
|
@ -892,36 +892,49 @@ macro_rules! find_from {
|
|||
}};
|
||||
}
|
||||
|
||||
macro_rules! find_name_from {
|
||||
($_self:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{
|
||||
let mut ret = None;
|
||||
for k in $matcher.arg_names() {
|
||||
if let Some(f) = find_by_name!($_self, k, flags, iter) {
|
||||
if let Some(ref v) = f.$from() {
|
||||
if v.contains($arg_name) {
|
||||
ret = Some(f.b.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(o) = find_by_name!($_self, k, opts, iter) {
|
||||
if let Some(ref v) = o.$from() {
|
||||
if v.contains(&$arg_name) {
|
||||
ret = Some(o.b.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(pos) = find_by_name!($_self, k, positionals, values) {
|
||||
if let Some(ref v) = pos.$from() {
|
||||
if v.contains($arg_name) {
|
||||
ret = Some(pos.b.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ret
|
||||
}};
|
||||
}
|
||||
//macro_rules! find_name_from {
|
||||
// ($_self:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{
|
||||
// let mut ret = None;
|
||||
// for k in $matcher.arg_names() {
|
||||
// if let Some(f) = find_by_name!($_self, k, flags, iter) {
|
||||
// if let Some(ref v) = f.$from() {
|
||||
// if v.contains($arg_name) {
|
||||
// ret = Some(f.b.name);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if let Some(o) = find_by_name!($_self, k, opts, iter) {
|
||||
// if let Some(ref v) = o.$from() {
|
||||
// if v.contains(&$arg_name) {
|
||||
// ret = Some(o.b.name);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if let Some(pos) = find_by_name!($_self, k, positionals, values) {
|
||||
// if let Some(ref v) = pos.$from() {
|
||||
// if v.contains($arg_name) {
|
||||
// ret = Some(pos.b.name);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// ret
|
||||
// }};
|
||||
//}
|
||||
|
||||
|
||||
macro_rules! find_any_by_name {
|
||||
($p:expr, $name:expr) => {
|
||||
{
|
||||
fn as_trait_obj<'a, 'b, T: AnyArg<'a, 'b>>(x: &T) -> &AnyArg<'a, 'b> { x }
|
||||
find_by_name!($p, $name, flags, iter).map(as_trait_obj).or(
|
||||
find_by_name!($p, $name, opts, iter).map(as_trait_obj).or(
|
||||
find_by_name!($p, $name, positionals, values).map(as_trait_obj)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Finds an arg by name
|
||||
macro_rules! find_by_name {
|
||||
($p:expr, $name:expr, $what:ident, $how:ident) => {
|
||||
|
|
Loading…
Reference in a new issue