diff --git a/strum_macros/src/helpers/metadata.rs b/strum_macros/src/helpers/metadata.rs index 94100a7f..384debf0 100644 --- a/strum_macros/src/helpers/metadata.rs +++ b/strum_macros/src/helpers/metadata.rs @@ -16,6 +16,7 @@ pub mod kw { // enum metadata custom_keyword!(serialize_all); + custom_keyword!(const_into_str); custom_keyword!(use_phf); custom_keyword!(prefix); @@ -51,6 +52,7 @@ pub enum EnumMeta { kw: kw::prefix, prefix: LitStr, }, + ConstIntoStr(kw::const_into_str) } impl Parse for EnumMeta { @@ -80,6 +82,8 @@ impl Parse for EnumMeta { input.parse::()?; let prefix = input.parse()?; Ok(EnumMeta::Prefix { kw, prefix }) + } else if lookahead.peek(kw::const_into_str) { + Ok(EnumMeta::ConstIntoStr(input.parse()?)) } else { Err(lookahead.error()) } diff --git a/strum_macros/src/helpers/type_props.rs b/strum_macros/src/helpers/type_props.rs index 7302853e..c04b3589 100644 --- a/strum_macros/src/helpers/type_props.rs +++ b/strum_macros/src/helpers/type_props.rs @@ -23,6 +23,7 @@ pub struct StrumTypeProperties { pub use_phf: bool, pub prefix: Option, pub enum_repr: Option, + pub const_into_str: bool, } impl HasTypeProperties for DeriveInput { @@ -37,6 +38,8 @@ impl HasTypeProperties for DeriveInput { let mut use_phf_kw = None; let mut crate_module_path_kw = None; let mut prefix_kw = None; + let mut const_into_str = None; + for meta in strum_meta { match meta { EnumMeta::SerializeAll { case_style, kw } => { @@ -82,6 +85,14 @@ impl HasTypeProperties for DeriveInput { prefix_kw = Some(kw); output.prefix = Some(prefix); } + EnumMeta::ConstIntoStr(kw) => { + if let Some(fst_kw) = const_into_str { + return Err(occurrence_error(fst_kw, kw, "const_into_str")); + } + + const_into_str = Some(kw); + output.const_into_str = true; + } } } diff --git a/strum_macros/src/macros/strings/as_ref_str.rs b/strum_macros/src/macros/strings/as_ref_str.rs index 8d44f810..eb535df8 100644 --- a/strum_macros/src/macros/strings/as_ref_str.rs +++ b/strum_macros/src/macros/strings/as_ref_str.rs @@ -99,7 +99,7 @@ pub fn as_static_str_inner( } } }, - GenerateTraitVariant::From => quote! { + GenerateTraitVariant::From if !type_properties.const_into_str => quote! { impl #impl_generics ::core::convert::From<#name #ty_generics> for &'static str #where_clause { fn from(x: #name #ty_generics) -> &'static str { match x { @@ -115,5 +115,27 @@ pub fn as_static_str_inner( } } }, + GenerateTraitVariant::From => quote! { + impl #impl_generics #name #ty_generics #where_clause { + pub const fn into_str(&self) -> &'static str { + match self { + #(#arms3),* + } + } + } + + impl #impl_generics ::core::convert::From<#name #ty_generics> for &'static str #where_clause { + fn from(x: #name #ty_generics) -> &'static str { + match x { + #(#arms2),* + } + } + } + impl #impl_generics2 ::core::convert::From<&'_derivative_strum #name #ty_generics> for &'static str #where_clause { + fn from(x: &'_derivative_strum #name #ty_generics) -> &'static str { + x.into_str() + } + } + }, }) } diff --git a/strum_tests/tests/as_ref_str.rs b/strum_tests/tests/as_ref_str.rs index d492f174..c0cf30b1 100644 --- a/strum_tests/tests/as_ref_str.rs +++ b/strum_tests/tests/as_ref_str.rs @@ -111,3 +111,77 @@ fn brightness_serialize_all() { assert_eq!("dim", <&'static str>::from(Brightness::Dim { glow: 0 })); assert_eq!("Bright", <&'static str>::from(Brightness::BrightWhite)); } + +#[derive(IntoStaticStr)] +#[strum(const_into_str)] +enum Bar<'a, T> + where + T: AsRef, +{ + A(T), + B, + C(&'a i32), + #[strum(serialize = "Dark")] + D, + #[strum(to_string = "Green")] + G, + #[strum(serialize = "b", to_string = "blue")] + Blue { hue: usize }, + #[strum(serialize = "y", serialize = "yellow")] + Yellow, +} + +#[derive(IntoStaticStr)] +#[strum(const_into_str)] +enum Baz<'a, T> { + A(T), + C(&'a i32), +} + +#[derive(IntoStaticStr)] +#[strum(serialize_all = "snake_case")] +#[strum(const_into_str)] +enum BrightnessConst { + DarkBlack, + Dim { + glow: usize, + }, + #[strum(serialize = "Bright")] + BrightWhite, +} + +#[test] +fn test_const_into_static_str() { + + const A: &'static str = Bar::A("foo").into_str(); + assert_eq!("A", A); + const B: &'static str = Bar::B::<&str>.into_str(); + assert_eq!("B", B); + const C: &'static str = Bar::C::<&str>(&12).into_str(); + assert_eq!("C", C); + + const D: &'static str = Bar::D::<&str>.into_str(); + assert_eq!("Dark", D); + + const G: &'static str = Bar::G::<&str>.into_str(); + assert_eq!("Green", G); + + const BLUE: &'static str = Bar::Blue::<&str>{ hue: 2 }.into_str(); + assert_eq!("blue", BLUE); + + const YELLOW: &'static str = Bar::Yellow::<&str>.into_str(); + assert_eq!("yellow", YELLOW); + + const BAZ_A: &'static str = Baz::A("foo").into_str(); + assert_eq!("A", BAZ_A); + + const BAZ_C: &'static str = Baz::C::<&str>(&6).into_str(); + assert_eq!("C", BAZ_C); + + const DARK_BLACK: &'static str = BrightnessConst::DarkBlack.into_str(); + assert_eq!("dark_black", DARK_BLACK); + const DIM: &'static str = BrightnessConst::Dim {glow:1}.into_str(); + assert_eq!("dim", DIM); + const BRIGHT_WHITE: &'static str = BrightnessConst::BrightWhite.into_str(); + assert_eq!("Bright", BRIGHT_WHITE); +}