Repository: Peternator7/strum
Pull request #261 (2023-03-26 23:12:10)

Update syn to v2
This updates `syn` to v2. Changes involved:

- Removing the `Spanned` requirement from `get_metadata_inner()` since it no longer seems needed and `Spanned` now requires `ToTokens` to be implemented on the type too
- Changing `parse_terminated()`'s arguments to take the delimiter instead of passing it with a turbo-fish
- Switching `path` to the method for `Attribute`s
- Changing the structure of how literals are expressed for meta name-values
- Matching the old structure of how tokenstreams were represented for `Attribute`'s
  - I tried to minimize the changes required to match the old parsing. A `Meta::List(_)` holds an internal tokenstream which could be used, but it's the tokenstream inside the group instead of the containing token-group itself. Instead I opted for taking the surrounding tokenstream and discarding the leading path to get at the group

CosmicHorrorDev: `syn` bumped its MSRV up to 1.56, so it's expected that the builds back on 1.32 would fail
smoelius: Can I please ask what the status of this PR is?

Patch:
diff --git a/README.md b/README.md
index e37b67a..484630c 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@ Strum is a set of macros and traits for working with enums and strings easier in
 
 # Compatibility
 
-Strum is currently with versions of rustc >= 1.32.0. Pull Requests that improve compatibility with older
+Strum is currently compatible with versions of rustc >= 1.32.0. Pull Requests that improve compatibility with older
 versions are welcome. The project goal is to support a rust version for at least 2 years after release 
 and even longer is preferred since this project changes slowly.
 
diff --git a/strum/src/additional_attributes.rs b/strum/src/additional_attributes.rs
index a7ae756..a29f1d6 100644
--- a/strum/src/additional_attributes.rs
+++ b/strum/src/additional_attributes.rs
@@ -20,11 +20,9 @@
 //!   - `Train-Case`
 //!
 //!   ```rust
-//!   use std::string::ToString;
-//!   use strum;
 //!   use strum_macros;
 //!   
-//!   #[derive(Debug, Eq, PartialEq, strum_macros::ToString)]
+//!   #[derive(Debug, Eq, PartialEq, strum_macros::Display)]
 //!   #[strum(serialize_all = "snake_case")]
 //!   enum Brightness {
 //!       DarkBlack,
diff --git a/strum_macros/Cargo.toml b/strum_macros/Cargo.toml
index bdb1c3c..60e5b57 100644
--- a/strum_macros/Cargo.toml
+++ b/strum_macros/Cargo.toml
@@ -23,7 +23,7 @@ heck = "0.4.1"
 proc-macro2 = "1.0"
 quote = "1.0"
 rustversion = "1.0"
-syn = { version = "1.0", features = ["parsing", "extra-traits"] }
+syn = { version = "2.0", features = ["parsing", "extra-traits"] }
 
 [dev-dependencies]
 strum = "0.24"
diff --git a/strum_macros/src/helpers/metadata.rs b/strum_macros/src/helpers/metadata.rs
index 56e4c78..d638ae3 100644
--- a/strum_macros/src/helpers/metadata.rs
+++ b/strum_macros/src/helpers/metadata.rs
@@ -1,12 +1,11 @@
-use proc_macro2::{Span, TokenStream};
+use proc_macro2::TokenStream;
 use syn::{
     parenthesized,
     parse::{Parse, ParseStream},
     parse2, parse_str,
     punctuated::Punctuated,
-    spanned::Spanned,
-    Attribute, DeriveInput, Ident, Lit, LitBool, LitStr, Meta, MetaNameValue, Path, Token, Variant,
-    Visibility,
+    Attribute, DeriveInput, Expr, ExprLit, Ident, Lit, LitBool, LitStr, Meta, MetaNameValue, Path,
+    Token, Variant, Visibility,
 };
 
 use super::case_style::CaseStyle;
@@ -76,17 +75,6 @@ impl Parse for EnumMeta {
     }
 }
 
