Repository: Peternator7/strum
Pull request #435 (2025-04-22 20:48:51)

allow discriminants on empty enum
Solves issue #433 


Patch:
diff --git a/strum/Cargo.toml b/strum/Cargo.toml
index 2fe217c..54a2db5 100644
--- a/strum/Cargo.toml
+++ b/strum/Cargo.toml
@@ -17,7 +17,7 @@ rust-version = "1.66.1"
 
 [dependencies]
 strum_macros = { path = "../strum_macros", optional = true, version = "0.27.1" }
-phf = { version = "0.11", features = ["macros"], optional = true }
+phf = { version = "0.12", features = ["macros"], optional = true }
 
 [dev-dependencies]
 strum_macros = { path = "../strum_macros" }
diff --git a/strum_macros/Cargo.toml b/strum_macros/Cargo.toml
index 06f73ab..2a6a64b 100644
--- a/strum_macros/Cargo.toml
+++ b/strum_macros/Cargo.toml
@@ -23,7 +23,6 @@ name = "strum_macros"
 heck = "0.5.0"
 proc-macro2 = "1.0"
 quote = "1.0"
-rustversion = "1.0"
 syn = { version = "2.0", features = ["parsing"] }
 
 [dev-dependencies]
diff --git a/strum_macros/src/lib.rs b/strum_macros/src/lib.rs
index a310a53..c9af84b 100644
--- a/strum_macros/src/lib.rs
+++ b/strum_macros/src/lib.rs
@@ -658,15 +658,10 @@ pub fn enum_table(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
 ///     Three = 3,
 /// }
 ///
-/// # #[rustversion::since(1.46)]
 /// const fn number_from_repr(d: u8) -> Option<Number> {
 ///     Number::from_repr(d)
 /// }
 ///
-/// # #[rustversion::before(1.46)]
-/// # fn number_from_repr(d: u8) -> Option<Number> {
-/// #     Number::from_repr(d)
-/// # }
 /// assert_eq!(None, number_from_repr(0));
 /// assert_eq!(Some(Number::One), number_from_repr(1));
 /// assert_eq!(None, number_from_repr(2));
diff --git a/strum_macros/src/macros/enum_discriminants.rs b/strum_macros/src/macros/enum_discriminants.rs
index 2f840bb..3f0ca80 100644
--- a/strum_macros/src/macros/enum_discriminants.rs
+++ b/strum_macros/src/macros/enum_discriminants.rs
@@ -136,7 +136,12 @@ pub fn enum_discriminants_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
         })
         .collect::<Vec<_>>();
 
