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
4 changes: 3 additions & 1 deletion strum/src/additional_attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@
//!
//! - `transparent`: Signals that the inner field's implementation should be used, instead of generating
//! one for this variant. Only applicable to enum variants with a single field. Compatible with the
//! `AsRefStr`, `Display` and `IntoStaticStr` derive macros.
//! `AsRefStr`, `Display` and `IntoStaticStr` derive macros. Note that `IntoStaticStr` has a few restrictions,
//! the value must be `'static` and `const_into_str` is not supported in combination with `transparent` b/c
//! transparent relies on a call on `From::from(variant)`.
//!
//! - `disabled`: removes variant from generated code.
//!
Expand Down
2 changes: 1 addition & 1 deletion strum_macros/src/macros/strings/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub fn display_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {

if let Some(..) = variant_properties.transparent {
let arm = super::extract_single_field_variant_and_then(name, variant, |tok| {
quote! { ::core::fmt::Display::fmt(#tok, f)}
quote! { ::core::fmt::Display::fmt(#tok, f) }
})
.map_err(|_| non_single_field_variant_error("transparent"))?;

Expand Down
21 changes: 15 additions & 6 deletions strum_macros/src/macros/strings/from_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,20 +53,29 @@ pub fn from_string_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
return Err(occurrence_error(fst_kw, kw, "default"));
}

default_kw = Some(kw);
default_err_ty = quote! { #strum_module_path::ParseError };

match &variant.fields {
Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {}
Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
default = quote! {
::core::result::Result::Ok(#name::#ident(s.into()))
};
}
Fields::Named(ref f) if f.named.len() == 1 => {
let field_name = f.named.last().unwrap().ident.as_ref().unwrap();
default = quote! {
::core::result::Result::Ok(#name::#ident { #field_name : s.into() } )
};
}
_ => {
return Err(syn::Error::new_spanned(
variant,
"Default only works on newtype structs with a single String field",
))
}
}
default_kw = Some(kw);
default_err_ty = quote! { #strum_module_path::ParseError };
default = quote! {
::core::result::Result::Ok(#name::#ident(s.into()))
};

continue;
}

Expand Down
22 changes: 17 additions & 5 deletions strum_macros/src/macros/strings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,26 @@ where

let pattern_and_return = match &variant.fields {
Fields::Unnamed(f) if f.unnamed.len() == 1 => {
let pat = &quote! { field0 };
let ret_val = return_val_fn(pat);
quote! { (ref #pat) => #ret_val }
let ident = &quote! { field0 };
let ref_kw = match f.unnamed.last().unwrap().ty {
syn::Type::Reference(..) => quote! { },
_ => quote! { ref },
};

let ret_val = return_val_fn(ident);
quote! { (#ref_kw #ident) => #ret_val }
}
Fields::Named(f) if f.named.len() == 1 => {
let ident = &quote! { f.named.last().unwrap().ident.as_ref().unwrap() };
let field = f.named.last().unwrap();
let ref_kw = match field.ty {
syn::Type::Reference(..) => quote! { },
_ => quote! { ref },
};

let ident = field.ident.as_ref().unwrap();
let ident = &quote! { #ident };
let ret_val = return_val_fn(ident);
quote! { {ref #ident} => #ret_val }
quote! { { #ref_kw #ident} => #ret_val }
}
_ => return Err(NonSingleFieldEnum),
};
Expand Down
9 changes: 9 additions & 0 deletions strum_tests/tests/as_ref_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ enum Color {
Green(String),
#[strum(transparent)]
Inner(InnerColor),
#[strum(transparent)]
InnerField { inner: InnerColor },
}

#[test]
Expand Down Expand Up @@ -59,6 +61,7 @@ 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());
}

#[derive(IntoStaticStr)]
Expand Down Expand Up @@ -119,6 +122,10 @@ enum Brightness {
},
#[strum(serialize = "Bright")]
BrightWhite,
#[strum(transparent)]
Gray(&'static str),
#[strum(transparent)]
Grey { inner: &'static str }
}

#[test]
Expand All @@ -134,6 +141,8 @@ fn brightness_serialize_all() {
assert_eq!("dark_black", <&'static str>::from(Brightness::DarkBlack));
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" }));
}

#[derive(IntoStaticStr)]
Expand Down
16 changes: 16 additions & 0 deletions strum_tests/tests/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ fn non_string_default_to_string() {
enum TransparentString {
#[strum(transparent)]
Something(String),

#[strum(transparent)]
SomethingNamed { my_field: String },
}

#[test]
Expand All @@ -169,3 +172,16 @@ fn transparent_string() {
)
);
}

#[test]
fn transparent_string_named_field() {
assert_eq!(
String::from("string in here"),
format!(
"{}",
TransparentString::SomethingNamed {
my_field: String::from("string in here")
}
)
);
}
12 changes: 12 additions & 0 deletions strum_tests/tests/from_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ enum Color {
White(String),
}

#[derive(Debug, Eq, PartialEq, EnumString, strum::Display)]
enum Color2 {
#[strum(default)]
Purple { inner: String }
}

#[rustversion::since(1.34)]
fn assert_from_str<'a, T>(a: T, from: &'a str)
where
Expand Down Expand Up @@ -74,6 +80,12 @@ fn color_default() {
assert_from_str(Color::Green(String::from("not found")), "not found");
}

#[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());
}

#[test]
fn color_ascii_case_insensitive() {
assert_from_str(Color::Black, "BLK");
Expand Down