Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions strum_macros/src/helpers/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub mod kw {
custom_keyword!(const_into_str);
custom_keyword!(use_phf);
custom_keyword!(prefix);
custom_keyword!(suffix);
custom_keyword!(parse_err_ty);
custom_keyword!(parse_err_fn);

Expand Down Expand Up @@ -56,6 +57,10 @@ pub enum EnumMeta {
kw: kw::prefix,
prefix: LitStr,
},
Suffix {
kw: kw::suffix,
suffix: LitStr,
},
ParseErrTy {
kw: kw::parse_err_ty,
path: Path,
Expand Down Expand Up @@ -94,6 +99,11 @@ impl Parse for EnumMeta {
input.parse::<Token![=]>()?;
let prefix = input.parse()?;
Ok(EnumMeta::Prefix { kw, prefix })
} else if lookahead.peek(kw::suffix) {
let kw = input.parse::<kw::suffix>()?;
input.parse::<Token![=]>()?;
let suffix = input.parse()?;
Ok(EnumMeta::Suffix { kw, suffix })
} else if lookahead.peek(kw::parse_err_ty) {
let kw = input.parse::<kw::parse_err_ty>()?;
input.parse::<Token![=]>()?;
Expand Down
10 changes: 10 additions & 0 deletions strum_macros/src/helpers/type_props.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub struct StrumTypeProperties {
pub discriminant_vis: Option<Visibility>,
pub use_phf: bool,
pub prefix: Option<LitStr>,
pub suffix: Option<LitStr>,
pub enum_repr: Option<TokenStream>,
pub const_into_str: bool,
pub discriminant_docs: Vec<LitStr>,
Expand All @@ -43,6 +44,7 @@ impl HasTypeProperties for DeriveInput {
let mut use_phf_kw = None;
let mut crate_module_path_kw = None;
let mut prefix_kw = None;
let mut suffix_kw = None;
let mut const_into_str = None;

for meta in strum_meta {
Expand Down Expand Up @@ -90,6 +92,14 @@ impl HasTypeProperties for DeriveInput {
prefix_kw = Some(kw);
output.prefix = Some(prefix);
}
EnumMeta::Suffix { suffix, kw } => {
if let Some(fst_kw) = suffix_kw {
return Err(occurrence_error(fst_kw, kw, "suffix"));
}

suffix_kw = Some(kw);
output.suffix = Some(suffix);
}
EnumMeta::ParseErrTy { path, kw } => {
if let Some(fst_kw) = parse_err_ty_kw {
return Err(occurrence_error(fst_kw, kw, "parse_err_ty"));
Expand Down
5 changes: 5 additions & 0 deletions strum_macros/src/helpers/variant_props.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ impl StrumVariantProperties {
&self,
case_style: Option<CaseStyle>,
prefix: Option<&LitStr>,
suffix: Option<&LitStr>,
) -> LitStr {
let mut output = self.to_string.as_ref().cloned().unwrap_or_else(|| {
self.serialize
Expand All @@ -48,6 +49,10 @@ impl StrumVariantProperties {
output = LitStr::new(&(prefix.value() + &output.value()), output.span());
}

if let Some(suffix) = suffix {
output = LitStr::new(&(output.value() + &suffix.value()), output.span());
}

output
}

Expand Down
16 changes: 15 additions & 1 deletion strum_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,18 @@ pub fn from_string(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
///
/// assert_eq!("/redred", ColorWithPrefix::Red.as_ref());
/// assert_eq!("/Green", ColorWithPrefix::Green.as_ref());
///
/// // With suffix on all variants
/// #[derive(AsRefStr, Debug)]
/// #[strum(suffix = ".rs")]
/// enum ColorWithSuffix {
/// #[strum(serialize = "redred")]
/// Red,
/// Green,
/// }
///
/// assert_eq!("redred.rs", ColorWithSuffix::Red.as_ref());
/// assert_eq!("Green.rs", ColorWithSuffix::Green.as_ref());
/// ```
#[proc_macro_derive(AsRefStr, attributes(strum))]
pub fn as_ref_str(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
Expand Down Expand Up @@ -381,7 +393,9 @@ pub fn to_string(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
/// 3. The name of the variant will be used if there are no `serialize` or `to_string` attributes.
/// 4. If the enum has a `strum(prefix = "some_value_")`, every variant will have that prefix prepended
/// to the serialization.
/// 5. Enums with fields support string interpolation.
/// 5. If the enum has a `strum(suffix = "_another_value")`, every variant will have that suffix appended
/// to the serialization.
/// 6. Enums with fields support string interpolation.
/// Note this means the variant will not "round trip" if you then deserialize the string.
///
/// ```rust
Expand Down
7 changes: 5 additions & 2 deletions strum_macros/src/macros/enum_variant_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ pub fn enum_variant_names_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
.iter()
.map(|v| {
let props = v.get_variant_properties()?;
Ok(props
.get_preferred_name(type_properties.case_style, type_properties.prefix.as_ref()))
Ok(props.get_preferred_name(
type_properties.case_style,
type_properties.prefix.as_ref(),
type_properties.suffix.as_ref(),
))
})
.collect::<syn::Result<Vec<LitStr>>>()?;

Expand Down
7 changes: 5 additions & 2 deletions strum_macros/src/macros/strings/as_ref_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,11 @@ where
// Look at all the serialize attributes.
// Use `to_string` attribute (not `as_ref_str` or something) to keep things consistent
// (i.e. always `enum.as_ref().to_string() == enum.to_string()`).
let output = variant_properties
.get_preferred_name(type_properties.case_style, type_properties.prefix.as_ref());
let output = variant_properties.get_preferred_name(
type_properties.case_style,
type_properties.prefix.as_ref(),
type_properties.suffix.as_ref(),
);
let params = match variant.fields {
Fields::Unit => quote! {},
Fields::Unnamed(..) => quote! { (..) },
Expand Down
7 changes: 5 additions & 2 deletions strum_macros/src/macros/strings/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,11 @@ pub fn display_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
}

// Look at all the serialize attributes.
let output = variant_properties
.get_preferred_name(type_properties.case_style, type_properties.prefix.as_ref());
let output = variant_properties.get_preferred_name(
type_properties.case_style,
type_properties.prefix.as_ref(),
type_properties.suffix.as_ref(),
);

let params = match variant.fields {
Fields::Unit => quote! {},
Expand Down
4 changes: 2 additions & 2 deletions strum_macros/src/macros/strings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ where
Fields::Unnamed(f) if f.unnamed.len() == 1 => {
let ident = &quote! { field0 };
let ref_kw = match f.unnamed.last().unwrap().ty {
syn::Type::Reference(..) => quote! { },
syn::Type::Reference(..) => quote! {},
_ => quote! { ref },
};

Expand All @@ -33,7 +33,7 @@ where
Fields::Named(f) if f.named.len() == 1 => {
let field = f.named.last().unwrap();
let ref_kw = match field.ty {
syn::Type::Reference(..) => quote! { },
syn::Type::Reference(..) => quote! {},
_ => quote! { ref },
};

Expand Down
7 changes: 5 additions & 2 deletions strum_macros/src/macros/strings/to_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,11 @@ pub fn to_string_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
}

// Look at all the serialize attributes.
let output = variant_properties
.get_preferred_name(type_properties.case_style, type_properties.prefix.as_ref());
let output = variant_properties.get_preferred_name(
type_properties.case_style,
type_properties.prefix.as_ref(),
type_properties.suffix.as_ref(),
);

let params = match variant.fields {
Fields::Unit => quote! {},
Expand Down
54 changes: 50 additions & 4 deletions strum_tests/tests/as_ref_str.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![allow(deprecated)]

use std::str::FromStr;
use strum::{AsRefStr, AsStaticRef, AsStaticStr, EnumString, IntoStaticStr};
use strum::{AsRefStr, AsStaticRef, AsStaticStr, Display, EnumString, IntoStaticStr};

mod core {} // ensure macros call `::core`

Expand Down Expand Up @@ -61,7 +61,13 @@ fn as_green_str() {
#[test]
fn as_fuchsia_str() {
assert_eq!("Purple", (Color::Inner(InnerColor::Purple)).as_ref());
assert_eq!("Purple", (Color::InnerField { inner: InnerColor::Purple }).as_ref());
assert_eq!(
"Purple",
(Color::InnerField {
inner: InnerColor::Purple
})
.as_ref()
);
}

#[derive(IntoStaticStr)]
Expand Down Expand Up @@ -128,7 +134,9 @@ enum Brightness {
#[strum(transparent)]
Gray(&'static str),
#[strum(transparent)]
Grey { inner: &'static str }
Grey {
inner: &'static str,
},
}

#[test]
Expand All @@ -145,7 +153,10 @@ fn brightness_serialize_all() {
assert_eq!("dim", <&'static str>::from(Brightness::Dim { glow: 0 }));
assert_eq!("Bright", <&'static str>::from(Brightness::BrightWhite));
assert_eq!("Gray", <&'static str>::from(Brightness::Gray("Gray")));
assert_eq!("Grey", <&'static str>::from(Brightness::Grey { inner: "Grey" }));
assert_eq!(
"Grey",
<&'static str>::from(Brightness::Grey { inner: "Grey" })
);
}

#[derive(IntoStaticStr)]
Expand Down Expand Up @@ -226,3 +237,38 @@ fn test_const_into_static_str() {
const BRIGHT_WHITE: &'static str = BrightnessConst::BrightWhite.into_str();
assert_eq!("Bright", BRIGHT_WHITE);
}

#[derive(AsRefStr, Display, EnumString)]
#[strum(prefix = "/etc/data/assets/", suffix = ".json")]
enum Asset {
#[strum(serialize = "cfg", serialize = "configuration", to_string = "config")]
Config,
#[strum(serialize = "params")]
Params,
#[strum(default)]
Generic(String),
}

#[test]
fn test_prefix_and_suffix() {
assert_eq!(
String::from("/etc/data/assets/config.json"),
(Asset::Config).to_string()
);
assert_eq!("/etc/data/assets/config.json", (Asset::Config).as_ref(),);

assert_eq!(
String::from("/etc/data/assets/params.json"),
(Asset::Params).to_string()
);
assert_eq!("/etc/data/assets/params.json", (Asset::Params).as_ref());

assert_eq!(
String::from("some-file"),
(Asset::Generic("some-file".into()).to_string()),
);
assert_eq!(
"/etc/data/assets/Generic.json",
(Asset::Generic("()".into()).as_ref()),
)
}
17 changes: 14 additions & 3 deletions strum_tests/tests/from_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ enum Color {
#[derive(Debug, Eq, PartialEq, EnumString, strum::Display)]
enum Color2 {
#[strum(default)]
Purple { inner: String }
Purple { inner: String },
}

#[rustversion::since(1.34)]
Expand Down Expand Up @@ -82,8 +82,19 @@ fn color_default() {

#[test]
fn color2_default() {
assert_from_str(Color2::Purple { inner: String::from("test") }, "test");
assert_eq!(String::from("test"), Color2::Purple { inner: String::from("test") }.to_string());
assert_from_str(
Color2::Purple {
inner: String::from("test"),
},
"test",
);
assert_eq!(
String::from("test"),
Color2::Purple {
inner: String::from("test")
}
.to_string()
);
}

#[test]
Expand Down
13 changes: 13 additions & 0 deletions strum_tests/tests/prefix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,16 @@ fn prefix_redred() {
assert_eq!(String::from("colour/RedRed"), (Color::Red).to_string());
assert_eq!(("colour/RedRed"), (Color::Red).as_ref());
}

#[test]
fn prefix_green_default() {
assert_eq!(
String::from("green"),
(Color::Green("green".into())).to_string()
);

assert_eq!(
String::from("colour/Green"),
(Color::Green("green".into())).as_ref()
);
}
44 changes: 44 additions & 0 deletions strum_tests/tests/suffix.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use strum::{Display, EnumString};
use strum_macros::AsRefStr;

#[allow(dead_code)]
#[derive(Debug, EnumString, Display, AsRefStr)]
#[strum(suffix = ".color")]
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 suffix_redred() {
let c = Color::Red;
assert_eq!(String::from("RedRed.color"), c.to_string());
assert_eq!("RedRed.color", c.as_ref());
}

#[test]
fn suffix_blue() {
let c = Color::Blue { hue: 10 };
assert_eq!(String::from("blue.color"), c.to_string());
assert_eq!("blue.color", c.as_ref());
}

#[test]
fn suffix_yellow() {
let c = Color::Yellow;
assert_eq!(String::from("yellow.color"), c.to_string());
assert_eq!("yellow.color", c.as_ref());
}

#[test]
fn suffix_green_default() {
let c = Color::Green("basic-green".into());
assert_eq!(String::from("basic-green"), c.to_string());
assert_eq!("Green.color", c.as_ref());
}