-    let from_fn_body = quote! { match val { #(#arms),* } };
+    let from_fn_body = if variants.is_empty() {
+        //this method on empty enum is impossible to be called. it is therefor left empty
+        quote! { unreachable!()}
+    } else {
+        quote! { match val { #(#arms),* } }
+    };
 
     let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
     let impl_from = quote! {
diff --git a/strum_macros/src/macros/from_repr.rs b/strum_macros/src/macros/from_repr.rs
index f372b6e..5ff0390 100644
--- a/strum_macros/src/macros/from_repr.rs
+++ b/strum_macros/src/macros/from_repr.rs
@@ -97,16 +97,7 @@ pub fn from_repr_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
     let const_if_possible = if has_additional_data {
         quote! {}
     } else {
-        #[rustversion::before(1.46)]
-        fn filter_by_rust_version(_: TokenStream) -> TokenStream {
-            quote! {}
-        }
-
-        #[rustversion::since(1.46)]
-        fn filter_by_rust_version(s: TokenStream) -> TokenStream {
-            s
-        }
-        filter_by_rust_version(quote! { const })
+        quote! { const }
     };
 
     Ok(quote! {
diff --git a/strum_macros/src/macros/strings/from_string.rs b/strum_macros/src/macros/strings/from_string.rs
index 505f89f..2dee52b 100644
--- a/strum_macros/src/macros/strings/from_string.rs
+++ b/strum_macros/src/macros/strings/from_string.rs
@@ -195,18 +195,6 @@ pub fn from_string_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
     })
 }
 
-#[rustversion::before(1.34)]
-fn try_from_str(
-    _name: &proc_macro2::Ident,
-    _impl_generics: &syn::ImplGenerics,
-    _ty_generics: &syn::TypeGenerics,
-    _where_clause: Option<&syn::WhereClause>,
-    _strum_module_path: &syn::Path,
-) -> TokenStream {
-    Default::default()
-}
-
-#[rustversion::since(1.34)]
 fn try_from_str(
     name: &proc_macro2::Ident,
     impl_generics: &syn::ImplGenerics,


Test patch:
diff --git a/strum_nostd_tests/Cargo.toml b/strum_nostd_tests/Cargo.toml
index 945c609..f07ec9a 100644
--- a/strum_nostd_tests/Cargo.toml
+++ b/strum_nostd_tests/Cargo.toml
@@ -7,6 +7,3 @@ rust-version = "1.66.1"
 [dependencies]
 strum = { path = "../strum", features = ["derive"] }
 strum_macros = { path = "../strum_macros", features = [] }
-
-[dev-dependencies]
-rustversion = "1.0"
diff --git a/strum_nostd_tests/src/lib.rs b/strum_nostd_tests/src/lib.rs
index 251fe03..4e07e96 100644
--- a/strum_nostd_tests/src/lib.rs
+++ b/strum_nostd_tests/src/lib.rs
@@ -25,13 +25,8 @@ mod tests {
     }
 
     #[test]
-    #[rustversion::since(1.34)]
     fn try_from_str_no_std() {
         use core::convert::TryFrom;
         assert_eq!(Color::Yellow, Color::try_from("yellow").unwrap());
     }
-
-    #[test]
-    #[rustversion::before(1.34)]
-    fn try_from_str_no_std() {}
 }
diff --git a/strum_tests/Cargo.toml b/strum_tests/Cargo.toml
index 1fbd0ab..570817d 100644
--- a/strum_tests/Cargo.toml
+++ b/strum_tests/Cargo.toml
@@ -15,6 +15,3 @@ strum_macros = { path = "../strum_macros", features = [] }
 clap = "=4.2.7"
 enum_variant_type = "=0.2.0"
 structopt = "=0.3.26"
-
-[dev-dependencies]
-rustversion = "1.0"
diff --git a/strum_tests/tests/enum_discriminants.rs b/strum_tests/tests/enum_discriminants.rs
index d6e4668..fcbcf17 100644
--- a/strum_tests/tests/enum_discriminants.rs
+++ b/strum_tests/tests/enum_discriminants.rs
@@ -3,6 +3,7 @@ use std::mem::{align_of, size_of};
 use enum_variant_type::EnumVariantType;
 use strum::{
     Display, EnumDiscriminants, EnumIter, EnumMessage, EnumString, FromRepr, IntoEnumIterator,
+    VariantArray,
 };
 
 mod core {} // ensure macros call `::core`
@@ -211,7 +212,6 @@ fn from_ref_test_complex() {
 }
 
 #[allow(dead_code)]
-#[rustversion::since(1.34)]
 #[derive(Debug, Eq, PartialEq, EnumDiscriminants, EnumVariantType)]
 #[strum_discriminants(
     name(VariantFilterAttrDiscs),
@@ -225,8 +225,7 @@ enum VariantFilterAttr {
     BrightWhite(i32),
 }
 
-#[rustversion::attr(since(1.34), test)]
-#[rustversion::since(1.34)]
+#[test]
 fn filter_variant_attributes_pass_through() {
     use std::str::FromStr;
 
@@ -245,7 +244,6 @@ fn filter_variant_attributes_pass_through() {
 }
 
 #[test]
-#[rustversion::since(1.34)]
 fn override_visibility() {
     mod private {
         use super::*;
@@ -265,27 +263,6 @@ fn override_visibility() {
     );
 }
 
-#[test]
-#[rustversion::before(1.34)]
-fn override_visibility() {
-    mod private {
-        use super::*;
-
-        #[allow(dead_code)]
-        #[derive(EnumDiscriminants)]
-        #[strum_discriminants(name(PubDiscriminants), vis(r#pub))]
-        enum PrivateEnum {
-            VariantA(bool),
-            VariantB(bool),
-        }
-    }
-
-    assert_ne!(
-        private::PubDiscriminants::VariantA,
-        private::PubDiscriminants::VariantB,
-    );
-}
-
 #[test]
 fn crate_module_path_test() {
     pub mod nested {
@@ -363,3 +340,16 @@ fn with_explicit_discriminant_value() {
         WithExplicitDicriminantValueDiscriminants::Variant0 as u8
     );
 }
+
+#[allow(dead_code)]
+#[derive(Debug, Eq, PartialEq, EnumIter, EnumDiscriminants)]
+#[strum_discriminants(derive(EnumIter, VariantArray))]
+enum Empty {}
+
+#[test]
+fn empty_test() {
+    let discriminants = Empty::iter().map(|i| i.into()).collect::<Vec<_>>();
+    let expected: Vec<_> = EmptyDiscriminants::VARIANTS.to_vec();
+
+    assert_eq!(expected, discriminants);
+}
diff --git a/strum_tests/tests/from_repr.rs b/strum_tests/tests/from_repr.rs
index 52603ac..4daf3e1 100644
--- a/strum_tests/tests/from_repr.rs
+++ b/strum_tests/tests/from_repr.rs
@@ -25,7 +25,6 @@ fn simple_test() {
     assert_eq!(Week::from_repr(9), None);
 }
 
-#[rustversion::since(1.46)]
 #[test]
 fn const_test() {
     // This is to test that it works in a const fn
diff --git a/strum_tests/tests/from_str.rs b/strum_tests/tests/from_str.rs
index 2f3acde..8569fd3 100644
--- a/strum_tests/tests/from_str.rs
+++ b/strum_tests/tests/from_str.rs
@@ -34,7 +34,6 @@ enum Color2 {
     Purple { inner: String }
 }
 
-#[rustversion::since(1.34)]
 fn assert_from_str<'a, T>(a: T, from: &'a str)
 where
     T: PartialEq + std::str::FromStr + std::convert::TryFrom<&'a str> + std::fmt::Debug,
@@ -45,15 +44,6 @@ where
     assert_eq!(a, std::convert::TryFrom::try_from(from).unwrap());
 }
 
-#[rustversion::before(1.34)]
-fn assert_from_str<T>(a: T, from: &str)
-where
-    T: PartialEq + std::str::FromStr + std::fmt::Debug,
-    <T as std::str::FromStr>::Err: std::fmt::Debug,
-{
-    assert_eq!(a, T::from_str(from).unwrap());
-}
-
 #[test]
 fn color_simple() {
     assert_from_str(Color::Red, "Red");
@@ -183,7 +173,6 @@ fn case_insensitive_enum_no_case_insensitive() {
     assert!(CaseInsensitiveEnum::from_str("nocaseinsensitive").is_err());
 }
 
-#[rustversion::since(1.34)]
 #[test]
 fn case_insensitive_enum_no_case_insensitive_try_from() {
     assert_from_str(CaseInsensitiveEnum::NoCaseInsensitive, "NoCaseInsensitive");