Skip to content

Commit

Permalink
fix!: use the tuple value for to_string on default (#270)
Browse files Browse the repository at this point in the history
The default attribute on a tuple like variant now causes the to_string
and display format to use the value of the tuple rather than the name
of the variant.

E.g. Color::Green("lime").to_string() will equal "lime" not "Green"

Fixes: how to round trip Display and EnumString with default="true" #86

BREAKING CHANGE
This changes how Display and ToString cause the following to renders:
```rust
#[strum(default)]
Green(String)
```
To maintain the previous behavior (use the variant name):
```rust
#[strum(default, to_string("Green"))]
Green(String)
```
  • Loading branch information
joshka committed Jun 18, 2023
1 parent 2b71e10 commit e6a9bf0
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 2 deletions.
2 changes: 1 addition & 1 deletion strum_macros/src/helpers/variant_props.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub struct StrumVariantProperties {
pub documentation: Vec<LitStr>,
pub string_props: Vec<(LitStr, LitStr)>,
serialize: Vec<LitStr>,
to_string: Option<LitStr>,
pub to_string: Option<LitStr>,
ident: Option<Ident>,
}

Expand Down
16 changes: 15 additions & 1 deletion strum_macros/src/macros/strings/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,21 @@ pub fn display_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
Fields::Named(..) => quote! { {..} },
};

arms.push(quote! { #name::#ident #params => f.pad(#output) });
if variant_properties.to_string.is_none() && variant_properties.default.is_some() {
match &variant.fields {
Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
arms.push(quote! { #name::#ident(ref s) => f.pad(s) });
}
_ => {
return Err(syn::Error::new_spanned(
variant,
"Default only works on newtype structs with a single String field",
))
}
}
} else {
arms.push(quote! { #name::#ident #params => f.pad(#output) });
}
}

if arms.len() < variants.len() {
Expand Down
16 changes: 16 additions & 0 deletions strum_macros/src/macros/strings/to_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,22 @@ pub fn to_string_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
continue;
}

// display variants like Green("lime") as "lime"
if variant_properties.to_string.is_none() && variant_properties.default.is_some() {
match &variant.fields {
Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
arms.push(quote! { #name::#ident(ref s) => ::std::string::String::from(s) });
continue;
}
_ => {
return Err(syn::Error::new_spanned(
variant,
"Default only works on newtype structs with a single String field",
))
}
}
}

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

Expand Down
22 changes: 22 additions & 0 deletions strum_tests/tests/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,28 @@ fn to_red_string() {
assert_eq!(String::from("RedRed"), format!("{}", Color::Red));
}

#[test]
fn to_green_string() {
assert_eq!(
String::from("lime"),
format!("{}", Color::Green("lime".into()))
);
}

#[derive(Debug, Eq, PartialEq, EnumString, Display)]
enum ColorWithDefaultAndToString {
#[strum(default, to_string = "GreenGreen")]
Green(String),
}

#[test]
fn to_green_with_default_and_to_string() {
assert_eq!(
String::from("GreenGreen"),
format!("{}", ColorWithDefaultAndToString::Green("lime".into()))
);
}

#[derive(Display, Debug, Eq, PartialEq)]
#[strum(serialize_all = "snake_case")]
enum Brightness {
Expand Down
30 changes: 30 additions & 0 deletions strum_tests/tests/to_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,36 @@ fn to_red_string() {
);
}

#[test]
fn to_green_string_with_default() {
assert_eq!(
String::from("lime"),
(Color::Green("lime".into())).to_string()
);
assert_eq!(
Color::Green("lime".into()),
Color::from_str("lime").unwrap()
);
}

#[derive(Debug, Eq, PartialEq, EnumString, ToString)]
enum ColorWithDefaultAndToString {
#[strum(default, to_string = "GreenGreen")]
Green(String),
}

#[test]
fn to_green_with_default_and_to_string() {
assert_eq!(
String::from("GreenGreen"),
(ColorWithDefaultAndToString::Green("lime".into())).to_string()
);
assert_eq!(
ColorWithDefaultAndToString::Green("lime".into()),
ColorWithDefaultAndToString::from_str("lime").unwrap()
);
}

#[derive(Debug, Eq, PartialEq, ToString)]
#[strum(serialize_all = "snake_case")]
enum Brightness {
Expand Down

0 comments on commit e6a9bf0

Please sign in to comment.