From 417f1a9813e28af026be68bf84eed6f7138a659b Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 16 Sep 2022 14:29:26 -0500 Subject: [PATCH 1/8] fix(derive): Read CARGO_PKG_NAME at runtime This was broken in #4168 --- clap_derive/src/derives/parser.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/clap_derive/src/derives/parser.rs b/clap_derive/src/derives/parser.rs index 5518fde7ff7..617857cacaa 100644 --- a/clap_derive/src/derives/parser.rs +++ b/clap_derive/src/derives/parser.rs @@ -29,6 +29,7 @@ use crate::item::Name; pub fn derive_parser(input: &DeriveInput) -> TokenStream { let ident = &input.ident; + let pkg_name = std::env::var("CARGO_PKG_NAME").ok().unwrap_or_default(); match input.data { Data::Struct(DataStruct { @@ -37,9 +38,7 @@ pub fn derive_parser(input: &DeriveInput) -> TokenStream { }) => { dummies::parser_struct(ident); - let name = Name::Assigned(quote!(std::env::var("CARGO_PKG_NAME") - .ok() - .unwrap_or_default())); + let name = Name::Assigned(quote!(#pkg_name)); let item = Item::from_args_struct(input, name); let fields = fields .named @@ -57,9 +56,7 @@ pub fn derive_parser(input: &DeriveInput) -> TokenStream { }) => { dummies::parser_struct(ident); - let name = Name::Assigned(quote!(std::env::var("CARGO_PKG_NAME") - .ok() - .unwrap_or_default())); + let name = Name::Assigned(quote!(#pkg_name)); let item = Item::from_args_struct(input, name); let fields = Punctuated::::new(); let fields = fields @@ -74,9 +71,7 @@ pub fn derive_parser(input: &DeriveInput) -> TokenStream { Data::Enum(ref e) => { dummies::parser_enum(ident); - let name = Name::Assigned(quote!(std::env::var("CARGO_PKG_NAME") - .ok() - .unwrap_or_default())); + let name = Name::Assigned(quote!(#pkg_name)); let item = Item::from_subcommand_enum(input, name); let variants = e .variants From 14c6ce0e838ef8d84c896254f02716e9e3c57c50 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 16 Sep 2022 15:26:34 -0500 Subject: [PATCH 2/8] fix(derive): Remove next_help_heading isolation Originally, I saw the ideal as the parent command being isolated from `#[clap(flatte)]` especially after all of the doc comment leakage issues. We scaled that back to just `next_help_heading` because of the issues with settling on a policy and maintenance to cover everything. When doing `next_display_order`, we decided it would mess things up too much to isolate it. With #1807, we instead have been moving towards setting `#[command(next_help_heading)]` anywhere, we just need to finish working out how it should work. --- CHANGELOG.md | 1 + clap_derive/src/derives/args.rs | 5 ----- clap_derive/src/derives/subcommand.rs | 5 ----- tests/derive/help.rs | 4 ++-- 4 files changed, 3 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9495823ce1a..3882a4451ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -229,6 +229,7 @@ Easier to catch changes: - `#[clap(value_parser)]` and `#[clap(action)]` are now redundant - *(derive)* `subcommand_required(true).arg_required_else_help(true)` is set instead of `SubcommandRequiredElseHelp` to give more meaningful errors when subcommands are missing and to reduce redundancy (#3280) - *(derive)* Remove `arg_enum` attribute in favor of `value_enum` to match the new name (we didn't have support in v3 to mark it deprecated) (#4127) +- *(derive)* `next_help_heading` can now leak out of a `#[clap(flatten)]`, like all other command settings - *(parser)* Assert when the CLI looksup an unknown args when external subcommand support is enabled to help catch bugs (#3703) - *(assert)* Sometimes `Arg::default_missing_value` didn't require `num_args(0..=N)`, now it does (#4023) - *(assert)* Leading dashes in `Arg::long` are no longer allowed (#3691) diff --git a/clap_derive/src/derives/args.rs b/clap_derive/src/derives/args.rs index 02cb052351b..c136d21d16d 100644 --- a/clap_derive/src/derives/args.rs +++ b/clap_derive/src/derives/args.rs @@ -194,26 +194,21 @@ pub fn gen_augment( } Kind::Flatten => { let ty = &field.ty; - let old_heading_var = format_ident!("__clap_old_heading"); let next_help_heading = item.next_help_heading(); let next_display_order = item.next_display_order(); if override_required { Some(quote_spanned! { kind.span()=> - let #old_heading_var = #app_var.get_next_help_heading().map(|s| clap::builder::Str::from(s.to_owned())); let #app_var = #app_var #next_help_heading #next_display_order; let #app_var = <#ty as clap::Args>::augment_args_for_update(#app_var); - let #app_var = #app_var.next_help_heading(clap::builder::Resettable::from(#old_heading_var)); }) } else { Some(quote_spanned! { kind.span()=> - let #old_heading_var = #app_var.get_next_help_heading().map(|s| clap::builder::Str::from(s.to_owned())); let #app_var = #app_var #next_help_heading #next_display_order; let #app_var = <#ty as clap::Args>::augment_args(#app_var); - let #app_var = #app_var.next_help_heading(clap::builder::Resettable::from(#old_heading_var)); }) } } diff --git a/clap_derive/src/derives/subcommand.rs b/clap_derive/src/derives/subcommand.rs index d55b669fc8f..1989e82fded 100644 --- a/clap_derive/src/derives/subcommand.rs +++ b/clap_derive/src/derives/subcommand.rs @@ -181,28 +181,23 @@ fn gen_augment( } else { quote!() }; - let old_heading_var = format_ident!("__clap_old_heading"); let next_help_heading = item.next_help_heading(); let next_display_order = item.next_display_order(); let subcommand = if override_required { quote! { #deprecations - let #old_heading_var = #app_var.get_next_help_heading().map(|s| clap::builder::Str::from(s.to_owned())); let #app_var = #app_var #next_help_heading #next_display_order; let #app_var = <#ty as clap::Subcommand>::augment_subcommands_for_update(#app_var); - let #app_var = #app_var.next_help_heading(clap::builder::Resettable::from(#old_heading_var)); } } else { quote! { #deprecations - let #old_heading_var = #app_var.get_next_help_heading().map(|s| clap::builder::Str::from(s.to_owned())); let #app_var = #app_var #next_help_heading #next_display_order; let #app_var = <#ty as clap::Subcommand>::augment_subcommands(#app_var); - let #app_var = #app_var.next_help_heading(clap::builder::Resettable::from(#old_heading_var)); } }; Some(subcommand) diff --git a/tests/derive/help.rs b/tests/derive/help.rs index dc925d74ce1..65861e4ac03 100644 --- a/tests/derive/help.rs +++ b/tests/derive/help.rs @@ -131,11 +131,11 @@ fn app_help_heading_flattened() { .unwrap(); assert_eq!(should_be_in_section_b.get_help_heading(), Some("HEADING B")); - let should_be_in_default_section = cmd + let should_be_in_section_b = cmd .get_arguments() .find(|a| a.get_id() == "should_be_in_default_section") .unwrap(); - assert_eq!(should_be_in_default_section.get_help_heading(), None); + assert_eq!(should_be_in_section_b.get_help_heading(), Some("HEADING B")); let sub_a_two = cmd.find_subcommand("sub-a-two").unwrap(); From dbf2c86995bc2ac9fc28bb4fe67c4ec7caffb0e4 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 16 Sep 2022 11:23:31 -0500 Subject: [PATCH 3/8] perf: Misc simplifications for code size This dropped a fraction of a KiB but it will at least not cause people to ask if it'd help to simplify in the future. --- src/builder/arg.rs | 10 +++++----- src/builder/command.rs | 20 ++++++-------------- src/mkeymap.rs | 5 ----- 3 files changed, 11 insertions(+), 24 deletions(-) diff --git a/src/builder/arg.rs b/src/builder/arg.rs index 4f42926c72d..73ead55d881 100644 --- a/src/builder/arg.rs +++ b/src/builder/arg.rs @@ -146,7 +146,7 @@ impl Arg { #[must_use] pub fn short(mut self, s: impl IntoResettable) -> Self { if let Some(s) = s.into_resettable().into_option() { - assert!(s != '-', "short option name cannot be `-`"); + debug_assert!(s != '-', "short option name cannot be `-`"); self.short = Some(s); } else { self.short = None; @@ -241,7 +241,7 @@ impl Arg { #[must_use] pub fn short_alias(mut self, name: impl IntoResettable) -> Self { if let Some(name) = name.into_resettable().into_option() { - assert!(name != '-', "short alias name cannot be `-`"); + debug_assert!(name != '-', "short alias name cannot be `-`"); self.short_aliases.push((name, false)); } else { self.short_aliases.clear(); @@ -301,7 +301,7 @@ impl Arg { #[must_use] pub fn short_aliases(mut self, names: impl IntoIterator) -> Self { for s in names { - assert!(s != '-', "short alias name cannot be `-`"); + debug_assert!(s != '-', "short alias name cannot be `-`"); self.short_aliases.push((s, false)); } self @@ -357,7 +357,7 @@ impl Arg { #[must_use] pub fn visible_short_alias(mut self, name: impl IntoResettable) -> Self { if let Some(name) = name.into_resettable().into_option() { - assert!(name != '-', "short alias name cannot be `-`"); + debug_assert!(name != '-', "short alias name cannot be `-`"); self.short_aliases.push((name, true)); } else { self.short_aliases.clear(); @@ -412,7 +412,7 @@ impl Arg { #[must_use] pub fn visible_short_aliases(mut self, names: impl IntoIterator) -> Self { for n in names { - assert!(n != '-', "short alias name cannot be `-`"); + debug_assert!(n != '-', "short alias name cannot be `-`"); self.short_aliases.push((n, true)); } self diff --git a/src/builder/command.rs b/src/builder/command.rs index ac834d46a8a..8fa40b99adf 100644 --- a/src/builder/command.rs +++ b/src/builder/command.rs @@ -195,10 +195,6 @@ impl Command { /// [arguments]: Arg #[must_use] pub fn args(mut self, args: impl IntoIterator>) -> Self { - let args = args.into_iter(); - let (lower, _) = args.size_hint(); - self.args.reserve(lower); - for arg in args { self = self.arg(arg); } @@ -407,10 +403,6 @@ impl Command { /// [`IntoIterator`]: std::iter::IntoIterator #[must_use] pub fn subcommands(mut self, subcmds: impl IntoIterator>) -> Self { - let subcmds = subcmds.into_iter(); - let (lower, _) = subcmds.size_hint(); - self.subcommands.reserve(lower); - for subcmd in subcmds { self = self.subcommand(subcmd); } @@ -2219,7 +2211,7 @@ impl Command { #[must_use] pub fn short_flag_alias(mut self, name: impl IntoResettable) -> Self { if let Some(name) = name.into_resettable().into_option() { - assert!(name != '-', "short alias name cannot be `-`"); + debug_assert!(name != '-', "short alias name cannot be `-`"); self.short_flag_aliases.push((name, false)); } else { self.short_flag_aliases.clear(); @@ -2310,7 +2302,7 @@ impl Command { #[must_use] pub fn short_flag_aliases(mut self, names: impl IntoIterator) -> Self { for s in names { - assert!(s != '-', "short alias name cannot be `-`"); + debug_assert!(s != '-', "short alias name cannot be `-`"); self.short_flag_aliases.push((s, false)); } self @@ -2402,7 +2394,7 @@ impl Command { #[must_use] pub fn visible_short_flag_alias(mut self, name: impl IntoResettable) -> Self { if let Some(name) = name.into_resettable().into_option() { - assert!(name != '-', "short alias name cannot be `-`"); + debug_assert!(name != '-', "short alias name cannot be `-`"); self.short_flag_aliases.push((name, true)); } else { self.short_flag_aliases.clear(); @@ -2491,7 +2483,7 @@ impl Command { #[must_use] pub fn visible_short_flag_aliases(mut self, names: impl IntoIterator) -> Self { for s in names { - assert!(s != '-', "short alias name cannot be `-`"); + debug_assert!(s != '-', "short alias name cannot be `-`"); self.short_flag_aliases.push((s, true)); } self @@ -4041,7 +4033,7 @@ impl Command { .map(|arg| arg.get_id().clone()) .collect(); - assert!(args_missing_help.is_empty(), + debug_assert!(args_missing_help.is_empty(), "Command::help_expected is enabled for the Command {}, but at least one of its arguments does not have either `help` or `long_help` set. List of such arguments: {}", self.name, args_missing_help.join(", ") @@ -4299,7 +4291,7 @@ impl Command { #[inline] pub(crate) fn contains_short(&self, s: char) -> bool { - assert!( + debug_assert!( self.is_set(AppSettings::Built), "If Command::_build hasn't been called, manually search through Arg shorts" ); diff --git a/src/mkeymap.rs b/src/mkeymap.rs index 82a82e1f800..a54fae455c0 100644 --- a/src/mkeymap.rs +++ b/src/mkeymap.rs @@ -90,11 +90,6 @@ impl MKeyMap { self.keys.iter().any(|x| x.key == key) } - /// Reserves capacity for at least additional more elements to be inserted - pub(crate) fn reserve(&mut self, additional: usize) { - self.args.reserve(additional); - } - /// Push an argument in the map. pub(crate) fn push(&mut self, new_arg: Arg) { self.args.push(new_arg); From acb0fb780978d30b70e2d3a3921352e45677f98b Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 16 Sep 2022 11:54:02 -0500 Subject: [PATCH 4/8] fix: Generalize `mut_arg`, like `mut_subcommand` This makes us accept `str` and not do any allocations at the cost of panicing if unsupported which I think fits our overall story in trying to catch development-time errors. --- CHANGELOG.md | 1 + src/builder/command.rs | 19 ++++++++++++++----- tests/builder/version.rs | 8 ++------ 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3882a4451ac..55b5b59a391 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -239,6 +239,7 @@ Easier to catch changes: - *(assert)* Ensure `overrides_with` IDs are valid - *(assert)* Ensure no self-`overrides_with` now that Actions replace it - *(assert)* Ensure subcommand names are not duplicated +- *(assert)* Assert on `mut_arg` receiving an invalid arg ID or `mut_subcommand` receiving an invalid command name ### Compatibility diff --git a/src/builder/command.rs b/src/builder/command.rs index 8fa40b99adf..c69b108ac20 100644 --- a/src/builder/command.rs +++ b/src/builder/command.rs @@ -205,6 +205,10 @@ impl Command { /// /// This can be useful for modifying the auto-generated help or version arguments. /// + /// # Panics + /// + /// If the argument is undefined + /// /// # Examples /// /// ```rust @@ -227,15 +231,16 @@ impl Command { /// assert!(res.is_ok()); /// ``` #[must_use] - pub fn mut_arg(mut self, arg_id: impl Into, f: F) -> Self + #[cfg_attr(debug_assertions, track_caller)] + pub fn mut_arg(mut self, arg_id: impl AsRef, f: F) -> Self where F: FnOnce(Arg) -> Arg, { - let id = arg_id.into(); + let id = arg_id.as_ref(); let a = self .args - .remove_by_name(id.as_str()) - .unwrap_or_else(|| Arg::new(id)); + .remove_by_name(id) + .unwrap_or_else(|| panic!("Argument `{}` is undefined", id)); self.args.push(f(a)); self @@ -246,6 +251,10 @@ impl Command { /// This can be useful for modifying auto-generated arguments of nested subcommands with /// [`Command::mut_arg`]. /// + /// # Panics + /// + /// If the subcommand is undefined + /// /// # Examples /// /// ```rust @@ -275,7 +284,7 @@ impl Command { let subcmd = if let Some(idx) = pos { self.subcommands.remove(idx) } else { - Self::new(Str::from(name.to_owned())) + panic!("Command `{}` is undefined", name) }; self.subcommands.push(f(subcmd)); diff --git a/tests/builder/version.rs b/tests/builder/version.rs index 2b05582d1df..d13f8121e7e 100644 --- a/tests/builder/version.rs +++ b/tests/builder/version.rs @@ -291,13 +291,9 @@ fn version_required() { } #[test] +#[should_panic = "Argument `version` is undefined"] fn mut_arg_version_no_auto_version() { - let res = common() - .mut_arg("version", |v| v.short('z').action(ArgAction::SetTrue)) - .try_get_matches_from("foo -z".split(' ')); - - assert!(res.is_ok(), "{}", res.unwrap_err()); - assert_eq!(res.unwrap().get_one::("version").copied(), Some(true)); + let _ = common().mut_arg("version", |v| v.short('z').action(ArgAction::SetTrue)); } #[cfg(debug_assertions)] From 3cadb8f2559ac162e54e86bdc362e223374d3d69 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 16 Sep 2022 16:14:01 -0500 Subject: [PATCH 5/8] docs(tutorial): Provide better default_value_t example --- examples/tutorial_builder/03_05_default_values.md | 10 +++++----- examples/tutorial_builder/03_05_default_values.rs | 12 ++++++++---- examples/tutorial_derive/03_05_default_values.md | 10 +++++----- examples/tutorial_derive/03_05_default_values.rs | 6 +++--- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/examples/tutorial_builder/03_05_default_values.md b/examples/tutorial_builder/03_05_default_values.md index 9954f3adbae..96880f16972 100644 --- a/examples/tutorial_builder/03_05_default_values.md +++ b/examples/tutorial_builder/03_05_default_values.md @@ -2,19 +2,19 @@ $ 03_05_default_values --help A simple to use, efficient, and full-featured Command Line Argument Parser -Usage: 03_05_default_values[EXE] [NAME] +Usage: 03_05_default_values[EXE] [PORT] Arguments: - [NAME] [default: alice] + [PORT] [default: 2020] Options: -h, --help Print help information -V, --version Print version information $ 03_05_default_values -name: "alice" +port: 2020 -$ 03_05_default_values bob -name: "bob" +$ 03_05_default_values 22 +port: 22 ``` diff --git a/examples/tutorial_builder/03_05_default_values.rs b/examples/tutorial_builder/03_05_default_values.rs index b11042c352b..d259ee06edf 100644 --- a/examples/tutorial_builder/03_05_default_values.rs +++ b/examples/tutorial_builder/03_05_default_values.rs @@ -1,14 +1,18 @@ -use clap::{arg, command}; +use clap::{arg, command, value_parser}; fn main() { let matches = command!() // requires `cargo` feature - .arg(arg!([NAME]).default_value("alice")) + .arg( + arg!([PORT]) + .value_parser(value_parser!(u16)) + .default_value("2020"), + ) .get_matches(); println!( - "name: {:?}", + "port: {:?}", matches - .get_one::("NAME") + .get_one::("PORT") .expect("default ensures there is always a value") ); } diff --git a/examples/tutorial_derive/03_05_default_values.md b/examples/tutorial_derive/03_05_default_values.md index 9c124b67f68..194f54fb832 100644 --- a/examples/tutorial_derive/03_05_default_values.md +++ b/examples/tutorial_derive/03_05_default_values.md @@ -2,19 +2,19 @@ $ 03_05_default_values_derive --help A simple to use, efficient, and full-featured Command Line Argument Parser -Usage: 03_05_default_values_derive[EXE] [NAME] +Usage: 03_05_default_values_derive[EXE] [PORT] Arguments: - [NAME] [default: alice] + [PORT] [default: 2020] Options: -h, --help Print help information -V, --version Print version information $ 03_05_default_values_derive -name: "alice" +port: 2020 -$ 03_05_default_values_derive bob -name: "bob" +$ 03_05_default_values_derive 22 +port: 22 ``` diff --git a/examples/tutorial_derive/03_05_default_values.rs b/examples/tutorial_derive/03_05_default_values.rs index c49a42187f6..bc33a931abc 100644 --- a/examples/tutorial_derive/03_05_default_values.rs +++ b/examples/tutorial_derive/03_05_default_values.rs @@ -3,12 +3,12 @@ use clap::Parser; #[derive(Parser)] #[command(author, version, about, long_about = None)] struct Cli { - #[arg(default_value_t = String::from("alice"))] - name: String, + #[arg(default_value_t = 2020)] + port: u16, } fn main() { let cli = Cli::parse(); - println!("name: {:?}", cli.name); + println!("port: {:?}", cli.port); } From 4869c43612bc36783f4981708d2c5e01a70ef7c7 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 16 Sep 2022 11:55:08 -0500 Subject: [PATCH 6/8] refactor: Simplify help subtree creation --- src/builder/command.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/builder/command.rs b/src/builder/command.rs index c69b108ac20..c659e22c4af 100644 --- a/src/builder/command.rs +++ b/src/builder/command.rs @@ -4217,7 +4217,7 @@ impl Command { } fn _copy_subtree_for_help(&self) -> Command { - let mut cmd = Command::new(self.get_name().to_string()) + let mut cmd = Command::new(self.name.clone()) .hide(self.is_hide_set()) .global_setting(AppSettings::DisableHelpFlag) .global_setting(AppSettings::DisableVersionFlag) From af9e1b97639c899093671e4b207c24dd2d248757 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 16 Sep 2022 11:59:10 -0500 Subject: [PATCH 7/8] refactor(parser): Don't throwaway work --- src/parser/matches/arg_matches.rs | 6 +++--- src/util/flat_map.rs | 13 +++++++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/parser/matches/arg_matches.rs b/src/parser/matches/arg_matches.rs index d9664add155..2d93e92d8ed 100644 --- a/src/parser/matches/arg_matches.rs +++ b/src/parser/matches/arg_matches.rs @@ -1060,8 +1060,8 @@ impl ArgMatches { arg: &str, ) -> Result, MatchesError> { self.verify_arg(arg)?; - let matched = match self.args.remove(arg) { - Some(matched) => matched, + let (id, matched) = match self.args.remove_entry(arg) { + Some((id, matched)) => (id, matched), None => { return Ok(None); } @@ -1072,7 +1072,7 @@ impl ArgMatches { if actual == expected { Ok(Some(matched)) } else { - self.args.insert(Id::from(arg.to_owned()), matched); + self.args.insert(id, matched); Err(MatchesError::Downcast { actual, expected }) } } diff --git a/src/util/flat_map.rs b/src/util/flat_map.rs index 07e418bf28b..ce5b0fb3f1d 100644 --- a/src/util/flat_map.rs +++ b/src/util/flat_map.rs @@ -53,6 +53,14 @@ impl FlatMap { } pub fn remove(&mut self, key: &Q) -> Option + where + K: Borrow, + Q: std::hash::Hash + Eq, + { + self.remove_entry(key).map(|(_, v)| v) + } + + pub fn remove_entry(&mut self, key: &Q) -> Option<(K, V)> where K: Borrow, Q: std::hash::Hash + Eq, @@ -62,8 +70,9 @@ impl FlatMap { .iter() .enumerate() .find_map(|(i, k)| (k.borrow() == key).then(|| i))?; - self.keys.remove(index); - Some(self.values.remove(index)) + let key = self.keys.remove(index); + let value = self.values.remove(index); + Some((key, value)) } pub(crate) fn is_empty(&self) -> bool { From 86b2fe5a2d048cdcf7fa90b326f6cb598f65d371 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 16 Sep 2022 12:08:13 -0500 Subject: [PATCH 8/8] refactor(parser): Reduce work when validating args --- src/parser/arg_matcher.rs | 2 +- src/parser/matches/arg_matches.rs | 14 +++++--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/parser/arg_matcher.rs b/src/parser/arg_matcher.rs index 875c9241479..071e3b272db 100644 --- a/src/parser/arg_matcher.rs +++ b/src/parser/arg_matcher.rs @@ -32,7 +32,7 @@ impl ArgMatcher { #[cfg(debug_assertions)] valid_subcommands: _cmd .get_subcommands() - .map(|sc| sc.get_name().to_owned()) + .map(|sc| sc.get_name_str().clone()) .collect(), ..Default::default() }, diff --git a/src/parser/matches/arg_matches.rs b/src/parser/matches/arg_matches.rs index 2d93e92d8ed..cfbae26ef1f 100644 --- a/src/parser/matches/arg_matches.rs +++ b/src/parser/matches/arg_matches.rs @@ -66,7 +66,7 @@ pub struct ArgMatches { #[cfg(debug_assertions)] pub(crate) valid_args: Vec, #[cfg(debug_assertions)] - pub(crate) valid_subcommands: Vec, + pub(crate) valid_subcommands: Vec, pub(crate) args: FlatMap, pub(crate) subcommand: Option>, } @@ -924,8 +924,7 @@ impl ArgMatches { pub fn is_valid_subcommand(&self, _name: &str) -> bool { #[cfg(debug_assertions)] { - let _name = _name.to_owned(); - _name == String::default() || self.valid_subcommands.contains(&_name) + _name.is_empty() || self.valid_subcommands.iter().any(|s| *s == _name) } #[cfg(not(debug_assertions))] { @@ -1094,8 +1093,7 @@ impl ArgMatches { fn verify_arg(&self, _arg: &str) -> Result<(), MatchesError> { #[cfg(debug_assertions)] { - let _arg = Id::from(_arg.to_owned()); - if _arg == Id::EXTERNAL || self.valid_args.contains(&_arg) { + if _arg == Id::EXTERNAL || self.valid_args.iter().any(|s| *s == _arg) { } else { debug!( "`{:?}` is not an id of an argument or a group.\n\ @@ -1114,8 +1112,7 @@ impl ArgMatches { fn get_arg<'s>(&'s self, arg: &str) -> Option<&'s MatchedArg> { #[cfg(debug_assertions)] { - let arg = Id::from(arg.to_owned()); - if arg == Id::EXTERNAL || self.valid_args.contains(&arg) { + if arg == Id::EXTERNAL || self.valid_args.iter().any(|s| *s == arg) { } else { panic!( "`{:?}` is not an id of an argument or a group.\n\ @@ -1134,8 +1131,7 @@ impl ArgMatches { fn get_subcommand(&self, name: &str) -> Option<&SubCommand> { #[cfg(debug_assertions)] { - let name = name.to_owned(); - if name == String::default() || self.valid_subcommands.contains(&name) { + if name.is_empty() || self.valid_subcommands.iter().any(|s| *s == name) { } else { panic!("`{}` is not a name of a subcommand.", name); }