Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for const_into_str attribute to enable static string conversions in const contexts #353

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions strum_macros/src/helpers/metadata.rs
Expand Up @@ -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);

Expand Down Expand Up @@ -51,6 +52,7 @@ pub enum EnumMeta {
kw: kw::prefix,
prefix: LitStr,
},
ConstIntoStr(kw::const_into_str)
}

impl Parse for EnumMeta {
Expand Down Expand Up @@ -80,6 +82,8 @@ impl Parse for EnumMeta {
input.parse::<Token![=]>()?;
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())
}
Expand Down
11 changes: 11 additions & 0 deletions strum_macros/src/helpers/type_props.rs
Expand Up @@ -23,6 +23,7 @@ pub struct StrumTypeProperties {
pub use_phf: bool,
pub prefix: Option<LitStr>,
pub enum_repr: Option<TokenStream>,
pub const_into_str: bool,
}

impl HasTypeProperties for DeriveInput {
Expand All @@ -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 } => {
Expand Down Expand Up @@ -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;
}
}
}

Expand Down
24 changes: 23 additions & 1 deletion strum_macros/src/macros/strings/as_ref_str.rs
Expand Up @@ -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 {
Expand All @@ -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()
}
}
},
})
}
74 changes: 74 additions & 0 deletions strum_tests/tests/as_ref_str.rs
Expand Up @@ -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<str>,
{
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);
}