-impl Spanned for EnumMeta {
-    fn span(&self) -> Span {
-        match self {
-            EnumMeta::SerializeAll { kw, .. } => kw.span(),
-            EnumMeta::AsciiCaseInsensitive(kw) => kw.span(),
-            EnumMeta::Crate { kw, .. } => kw.span(),
-            EnumMeta::UsePhf(use_phf) => use_phf.span(),
-        }
-    }
-}
-
 pub enum EnumDiscriminantsMeta {
     Derive { kw: kw::derive, paths: Vec<Path> },
     Name { kw: kw::name, name: Ident },
@@ -100,7 +88,7 @@ impl Parse for EnumDiscriminantsMeta {
             let kw = input.parse()?;
             let content;
             parenthesized!(content in input);
-            let paths = content.parse_terminated::<_, Token![,]>(Path::parse)?;
+            let paths = content.parse_terminated(Path::parse, Token![,])?;
             Ok(EnumDiscriminantsMeta::Derive {
                 kw,
                 paths: paths.into_iter().collect(),
@@ -127,17 +115,6 @@ impl Parse for EnumDiscriminantsMeta {
     }
 }
 
-impl Spanned for EnumDiscriminantsMeta {
-    fn span(&self) -> Span {
-        match self {
-            EnumDiscriminantsMeta::Derive { kw, .. } => kw.span,
-            EnumDiscriminantsMeta::Name { kw, .. } => kw.span,
-            EnumDiscriminantsMeta::Vis { kw, .. } => kw.span,
-            EnumDiscriminantsMeta::Other { path, .. } => path.span(),
-        }
-    }
-}
-
 pub trait DeriveInputExt {
     /// Get all the strum metadata associated with an enum.
     fn get_metadata(&self) -> syn::Result<Vec<EnumMeta>>;
@@ -228,7 +205,7 @@ impl Parse for VariantMeta {
             let kw = input.parse()?;
             let content;
             parenthesized!(content in input);
-            let props = content.parse_terminated::<_, Token![,]>(Prop::parse)?;
+            let props = content.parse_terminated(Prop::parse, Token![,])?;
             Ok(VariantMeta::Props {
                 kw,
                 props: props
@@ -256,22 +233,6 @@ impl Parse for Prop {
     }
 }
 
-impl Spanned for VariantMeta {
-    fn span(&self) -> Span {
-        match self {
-            VariantMeta::Message { kw, .. } => kw.span,
-            VariantMeta::DetailedMessage { kw, .. } => kw.span,
-            VariantMeta::Documentation { value } => value.span(),
-            VariantMeta::Serialize { kw, .. } => kw.span,
-            VariantMeta::ToString { kw, .. } => kw.span,
-            VariantMeta::Disabled(kw) => kw.span,
-            VariantMeta::Default(kw) => kw.span,
-            VariantMeta::AsciiCaseInsensitive { kw, .. } => kw.span,
-            VariantMeta::Props { kw, .. } => kw.span,
-        }
-    }
-}
-
 pub trait VariantExt {
     /// Get all the metadata associated with an enum variant.
     fn get_metadata(&self) -> syn::Result<Vec<VariantMeta>>;
@@ -282,26 +243,32 @@ impl VariantExt for Variant {
         let result = get_metadata_inner("strum", &self.attrs)?;
         self.attrs
             .iter()
-            .filter(|attr| attr.path.is_ident("doc"))
+            .filter(|attr| attr.path().is_ident("doc"))
             .try_fold(result, |mut vec, attr| {
                 if let Meta::NameValue(MetaNameValue {
-                    lit: Lit::Str(value),
+                    value:
+                        Expr::Lit(ExprLit {
+                            lit: Lit::Str(value),
+                            ..
+                        }),
                     ..
-                }) = attr.parse_meta()?
+                }) = &attr.meta
                 {
-                    vec.push(VariantMeta::Documentation { value })
+                    vec.push(VariantMeta::Documentation {
+                        value: value.clone(),
+                    })
                 }
                 Ok(vec)
             })
     }
 }
 
-fn get_metadata_inner<'a, T: Parse + Spanned>(
+fn get_metadata_inner<'a, T: Parse>(
     ident: &str,
     it: impl IntoIterator<Item = &'a Attribute>,
 ) -> syn::Result<Vec<T>> {
     it.into_iter()
-        .filter(|attr| attr.path.is_ident(ident))
+        .filter(|attr| attr.path().is_ident(ident))
         .try_fold(Vec::new(), |mut vec, attr| {
             vec.extend(attr.parse_args_with(Punctuated::<T, Token![,]>::parse_terminated)?);
             Ok(vec)
diff --git a/strum_macros/src/macros/enum_count.rs b/strum_macros/src/macros/enum_count.rs
index 44c7f2e..b9e6aaa 100644
--- a/strum_macros/src/macros/enum_count.rs
+++ b/strum_macros/src/macros/enum_count.rs
@@ -2,11 +2,18 @@ use proc_macro2::TokenStream;
 use quote::quote;
 use syn::{Data, DeriveInput};
 
+use crate::helpers::variant_props::HasStrumVariantProperties;
 use crate::helpers::{non_enum_error, HasTypeProperties};
 
 pub(crate) fn enum_count_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
     let n = match &ast.data {
-        Data::Enum(v) => v.variants.len(),
+        Data::Enum(v) => v.variants.iter().try_fold(0usize, |acc, v| {
+            if v.get_variant_properties()?.disabled.is_none() {
+                Ok::<usize, syn::Error>(acc + 1usize)
+            } else {
+                Ok::<usize, syn::Error>(acc)
+            }
+        })?,
         _ => return Err(non_enum_error()),
     };
     let type_properties = ast.get_type_properties()?;
diff --git a/strum_macros/src/macros/enum_discriminants.rs b/strum_macros/src/macros/enum_discriminants.rs
index 66eee46..4e54a30 100644
--- a/strum_macros/src/macros/enum_discriminants.rs
+++ b/strum_macros/src/macros/enum_discriminants.rs
@@ -53,14 +53,16 @@ pub fn enum_discriminants_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
             .filter(|attr| {
                 ATTRIBUTES_TO_COPY
                     .iter()
-                    .any(|attr_whitelisted| attr.path.is_ident(attr_whitelisted))
+                    .any(|attr_whitelisted| attr.path().is_ident(attr_whitelisted))
             })
             .map(|attr| {
-                if attr.path.is_ident("strum_discriminants") {
-                    let passthrough_group = attr
-                        .tokens
-                        .clone()
-                        .into_iter()
+                if attr.path().is_ident("strum_discriminants") {
+                    let mut ts = attr.meta.require_list()?.to_token_stream().into_iter();
+
+                    // Discard strum_discriminants(...)
+                    let _ = ts.next();
+
+                    let passthrough_group = ts
                         .next()
                         .ok_or_else(|| strum_discriminants_passthrough_error(attr))?;
                     let passthrough_attribute = match passthrough_group {
diff --git a/strum_macros/src/macros/from_repr.rs b/strum_macros/src/macros/from_repr.rs
index ec9f557..811467e 100644
--- a/strum_macros/src/macros/from_repr.rs
+++ b/strum_macros/src/macros/from_repr.rs
@@ -1,6 +1,6 @@
 use heck::ToShoutySnakeCase;
 use proc_macro2::{Span, TokenStream};
-use quote::{format_ident, quote};
+use quote::{format_ident, quote, ToTokens};
 use syn::{Data, DeriveInput, Fields, PathArguments, Type, TypeParen};
 
 use crate::helpers::{non_enum_error, HasStrumVariantProperties};
@@ -14,8 +14,13 @@ pub fn from_repr_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
 
     let mut discriminant_type: Type = syn::parse("usize".parse().unwrap()).unwrap();
     for attr in attrs {
-        let path = &attr.path;
-        let tokens = &attr.tokens;
+        let path = attr.path();
+
+        let mut ts = attr.meta.require_list()?.to_token_stream().into_iter();
+        // Discard the path
+        let _ = ts.next();
+        let tokens: TokenStream = ts.collect();
+
         if path.leading_colon.is_some() {
             continue;
         }
diff --git a/strum_macros/src/macros/strings/as_ref_str.rs b/strum_macros/src/macros/strings/as_ref_str.rs
index 4dfdc4b..617b887 100644
--- a/strum_macros/src/macros/strings/as_ref_str.rs
+++ b/strum_macros/src/macros/strings/as_ref_str.rs
@@ -80,7 +80,7 @@ pub fn as_static_str_inner(
     let mut generics = ast.generics.clone();
     generics
         .params
-        .push(syn::GenericParam::Lifetime(syn::LifetimeDef::new(
+        .push(syn::GenericParam::Lifetime(syn::LifetimeParam::new(
             parse_quote!('_derivative_strum),
         )));
     let (impl_generics2, _, _) = generics.split_for_impl();


Test patch:
diff --git a/strum_tests/tests/enum_count.rs b/strum_tests/tests/enum_count.rs
index 794e563..db98110 100644
--- a/strum_tests/tests/enum_count.rs
+++ b/strum_tests/tests/enum_count.rs
@@ -11,12 +11,29 @@ enum Week {
     Saturday,
 }
 
+#[allow(dead_code)]
+#[derive(Debug, EnumCount, EnumIter)]
+enum Pets {
+    Dog,
+    Cat,
+    Fish,
+    Bird,
+    #[strum(disabled)]
+    Hamster,
+}
+
 #[test]
 fn simple_test() {
     assert_eq!(7, Week::COUNT);
     assert_eq!(Week::iter().count(), Week::COUNT);
 }
 
+#[test]
+fn disabled_test() {
+    assert_eq!(4, Pets::COUNT);
+    assert_eq!(Pets::iter().count(), Pets::COUNT);
+}
+
 #[test]
 fn crate_module_path_test() {
     pub mod nested {