Repository: Peternator7/strum
Pull request #421 (2025-02-17 00:16:02)

Peternator7/fix transparent typo
Incorrect refactoring on my part. This fixes that and adds a few test cases


Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
deleted file mode 100644
index e218db9..0000000
--- a/.github/workflows/ci.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-name: Rust
-
-on:
-  push:
-    branches: [ "master" ]
-  pull_request:
-    branches: [ "master" ]
-
-env:
-  CARGO_TERM_COLOR: always
-
-jobs:
-  build_and_test:
-    name: strum - latest
-    runs-on: ubuntu-latest
-    strategy:
-      matrix:
-        toolchain:
-          - 1.66.1
-          - stable
-          - beta
-          - nightly
-    steps:
-    - uses: actions/checkout@v4
-    - run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }}
-    - name: Build
-      run: cargo build --verbose
-    - name: Run tests
-      run: cargo test --verbose
diff --git a/strum/src/additional_attributes.rs b/strum/src/additional_attributes.rs
index b77a62f..b640ba4 100644
--- a/strum/src/additional_attributes.rs
+++ b/strum/src/additional_attributes.rs
@@ -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.
 //!
diff --git a/strum_macros/src/macros/strings/as_ref_str.rs b/strum_macros/src/macros/strings/as_ref_str.rs
index 4248171..f931a0b 100644
--- a/strum_macros/src/macros/strings/as_ref_str.rs
+++ b/strum_macros/src/macros/strings/as_ref_str.rs
@@ -93,7 +93,7 @@ pub fn as_static_str_inner(
 ) -> syn::Result<TokenStream> {
     let name = &ast.ident;
     let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
-    let arms = &get_arms(ast, |tok| {
+    let arms = get_arms(ast, |tok| {
         quote! { ::core::convert::From::from(#tok) }
     })?;
 
@@ -107,6 +107,8 @@ pub fn as_static_str_inner(
             parse_quote!('_derivative_strum),
         )));
     let (impl_generics2, _, _) = generics.split_for_impl();
+    let arms2 = arms.clone();
+    let arms3 = arms.clone();
 
     Ok(match trait_variant {
         GenerateTraitVariant::AsStaticStr => quote! {
@@ -124,7 +126,7 @@ pub fn as_static_str_inner(
                 #[inline]
                 fn from(x: #name #ty_generics) -> &'static str {
                     match x {
-                        #(#arms),*
+                        #(#arms2),*
                     }
                 }
             }
@@ -132,7 +134,7 @@ pub fn as_static_str_inner(
                 #[inline]
                 fn from(x: &'_derivative_strum #name #ty_generics) -> &'static str {
                     match *x {
-                        #(#arms),*
+                        #(#arms3),*
                     }
                 }
             }
@@ -141,7 +143,7 @@ pub fn as_static_str_inner(
             impl #impl_generics #name #ty_generics #where_clause {
                 pub const fn into_str(&self) -> &'static str {
                     match self {
-                        #(#arms),*
+                        #(#arms3),*
                     }
                 }
             }
@@ -149,7 +151,7 @@ pub fn as_static_str_inner(
             impl #impl_generics ::core::convert::From<#name #ty_generics> for &'static str #where_clause {
                 fn from(x: #name #ty_generics) -> &'static str {
                     match x {
-                        #(#arms),*
+                        #(#arms2),*
                     }
                 }
             }
diff --git a/strum_macros/src/macros/strings/display.rs b/strum_macros/src/macros/strings/display.rs
index 66dfeeb..cfce6c8 100644
--- a/strum_macros/src/macros/strings/display.rs
+++ b/strum_macros/src/macros/strings/display.rs
@@ -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"))?;
 
diff --git a/strum_macros/src/macros/strings/from_string.rs b/strum_macros/src/macros/strings/from_string.rs
index 9b95567..505f89f 100644
--- a/strum_macros/src/macros/strings/from_string.rs
+++ b/strum_macros/src/macros/strings/from_string.rs
@@ -53,8 +53,21 @@ 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,
@@ -62,11 +75,7 @@ pub fn from_string_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
                     ))
                 }
             }
-            default_kw = Some(kw);
-            default_err_ty = quote! { #strum_module_path::ParseError };
-            default = quote! {
-                ::core::result::Result::Ok(#name::#ident(s.into()))
-            };
+
             continue;
         }
 
diff --git a/strum_macros/src/macros/strings/mod.rs b/strum_macros/src/macros/strings/mod.rs
index 52a6a0b..041e63b 100644
--- a/strum_macros/src/macros/strings/mod.rs
+++ b/strum_macros/src/macros/strings/mod.rs
@@ -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),
     };


Test patch:
diff --git a/strum_tests/tests/as_ref_str.rs b/strum_tests/tests/as_ref_str.rs
index 9c38644..d20cc83 100644
--- a/strum_tests/tests/as_ref_str.rs
+++ b/strum_tests/tests/as_ref_str.rs
@@ -30,6 +30,8 @@ enum Color {
     Green(String),
     #[strum(transparent)]
     Inner(InnerColor),
+    #[strum(transparent)]
+    InnerField { inner: InnerColor },
 }
 
 #[test]
@@ -59,12 +61,12 @@ 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)]
 enum Foo<'a> {
     A,
