From c1398efb1da63f7fcf0c1fe29c9d8b534282b86c Mon Sep 17 00:00:00 2001 From: chanman3388 Date: Fri, 15 Sep 2023 03:02:30 +0100 Subject: [PATCH 1/3] implement prefix enum attribute --- strum_macros/src/helpers/metadata.rs | 10 ++++++++++ strum_macros/src/helpers/type_props.rs | 12 +++++++++++- strum_macros/src/macros/strings/display.rs | 7 +++++-- strum_tests/tests/prefix.rs | 20 ++++++++++++++++++++ 4 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 strum_tests/tests/prefix.rs diff --git a/strum_macros/src/helpers/metadata.rs b/strum_macros/src/helpers/metadata.rs index d638ae3c..19eb9270 100644 --- a/strum_macros/src/helpers/metadata.rs +++ b/strum_macros/src/helpers/metadata.rs @@ -17,6 +17,7 @@ pub mod kw { // enum metadata custom_keyword!(serialize_all); custom_keyword!(use_phf); + custom_keyword!(prefix); // enum discriminant metadata custom_keyword!(derive); @@ -45,6 +46,10 @@ pub enum EnumMeta { crate_module_path: Path, }, UsePhf(kw::use_phf), + Prefix { + kw: kw::prefix, + prefix: LitStr, + }, } impl Parse for EnumMeta { @@ -69,6 +74,11 @@ impl Parse for EnumMeta { Ok(EnumMeta::AsciiCaseInsensitive(input.parse()?)) } else if lookahead.peek(kw::use_phf) { Ok(EnumMeta::UsePhf(input.parse()?)) + } else if lookahead.peek(kw::prefix) { + let kw = input.parse::()?; + input.parse::()?; + let prefix = input.parse()?; + Ok(EnumMeta::Prefix { kw, prefix }) } else { Err(lookahead.error()) } diff --git a/strum_macros/src/helpers/type_props.rs b/strum_macros/src/helpers/type_props.rs index 0d49e04e..9abaf4df 100644 --- a/strum_macros/src/helpers/type_props.rs +++ b/strum_macros/src/helpers/type_props.rs @@ -1,7 +1,7 @@ use proc_macro2::TokenStream; use quote::quote; use std::default::Default; -use syn::{parse_quote, DeriveInput, Ident, Path, Visibility}; +use syn::{parse_quote, DeriveInput, Ident, LitStr, Path, Visibility}; use super::case_style::CaseStyle; use super::metadata::{DeriveInputExt, EnumDiscriminantsMeta, EnumMeta}; @@ -21,6 +21,7 @@ pub struct StrumTypeProperties { pub discriminant_others: Vec, pub discriminant_vis: Option, pub use_phf: bool, + pub prefix: Option, } impl HasTypeProperties for DeriveInput { @@ -34,6 +35,7 @@ impl HasTypeProperties for DeriveInput { let mut ascii_case_insensitive_kw = None; let mut use_phf_kw = None; let mut crate_module_path_kw = None; + let mut prefix_kw = None; for meta in strum_meta { match meta { EnumMeta::SerializeAll { case_style, kw } => { @@ -71,6 +73,14 @@ impl HasTypeProperties for DeriveInput { crate_module_path_kw = Some(kw); output.crate_module_path = Some(crate_module_path); } + EnumMeta::Prefix { prefix, kw } => { + if let Some(fst_kw) = prefix_kw { + return Err(occurrence_error(fst_kw, kw, "prefix")); + } + + prefix_kw = Some(kw); + output.prefix = Some(prefix); + } } } diff --git a/strum_macros/src/macros/strings/display.rs b/strum_macros/src/macros/strings/display.rs index fcc5936a..abb32ba3 100644 --- a/strum_macros/src/macros/strings/display.rs +++ b/strum_macros/src/macros/strings/display.rs @@ -1,6 +1,6 @@ use proc_macro2::TokenStream; use quote::quote; -use syn::{Data, DeriveInput, Fields}; +use syn::{Data, DeriveInput, Fields, LitStr}; use crate::helpers::{non_enum_error, HasStrumVariantProperties, HasTypeProperties}; @@ -24,7 +24,10 @@ pub fn display_inner(ast: &DeriveInput) -> syn::Result { } // Look at all the serialize attributes. - let output = variant_properties.get_preferred_name(type_properties.case_style); + let mut output = variant_properties.get_preferred_name(type_properties.case_style); + if let Some(prefix) = &type_properties.prefix { + output = LitStr::new(&(prefix.value() + &output.value()), output.span()); + } let params = match variant.fields { Fields::Unit => quote! {}, diff --git a/strum_tests/tests/prefix.rs b/strum_tests/tests/prefix.rs new file mode 100644 index 00000000..806b5d52 --- /dev/null +++ b/strum_tests/tests/prefix.rs @@ -0,0 +1,20 @@ +use strum::{Display, EnumString}; + +#[allow(dead_code)] +#[derive(Debug, EnumString, Display)] +#[strum(prefix = "colour/")] +enum Color { + #[strum(to_string = "RedRed")] + Red, + #[strum(serialize = "b", to_string = "blue")] + Blue { hue: usize }, + #[strum(serialize = "y", serialize = "yellow")] + Yellow, + #[strum(default)] + Green(String), +} + +#[test] +fn prefix_redred() { + assert_eq!(String::from("colour/RedRed"), (Color::Red).to_string()); +} From 9639f0a6912cc78132831f841879dd4e4ab8d670 Mon Sep 17 00:00:00 2001 From: chanman3388 Date: Fri, 15 Sep 2023 03:03:11 +0100 Subject: [PATCH 2/3] `cargo fmt` --- strum_macros/src/helpers/case_style.rs | 3 ++- strum_macros/src/helpers/mod.rs | 2 +- strum_macros/src/macros/enum_messages.rs | 19 +++++++++++-------- strum_macros/src/macros/enum_variant_names.rs | 11 ++++++++--- .../src/macros/strings/from_string.rs | 2 +- strum_tests/tests/enum_discriminants.rs | 1 - strum_tests/tests/enum_is.rs | 9 +++++++-- strum_tests/tests/enum_message.rs | 5 ++++- strum_tests/tests/enum_try_as.rs | 5 ++++- 9 files changed, 38 insertions(+), 19 deletions(-) diff --git a/strum_macros/src/helpers/case_style.rs b/strum_macros/src/helpers/case_style.rs index 86a85830..bcea7886 100644 --- a/strum_macros/src/helpers/case_style.rs +++ b/strum_macros/src/helpers/case_style.rs @@ -1,5 +1,6 @@ use heck::{ - ToKebabCase, ToLowerCamelCase, ToShoutySnakeCase, ToSnakeCase, ToTitleCase, ToUpperCamelCase, ToTrainCase, + ToKebabCase, ToLowerCamelCase, ToShoutySnakeCase, ToSnakeCase, ToTitleCase, ToTrainCase, + ToUpperCamelCase, }; use std::str::FromStr; use syn::{ diff --git a/strum_macros/src/helpers/mod.rs b/strum_macros/src/helpers/mod.rs index 142ea0b8..724fce2f 100644 --- a/strum_macros/src/helpers/mod.rs +++ b/strum_macros/src/helpers/mod.rs @@ -1,4 +1,4 @@ -pub use self::case_style::{CaseStyleHelpers, snakify}; +pub use self::case_style::{snakify, CaseStyleHelpers}; pub use self::type_props::HasTypeProperties; pub use self::variant_props::HasStrumVariantProperties; diff --git a/strum_macros/src/macros/enum_messages.rs b/strum_macros/src/macros/enum_messages.rs index c0561085..2dad4117 100644 --- a/strum_macros/src/macros/enum_messages.rs +++ b/strum_macros/src/macros/enum_messages.rs @@ -74,14 +74,17 @@ pub fn enum_message_inner(ast: &DeriveInput) -> syn::Result { if !documentation.is_empty() { let params = params.clone(); // Strip a single leading space from each documentation line. - let documentation: Vec = documentation.iter().map(|lit_str| { - let line = lit_str.value(); - if line.starts_with(' ') { - LitStr::new(&line.as_str()[1..], lit_str.span()) - } else { - lit_str.clone() - } - }).collect(); + let documentation: Vec = documentation + .iter() + .map(|lit_str| { + let line = lit_str.value(); + if line.starts_with(' ') { + LitStr::new(&line.as_str()[1..], lit_str.span()) + } else { + lit_str.clone() + } + }) + .collect(); if documentation.len() == 1 { let text = &documentation[0]; documentation_arms diff --git a/strum_macros/src/macros/enum_variant_names.rs b/strum_macros/src/macros/enum_variant_names.rs index c54d45dc..d10a79e7 100644 --- a/strum_macros/src/macros/enum_variant_names.rs +++ b/strum_macros/src/macros/enum_variant_names.rs @@ -1,6 +1,6 @@ use proc_macro2::TokenStream; use quote::quote; -use syn::{Data, DeriveInput}; +use syn::{parse_quote, Data, DeriveInput, LitStr}; use crate::helpers::{non_enum_error, HasStrumVariantProperties, HasTypeProperties}; @@ -22,9 +22,14 @@ pub fn enum_variant_names_inner(ast: &DeriveInput) -> syn::Result { .iter() .map(|v| { let props = v.get_variant_properties()?; - Ok(props.get_preferred_name(type_properties.case_style)) + let preferred_name = props.get_preferred_name(type_properties.case_style); + if let Some(prefix) = &type_properties.prefix { + Ok(parse_quote!(#prefix, #preferred_name)) + } else { + Ok(props.get_preferred_name(type_properties.case_style)) + } }) - .collect::>>()?; + .collect::>>()?; Ok(quote! { impl #impl_generics #strum_module_path::VariantNames for #name #ty_generics #where_clause { diff --git a/strum_macros/src/macros/strings/from_string.rs b/strum_macros/src/macros/strings/from_string.rs index 2d255917..4b9a7219 100644 --- a/strum_macros/src/macros/strings/from_string.rs +++ b/strum_macros/src/macros/strings/from_string.rs @@ -79,7 +79,7 @@ pub fn from_string_inner(ast: &DeriveInput) -> syn::Result { phf_exact_match_arms.push(quote! { #serialization => #name::#ident #params, }); if is_ascii_case_insensitive { - // Store the lowercase and UPPERCASE variants in the phf map to capture + // Store the lowercase and UPPERCASE variants in the phf map to capture let ser_string = serialization.value(); let lower = diff --git a/strum_tests/tests/enum_discriminants.rs b/strum_tests/tests/enum_discriminants.rs index eb29e6d1..11336585 100644 --- a/strum_tests/tests/enum_discriminants.rs +++ b/strum_tests/tests/enum_discriminants.rs @@ -1,7 +1,6 @@ use enum_variant_type::EnumVariantType; use strum::{Display, EnumDiscriminants, EnumIter, EnumMessage, EnumString, IntoEnumIterator}; - mod core {} // ensure macros call `::core` #[allow(dead_code)] diff --git a/strum_tests/tests/enum_is.rs b/strum_tests/tests/enum_is.rs index 789881ce..e3cc3406 100644 --- a/strum_tests/tests/enum_is.rs +++ b/strum_tests/tests/enum_is.rs @@ -6,8 +6,13 @@ mod core {} // ensure macros call `::core` enum Foo { Unit, Named0 {}, - Named1 { _a: char }, - Named2 { _a: u32, _b: String }, + Named1 { + _a: char, + }, + Named2 { + _a: u32, + _b: String, + }, Unnamed0(), Unnamed1(Option), Unnamed2(bool, u8), diff --git a/strum_tests/tests/enum_message.rs b/strum_tests/tests/enum_message.rs index b1c86004..e7ff3033 100644 --- a/strum_tests/tests/enum_message.rs +++ b/strum_tests/tests/enum_message.rs @@ -49,7 +49,10 @@ fn only_detailed_message() { #[test] fn documentation() { - assert_eq!("I eat birds.\n\nAnd fish.\n", (Pets::Cat).get_documentation().unwrap()); + assert_eq!( + "I eat birds.\n\nAnd fish.\n", + (Pets::Cat).get_documentation().unwrap() + ); assert_eq!("I'm a fish.", (Pets::Fish).get_documentation().unwrap()); assert_eq!("I'm a bird.", (Pets::Bird).get_documentation().unwrap()); } diff --git a/strum_tests/tests/enum_try_as.rs b/strum_tests/tests/enum_try_as.rs index aa54205e..6cbf81e5 100644 --- a/strum_tests/tests/enum_try_as.rs +++ b/strum_tests/tests/enum_try_as.rs @@ -11,7 +11,10 @@ enum Foo { #[allow(dead_code)] Unit, #[allow(dead_code)] - Named { _a: u32, _b: String }, + Named { + _a: u32, + _b: String, + }, } #[test] From cfae2e1b2af5ed0665d0208bf45e1c87aaf8cd0c Mon Sep 17 00:00:00 2001 From: chanman3388 Date: Fri, 15 Sep 2023 03:04:12 +0100 Subject: [PATCH 3/3] undo changes --- strum_macros/src/macros/enum_variant_names.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/strum_macros/src/macros/enum_variant_names.rs b/strum_macros/src/macros/enum_variant_names.rs index d10a79e7..f53b0afa 100644 --- a/strum_macros/src/macros/enum_variant_names.rs +++ b/strum_macros/src/macros/enum_variant_names.rs @@ -1,6 +1,6 @@ use proc_macro2::TokenStream; use quote::quote; -use syn::{parse_quote, Data, DeriveInput, LitStr}; +use syn::{Data, DeriveInput, LitStr}; use crate::helpers::{non_enum_error, HasStrumVariantProperties, HasTypeProperties}; @@ -22,12 +22,7 @@ pub fn enum_variant_names_inner(ast: &DeriveInput) -> syn::Result { .iter() .map(|v| { let props = v.get_variant_properties()?; - let preferred_name = props.get_preferred_name(type_properties.case_style); - if let Some(prefix) = &type_properties.prefix { - Ok(parse_quote!(#prefix, #preferred_name)) - } else { - Ok(props.get_preferred_name(type_properties.case_style)) - } + Ok(props.get_preferred_name(type_properties.case_style)) }) .collect::>>()?;