Repository: Peternator7/strum
Pull request #300 (2023-09-28 15:31:13)

Fix EnumIter for enums named Option
Fixes https://github.com/Peternator7/strum/issues/299


Patch:
diff --git a/strum_macros/src/macros/enum_is.rs b/strum_macros/src/macros/enum_is.rs
index b69fa0c..ecada45 100644
--- a/strum_macros/src/macros/enum_is.rs
+++ b/strum_macros/src/macros/enum_is.rs
@@ -8,9 +8,9 @@ pub fn enum_is_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
         Data::Enum(v) => &v.variants,
         _ => return Err(non_enum_error()),
     };
+    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
 
     let enum_name = &ast.ident;
-
     let variants: Vec<_> = variants
         .iter()
         .filter_map(|variant| {
@@ -20,10 +20,11 @@ pub fn enum_is_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
 
             let variant_name = &variant.ident;
             let fn_name = format_ident!("is_{}", snakify(&variant_name.to_string()));
-
+            let doc_comment = format!("Returns [true] if the enum is [{}::{}] otherwise [false]", enum_name, variant_name);
             Some(quote! {
                 #[must_use]
                 #[inline]
+                #[doc = #doc_comment]
                 pub const fn #fn_name(&self) -> bool {
                     match self {
                         &#enum_name::#variant_name { .. } => true,
@@ -35,7 +36,7 @@ pub fn enum_is_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
         .collect();
 
     Ok(quote! {
-        impl #enum_name {
+        impl #impl_generics #enum_name  #ty_generics #where_clause {
             #(#variants)*
         }
     }
diff --git a/strum_macros/src/macros/enum_iter.rs b/strum_macros/src/macros/enum_iter.rs
index ce8237f..0e700aa 100644
--- a/strum_macros/src/macros/enum_iter.rs
+++ b/strum_macros/src/macros/enum_iter.rs
@@ -91,7 +91,7 @@ pub fn enum_iter_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
         }
 
         impl #impl_generics #iter_name #ty_generics #where_clause {
-            fn get(&self, idx: usize) -> Option<#name #ty_generics> {
+            fn get(&self, idx: usize) -> ::core::option::Option<#name #ty_generics> {
                 match idx {
                     #(#arms),*
                 }
@@ -112,16 +112,16 @@ pub fn enum_iter_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
         impl #impl_generics Iterator for #iter_name #ty_generics #where_clause {
             type Item = #name #ty_generics;
 
-            fn next(&mut self) -> Option<<Self as Iterator>::Item> {
+            fn next(&mut self) -> ::core::option::Option<<Self as Iterator>::Item> {
                 self.nth(0)
             }
 
-            fn size_hint(&self) -> (usize, Option<usize>) {
+            fn size_hint(&self) -> (usize, ::core::option::Option<usize>) {
                 let t = if self.idx + self.back_idx >= #variant_count { 0 } else { #variant_count - self.idx - self.back_idx };
                 (t, Some(t))
             }
 
-            fn nth(&mut self, n: usize) -> Option<<Self as Iterator>::Item> {
+            fn nth(&mut self, n: usize) -> ::core::option::Option<<Self as Iterator>::Item> {
                 let idx = self.idx + n + 1;
                 if idx + self.back_idx > #variant_count {
                     // We went past the end of the iterator. Freeze idx at #variant_count
@@ -143,7 +143,7 @@ pub fn enum_iter_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
         }
 
         impl #impl_generics DoubleEndedIterator for #iter_name #ty_generics #where_clause {
-            fn next_back(&mut self) -> Option<<Self as Iterator>::Item> {
+            fn next_back(&mut self) -> ::core::option::Option<<Self as Iterator>::Item> {
                 let back_idx = self.back_idx + 1;
 
                 if self.idx + back_idx > #variant_count {
diff --git a/strum_macros/src/macros/enum_properties.rs b/strum_macros/src/macros/enum_properties.rs
index 0fe389e..2583096 100644
--- a/strum_macros/src/macros/enum_properties.rs
+++ b/strum_macros/src/macros/enum_properties.rs
@@ -19,8 +19,6 @@ pub fn enum_properties_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
         let ident = &variant.ident;
         let variant_properties = variant.get_variant_properties()?;
         let mut string_arms = Vec::new();
-        let mut bool_arms = Vec::new();
-        let mut num_arms = Vec::new();
         // But you can disable the messages.
         if variant_properties.disabled.is_some() {
             continue;
@@ -37,8 +35,6 @@ pub fn enum_properties_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
         }
 
         string_arms.push(quote! { _ => ::core::option::Option::None });
-        bool_arms.push(quote! { _ => ::core::option::Option::None });
-        num_arms.push(quote! { _ => ::core::option::Option::None });
 
         arms.push(quote! {
             &#name::#ident #params => {


Test patch:
diff --git a/strum_tests/src/lib.rs b/strum_tests/src/lib.rs
index 3addd0d..eb3f65d 100644
--- a/strum_tests/src/lib.rs
+++ b/strum_tests/src/lib.rs
@@ -1,6 +1,7 @@
 use strum::{Display, EnumCount, EnumDiscriminants, EnumString};
+use strum_macros::EnumIs;
 
-#[derive(Debug, Eq, PartialEq, EnumString, Display, EnumCount, EnumDiscriminants)]
+#[derive(Debug, Eq, PartialEq, EnumString, Display, EnumCount, EnumDiscriminants, EnumIs)]
 pub enum Color {
     /// Docs on red
     #[strum(to_string = "RedRed")]
diff --git a/strum_tests/src/main.rs b/strum_tests/src/main.rs
index 4d048a6..97e348a 100644
--- a/strum_tests/src/main.rs
+++ b/strum_tests/src/main.rs
@@ -1,7 +1,8 @@
 use strum::{Display, EnumCount, EnumDiscriminants, EnumString};
+use strum_macros::EnumIs;
 
 #[allow(dead_code)]
-#[derive(Debug, Eq, PartialEq, EnumString, Display, EnumCount, EnumDiscriminants)]
+#[derive(Debug, Eq, PartialEq, EnumString, Display, EnumCount, EnumDiscriminants, EnumIs)]
 enum Color {
     /// Random Docs
     #[strum(to_string = "RedRed")]
diff --git a/strum_tests/tests/enum_is.rs b/strum_tests/tests/enum_is.rs
index 789881c..4e997fe 100644
--- a/strum_tests/tests/enum_is.rs
+++ b/strum_tests/tests/enum_is.rs
@@ -1,7 +1,12 @@
+use std::borrow::Cow;
 use strum::EnumIs;
 
 mod core {} // ensure macros call `::core`
-
+#[derive(EnumIs)]
+enum LifeTimeTest<'a>{
+    One(Cow<'a, str>),
+    Two(&'a str)
+}
 #[derive(EnumIs)]
 enum Foo {
     Unit,
@@ -16,7 +21,15 @@ enum Foo {
     #[allow(dead_code)]
     Disabled,
 }
-
+#[test]
+fn generics_test(){
+    let foo = LifeTimeTest::One(Cow::Borrowed("Hello"));
+    assert!(foo.is_one());
+    let foo = LifeTimeTest::Two("Hello");
+    assert!(foo.is_two());
+    let foo = LifeTimeTest::One(Cow::Owned("Hello".to_string()));
+    assert!(foo.is_one());
+}
 #[test]
 fn simple_test() {
     assert!(Foo::Unit.is_unit());
diff --git a/strum_tests/tests/enum_iter.rs b/strum_tests/tests/enum_iter.rs
index 313ed5c..ce6ecb2 100644
--- a/strum_tests/tests/enum_iter.rs
+++ b/strum_tests/tests/enum_iter.rs
@@ -211,3 +211,16 @@ fn crate_module_path_test() {
 
     assert_eq!(expected, results);
 }
+
+#[test]
+fn enum_iter_option() {
+    #[derive(Debug, Eq, PartialEq, EnumIter)]
+    enum Option {
+        BluePill,
+        RedPill,
+    }
+    let results = Option::iter().collect::<Vec<_>>();
+    let expected = vec![Option::BluePill, Option::RedPill];
+
+    assert_eq!(expected, results);
+}