-    #[allow(dead_code)]
     C(&'a i32),
 }
 
@@ -72,7 +74,6 @@ enum Foo<'a> {
 enum Boo<'a, T> {
     A(T),
     B,
-    #[allow(dead_code)]
     C(&'a i32),
 }
 
@@ -83,7 +84,6 @@ where
 {
     A(T),
     B,
-    #[allow(dead_code)]
     C(&'a i32),
 }
 
@@ -122,6 +122,10 @@ enum Brightness {
     },
     #[strum(serialize = "Bright")]
     BrightWhite,
+    #[strum(transparent)]
+    Gray(&'static str),
+    #[strum(transparent)]
+    Grey { inner: &'static str }
 }
 
 #[test]
@@ -137,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)]
@@ -147,7 +153,6 @@ where
 {
     A(T),
     B,
-    #[allow(dead_code)]
     C(&'a i32),
     #[strum(serialize = "Dark")]
     D,
@@ -155,7 +160,6 @@ where
     G,
     #[strum(serialize = "b", to_string = "blue")]
     Blue {
-        #[allow(dead_code)]
         hue: usize,
     },
     #[strum(serialize = "y", serialize = "yellow")]
@@ -166,7 +170,6 @@ where
 #[strum(const_into_str)]
 enum Baz<'a, T> {
     A(T),
-    #[allow(dead_code)]
     C(&'a i32),
 }
 
@@ -176,7 +179,6 @@ enum Baz<'a, T> {
 enum BrightnessConst {
     DarkBlack,
     Dim {
-        #[allow(dead_code)]
         glow: usize,
     },
     #[strum(serialize = "Bright")]
diff --git a/strum_tests/tests/display.rs b/strum_tests/tests/display.rs
index fffd0b6..7d69d54 100644
--- a/strum_tests/tests/display.rs
+++ b/strum_tests/tests/display.rs
@@ -157,6 +157,9 @@ fn non_string_default_to_string() {
 enum TransparentString {
     #[strum(transparent)]
     Something(String),
+
+    #[strum(transparent)]
+    SomethingNamed { my_field: String },
 }
 
 #[test]
@@ -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")
+            }
+        )
+    );
+}
diff --git a/strum_tests/tests/enum_is.rs b/strum_tests/tests/enum_is.rs
index 0fe42db..d45ae4c 100644
--- a/strum_tests/tests/enum_is.rs
+++ b/strum_tests/tests/enum_is.rs
@@ -3,13 +3,11 @@ use strum::EnumIs;
 
 mod core {} // ensure macros call `::core`
 #[derive(EnumIs)]
-#[allow(dead_code)]
 enum LifeTimeTest<'a> {
     One(Cow<'a, str>),
     Two(&'a str),
 }
 #[derive(EnumIs)]
-#[allow(dead_code)]
 enum Foo {
     Unit,
     Named0 {},
diff --git a/strum_tests/tests/enum_variant_table.rs b/strum_tests/tests/enum_variant_table.rs
index 1661cad..25e854f 100644
--- a/strum_tests/tests/enum_variant_table.rs
+++ b/strum_tests/tests/enum_variant_table.rs
@@ -1,7 +1,6 @@
 use strum::EnumTable;
 
 #[derive(EnumTable)]
-#[allow(dead_code)]
 enum Color {
     Red,
     Yellow,
@@ -16,7 +15,6 @@ enum Color {
 // even though this isn't used, it needs to be a test
 // because if it doesn't compile, enum variants that conflict with keywords won't work
 #[derive(EnumTable)]
-#[allow(dead_code)]
 enum Keyword {
     Const,
 }
diff --git a/strum_tests/tests/from_repr.rs b/strum_tests/tests/from_repr.rs
index 52603ac..4e8f0ec 100644
--- a/strum_tests/tests/from_repr.rs
+++ b/strum_tests/tests/from_repr.rs
@@ -44,7 +44,6 @@ fn const_test() {
 fn crate_module_path_test() {
     pub mod nested {
         pub mod module {
-            #[allow(unused_imports)]
             pub use strum;
         }
     }
diff --git a/strum_tests/tests/from_str.rs b/strum_tests/tests/from_str.rs
index 31456e1..2f3acde 100644
--- a/strum_tests/tests/from_str.rs
+++ b/strum_tests/tests/from_str.rs
@@ -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
@@ -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");