From 480035ac9c36490c4cccbf09e71b0ae84a6d527b Mon Sep 17 00:00:00 2001 From: ModProg Date: Wed, 29 Sep 2021 18:05:19 +0200 Subject: [PATCH] ArgEnum: Slice instead of array, from_str in ArgEnum implemented --- clap_derive/examples/arg_enum.rs | 2 +- clap_derive/examples/value_hints_derive.rs | 2 +- clap_derive/src/derives/arg_enum.rs | 23 +++------------ clap_derive/src/derives/args.rs | 2 +- clap_derive/tests/arg_enum.rs | 34 ++++++++++++---------- src/derive.rs | 16 ++++++---- 6 files changed, 37 insertions(+), 42 deletions(-) diff --git a/clap_derive/examples/arg_enum.rs b/clap_derive/examples/arg_enum.rs index b2bd93c24e8..e5ca96230d3 100644 --- a/clap_derive/examples/arg_enum.rs +++ b/clap_derive/examples/arg_enum.rs @@ -4,7 +4,7 @@ use clap::{ArgEnum, Clap}; -#[derive(ArgEnum, Debug, PartialEq)] +#[derive(ArgEnum, Debug, PartialEq, Clone)] enum ArgChoice { /// Descriptions are supported as doc-comment Foo, diff --git a/clap_derive/examples/value_hints_derive.rs b/clap_derive/examples/value_hints_derive.rs index 0ecca5fb325..d0be2c00e82 100644 --- a/clap_derive/examples/value_hints_derive.rs +++ b/clap_derive/examples/value_hints_derive.rs @@ -19,7 +19,7 @@ use std::ffi::OsString; use std::io; use std::path::PathBuf; -#[derive(ArgEnum, Debug, PartialEq)] +#[derive(ArgEnum, Debug, PartialEq, Clone)] enum GeneratorChoice { Bash, Elvish, diff --git a/clap_derive/src/derives/arg_enum.rs b/clap_derive/src/derives/arg_enum.rs index 1211e829049..8d6a878f095 100644 --- a/clap_derive/src/derives/arg_enum.rs +++ b/clap_derive/src/derives/arg_enum.rs @@ -48,7 +48,6 @@ pub fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> TokenStr let lits = lits(&e.variants, &attrs); let arg_values = gen_arg_values(&lits); - let from_str = gen_from_str(&lits); let arg_value = gen_arg_value(&lits); quote! { @@ -66,7 +65,6 @@ pub fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> TokenStr #[deny(clippy::correctness)] impl clap::ArgEnum for #name { #arg_values - #from_str #arg_value } } @@ -102,24 +100,11 @@ fn lits( } fn gen_arg_values(lits: &[(TokenStream, Ident)]) -> TokenStream { - let lit = lits.iter().map(|l| &l.0).collect::>(); + let lit = lits.iter().map(|l| &l.1).collect::>(); quote! { - fn arg_values() -> Vec> { - vec![#(#lit),*] - } - } -} - -fn gen_from_str(lits: &[(TokenStream, Ident)]) -> TokenStream { - let (lit, variant): (Vec, Vec) = lits.iter().cloned().unzip(); - - quote! { - fn from_str(input: &str, case_insensitive: bool) -> ::std::result::Result { - match input { - #(val if #lit.matches(val, case_insensitive) => Ok(Self::#variant),)* - e => Err(format!("Invalid variant: {}", e)), - } + fn value_variants<'a>() -> &'a [Self]{ + &[#(Self::#lit),*] } } } @@ -128,7 +113,7 @@ fn gen_arg_value(lits: &[(TokenStream, Ident)]) -> TokenStream { let (lit, variant): (Vec, Vec) = lits.iter().cloned().unzip(); quote! { - fn arg_value(&self) -> Option> { + fn arg_value<'a>(&self) -> Option> { match self { #(Self::#variant => Some(#lit),)* _ => None diff --git a/clap_derive/src/derives/args.rs b/clap_derive/src/derives/args.rs index 0cceb291db9..ec7b6fdbb2b 100644 --- a/clap_derive/src/derives/args.rs +++ b/clap_derive/src/derives/args.rs @@ -361,7 +361,7 @@ pub fn gen_augment( fn gen_arg_enum_possible_values(ty: &Type) -> TokenStream { quote_spanned! { ty.span()=> - .possible_values(<#ty as clap::ArgEnum>::arg_values()) + .possible_values(<#ty as clap::ArgEnum>::value_variants().iter().filter_map(clap::ArgEnum::arg_value)) } } diff --git a/clap_derive/tests/arg_enum.rs b/clap_derive/tests/arg_enum.rs index 84c816cd8f8..f68cc70ce5d 100644 --- a/clap_derive/tests/arg_enum.rs +++ b/clap_derive/tests/arg_enum.rs @@ -11,7 +11,7 @@ use clap::{ArgEnum, ArgValue, Clap}; #[test] fn basic() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] enum ArgChoice { Foo, Bar, @@ -40,7 +40,7 @@ fn basic() { #[test] fn default_value() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] enum ArgChoice { Foo, Bar, @@ -86,7 +86,7 @@ fn default_value() { #[test] fn multi_word_is_renamed_kebab() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] #[allow(non_camel_case_types)] enum ArgChoice { FooBar, @@ -116,7 +116,7 @@ fn multi_word_is_renamed_kebab() { #[test] fn variant_with_defined_casing() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] enum ArgChoice { #[clap(rename_all = "screaming_snake")] FooBar, @@ -139,7 +139,7 @@ fn variant_with_defined_casing() { #[test] fn casing_is_propogated_from_parent() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] #[clap(rename_all = "screaming_snake")] enum ArgChoice { FooBar, @@ -162,7 +162,7 @@ fn casing_is_propogated_from_parent() { #[test] fn casing_propogation_is_overridden() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] #[clap(rename_all = "screaming_snake")] enum ArgChoice { #[clap(rename_all = "camel")] @@ -187,7 +187,7 @@ fn casing_propogation_is_overridden() { #[test] fn case_insensitive() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] enum ArgChoice { Foo, } @@ -214,7 +214,7 @@ fn case_insensitive() { #[test] fn case_insensitive_set_to_false() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] enum ArgChoice { Foo, } @@ -236,7 +236,7 @@ fn case_insensitive_set_to_false() { #[test] fn alias() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] enum ArgChoice { #[clap(alias = "TOTP")] TOTP, @@ -264,7 +264,7 @@ fn alias() { #[test] fn multiple_alias() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] enum ArgChoice { #[clap(alias = "TOTP", alias = "t")] TOTP, @@ -298,7 +298,7 @@ fn multiple_alias() { #[test] fn option() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] enum ArgChoice { Foo, Bar, @@ -328,7 +328,7 @@ fn option() { #[test] fn vector() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] enum ArgChoice { Foo, Bar, @@ -358,7 +358,7 @@ fn vector() { #[test] fn skip_variant() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] #[allow(dead_code)] // silence warning about `Baz` being unused enum ArgChoice { Foo, @@ -368,7 +368,11 @@ fn skip_variant() { } assert_eq!( - ArgChoice::arg_values(), + ArgChoice::value_variants() + .iter() + .map(ArgEnum::arg_value) + .map(Option::unwrap) + .collect::>(), vec![ArgValue::new("foo"), ArgValue::new("bar")] ); assert!(ArgChoice::from_str("foo", true).is_ok()); @@ -378,7 +382,7 @@ fn skip_variant() { #[test] fn from_str_invalid() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] enum ArgChoice { Foo, } diff --git a/src/derive.rs b/src/derive.rs index 3edb39c3e50..133ffbc308e 100644 --- a/src/derive.rs +++ b/src/derive.rs @@ -273,7 +273,7 @@ pub trait Subcommand: FromArgMatches + Sized { /// level: Level, /// } /// -/// #[derive(clap::ArgEnum)] +/// #[derive(clap::ArgEnum, Clone)] /// enum Level { /// Debug, /// Info, @@ -281,17 +281,23 @@ pub trait Subcommand: FromArgMatches + Sized { /// Error, /// } /// ``` -pub trait ArgEnum: Sized { +pub trait ArgEnum: Sized + Clone { /// All possible argument values, in display order. - fn arg_values() -> Vec>; + fn value_variants<'a>() -> &'a [Self]; /// Parse an argument into `Self`. - fn from_str(input: &str, case_insensitive: bool) -> Result; + fn from_str(input: &str, case_insensitive: bool) -> Result { + Self::value_variants() + .iter() + .find(|v| v.arg_value().unwrap().matches(input, case_insensitive)) + .cloned() + .ok_or_else(|| format!("Invalid variant: {}", input)) + } /// The canonical argument value. /// /// The value is `None` for skipped variants. - fn arg_value(&self) -> Option>; + fn arg_value<'a>(&self) -> Option>; } impl Clap for Box {