//! # Strum //! //! Strum is a set of macros and traits for working with //! enums and strings easier in Rust. //! #![recursion_limit = "128"] extern crate proc_macro; mod helpers; mod macros; use proc_macro2::TokenStream; use std::env; use syn::DeriveInput; fn debug_print_generated(ast: &DeriveInput, toks: &TokenStream) { let debug = env::var("STRUM_DEBUG"); if let Ok(s) = debug { if s == "1" { println!("{}", toks); } if ast.ident == s { println!("{}", toks); } } } /// Converts strings to enum variants based on their name. /// /// auto-derives `std::str::FromStr` on the enum (for Rust 1.34 and above, `std::convert::TryFrom<&str>` /// will be derived as well). Each variant of the enum will match on it's own name. /// This can be overridden using `serialize="DifferentName"` or `to_string="DifferentName"` /// on the attribute as shown below. /// Multiple deserializations can be added to the same variant. If the variant contains additional data, /// they will be set to their default values upon deserialization. /// /// The `default` attribute can be applied to a tuple variant with a single data parameter. When a match isn't /// found, the given variant will be returned and the input string will be captured in the parameter. /// /// Note that the implementation of `FromStr` by default only matches on the name of the /// variant. There is an option to match on different case conversions through the /// `#[strum(serialize_all = "snake_case")]` type attribute. /// /// See the [Additional Attributes](https://docs.rs/strum/0.22/strum/additional_attributes/index.html) /// Section for more information on using this feature. /// /// If you have a large enum, you may want to consider using the `use_phf` attribute here. It leverages /// perfect hash functions to parse much quicker than a standard `match`. (MSRV 1.46) /// /// # Example howto use `EnumString` /// ``` /// use std::str::FromStr; /// use strum_macros::EnumString; /// /// #[derive(Debug, PartialEq, EnumString)] /// enum Color { /// Red, /// // The Default value will be inserted into range if we match "Green". /// Green { /// range: usize, /// }, /// /// // We can match on multiple different patterns. /// #[strum(serialize = "blue", serialize = "b")] /// Blue(usize), /// /// // Notice that we can disable certain variants from being found /// #[strum(disabled)] /// Yellow, /// /// // We can make the comparison case insensitive (however Unicode is not supported at the moment) /// #[strum(ascii_case_insensitive)] /// Black, /// } /// /// /* /// //The generated code will look like: /// impl std::str::FromStr for Color { /// type Err = ::strum::ParseError; /// /// fn from_str(s: &str) -> ::core::result::Result { /// match s { /// "Red" => ::core::result::Result::Ok(Color::Red), /// "Green" => ::core::result::Result::Ok(Color::Green { range:Default::default() }), /// "blue" => ::core::result::Result::Ok(Color::Blue(Default::default())), /// "b" => ::core::result::Result::Ok(Color::Blue(Default::default())), /// s if s.eq_ignore_ascii_case("Black") => ::core::result::Result::Ok(Color::Black), /// _ => ::core::result::Result::Err(::strum::ParseError::VariantNotFound), /// } /// } /// } /// */ /// /// // simple from string /// let color_variant = Color::from_str("Red").unwrap(); /// assert_eq!(Color::Red, color_variant); /// // short version works too /// let color_variant = Color::from_str("b").unwrap(); /// assert_eq!(Color::Blue(0), color_variant); /// // was disabled for parsing = returns parse-error /// let color_variant = Color::from_str("Yellow"); /// assert!(color_variant.is_err()); /// // however the variant is still normally usable /// println!("{:?}", Color::Yellow); /// let color_variant = Color::from_str("bLACk").unwrap(); /// assert_eq!(Color::Black, color_variant); /// ``` #[proc_macro_derive(EnumString, attributes(strum))] pub fn from_string(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse_macro_input!(input as DeriveInput); let toks = macros::from_string::from_string_inner(&ast).unwrap_or_else(|err| err.to_compile_error()); debug_print_generated(&ast, &toks); toks.into() } /// Converts enum variants to `&'static str`. /// /// Implements `AsRef` on your enum using the same rules as /// `Display` for determining what string is returned. The difference is that `as_ref()` returns /// a `&str` instead of a `String` so you don't allocate any additional memory with each call. /// /// ``` /// // You need to bring the AsRef trait into scope to use it /// use std::convert::AsRef; /// use strum_macros::AsRefStr; /// /// #[derive(AsRefStr, Debug)] /// enum Color { /// #[strum(serialize = "redred")] /// Red, /// Green { /// range: usize, /// }, /// Blue(usize), /// Yellow, /// } /// /// // uses the serialize string for Display /// let red = Color::Red; /// assert_eq!("redred", red.as_ref()); /// // by default the variants Name /// let yellow = Color::Yellow; /// assert_eq!("Yellow", yellow.as_ref()); /// // or for string formatting /// println!( /// "blue: {} green: {}", /// Color::Blue(10).as_ref(), /// Color::Green { range: 42 }.as_ref() /// ); /// ``` #[proc_macro_derive(AsRefStr, attributes(strum))] pub fn as_ref_str(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse_macro_input!(input as DeriveInput); let toks = macros::as_ref_str::as_ref_str_inner(&ast).unwrap_or_else(|err| err.to_compile_error()); debug_print_generated(&ast, &toks); toks.into() } /// Implements `Strum::VariantNames` which adds an associated constant `VARIANTS` which is an array of discriminant names. /// /// Adds an `impl` block for the `enum` that adds a static `VARIANTS` array of `&'static str` that are the discriminant names. /// This will respect the `serialize_all` attribute on the `enum` (like `#[strum(serialize_all = "snake_case")]`. /// /// ``` /// // import the macros needed /// use strum_macros::{EnumString, EnumVariantNames}; /// // You need to import the trait, to have access to VARIANTS /// use strum::VariantNames; /// /// #[derive(Debug, EnumString, EnumVariantNames)] /// #[strum(serialize_all = "kebab_case")] /// enum Color { /// Red, /// Blue, /// Yellow, /// RebeccaPurple, /// } /// assert_eq!(["red", "blue", "yellow", "rebecca-purple"], Color::VARIANTS); /// ``` #[proc_macro_derive(EnumVariantNames, attributes(strum))] pub fn variant_names(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse_macro_input!(input as DeriveInput); let toks = macros::enum_variant_names::enum_variant_names_inner(&ast) .unwrap_or_else(|err| err.to_compile_error()); debug_print_generated(&ast, &toks); toks.into() } #[proc_macro_derive(AsStaticStr, attributes(strum))] #[deprecated( since = "0.22.0", note = "please use `#[derive(IntoStaticStr)]` instead" )] pub fn as_static_str(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse_macro_input!(input as DeriveInput); let toks = macros::as_ref_str::as_static_str_inner( &ast, ¯os::as_ref_str::GenerateTraitVariant::AsStaticStr, ) .unwrap_or_else(|err| err.to_compile_error()); debug_print_generated(&ast, &toks); toks.into() } /// Implements `From for &'static str` on an enum. /// /// Implements `From` and `From<&'a YourEnum>` for `&'static str`. This is /// useful for turning an enum variant into a static string. /// The Rust `std` provides a blanket impl of the reverse direction - i.e. `impl Into<&'static str> for YourEnum`. /// /// ``` /// use strum_macros::IntoStaticStr; /// /// #[derive(IntoStaticStr)] /// enum State<'a> { /// Initial(&'a str), /// Finished, /// } /// /// fn verify_state<'a>(s: &'a str) { /// let mut state = State::Initial(s); /// // The following won't work because the lifetime is incorrect: /// // let wrong: &'static str = state.as_ref(); /// // using the trait implemented by the derive works however: /// let right: &'static str = state.into(); /// assert_eq!("Initial", right); /// state = State::Finished; /// let done: &'static str = state.into(); /// assert_eq!("Finished", done); /// } /// /// verify_state(&"hello world".to_string()); /// ``` #[proc_macro_derive(IntoStaticStr, attributes(strum))] pub fn into_static_str(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse_macro_input!(input as DeriveInput); let toks = macros::as_ref_str::as_static_str_inner( &ast, ¯os::as_ref_str::GenerateTraitVariant::From, ) .unwrap_or_else(|err| err.to_compile_error()); debug_print_generated(&ast, &toks); toks.into() } /// implements `std::string::ToString` on en enum /// /// ``` /// // You need to bring the ToString trait into scope to use it /// use std::string::ToString; /// use strum_macros; /// /// #[derive(strum_macros::ToString, Debug)] /// enum Color { /// #[strum(serialize = "redred")] /// Red, /// Green { /// range: usize, /// }, /// Blue(usize), /// Yellow, /// } /// /// // uses the serialize string for Display /// let red = Color::Red; /// assert_eq!(String::from("redred"), red.to_string()); /// // by default the variants Name /// let yellow = Color::Yellow; /// assert_eq!(String::from("Yellow"), yellow.to_string()); /// ``` #[deprecated( since = "0.22.0", note = "please use `#[derive(Display)]` instead. See issue https://github.com/Peternator7/strum/issues/132" )] #[proc_macro_derive(ToString, attributes(strum))] pub fn to_string(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse_macro_input!(input as DeriveInput); let toks = macros::to_string::to_string_inner(&ast).unwrap_or_else(|err| err.to_compile_error()); debug_print_generated(&ast, &toks); toks.into() } /// Converts enum variants to strings. /// /// Deriving `Display` on an enum prints out the given enum. This enables you to perform round /// trip style conversions from enum into string and back again for unit style variants. `Display` /// choose which serialization to used based on the following criteria: /// /// 1. If there is a `to_string` property, this value will be used. There can only be one per variant. /// 1. Of the various `serialize` properties, the value with the longest length is chosen. If that /// behavior isn't desired, you should use `to_string`. /// 1. The name of the variant will be used if there are no `serialize` or `to_string` attributes. /// /// ``` /// // You need to bring the ToString trait into scope to use it /// use std::string::ToString; /// use strum_macros::Display; /// /// #[derive(Display, Debug)] /// enum Color { /// #[strum(serialize = "redred")] /// Red, /// Green { /// range: usize, /// }, /// Blue(usize), /// Yellow, /// } /// /// // uses the serialize string for Display /// let red = Color::Red; /// assert_eq!(String::from("redred"), format!("{}", red)); /// // by default the variants Name /// let yellow = Color::Yellow; /// assert_eq!(String::from("Yellow"), yellow.to_string()); /// // or for string formatting /// println!( /// "blue: {} green: {}", /// Color::Blue(10), /// Color::Green { range: 42 } /// ); /// ``` #[proc_macro_derive(Display, attributes(strum))] pub fn display(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse_macro_input!(input as DeriveInput); let toks = macros::display::display_inner(&ast).unwrap_or_else(|err| err.to_compile_error()); debug_print_generated(&ast, &toks); toks.into() } /// Creates a new type that iterates of the variants of an enum. /// /// Iterate over the variants of an Enum. Any additional data on your variants will be set to `Default::default()`. /// The macro implements `strum::IntoEnumIter` on your enum and creates a new type called `YourEnumIter` that is the iterator object. /// You cannot derive `EnumIter` on any type with a lifetime bound (`<'a>`) because the iterator would surely /// create [unbounded lifetimes](https://doc.rust-lang.org/nightly/nomicon/unbounded-lifetimes.html). /// /// ``` /// /// // You need to bring the trait into scope to use it! /// use strum::IntoEnumIterator; /// use strum_macros::EnumIter; /// /// #[derive(EnumIter, Debug, PartialEq)] /// enum Color { /// Red, /// Green { range: usize }, /// Blue(usize), /// Yellow, /// } /// /// // It's simple to iterate over the variants of an enum. /// for color in Color::iter() { /// println!("My favorite color is {:?}", color); /// } /// /// let mut ci = Color::iter(); /// assert_eq!(Some(Color::Red), ci.next()); /// assert_eq!(Some(Color::Green {range: 0}), ci.next()); /// assert_eq!(Some(Color::Blue(0)), ci.next()); /// assert_eq!(Some(Color::Yellow), ci.next()); /// assert_eq!(None, ci.next()); /// ``` #[proc_macro_derive(EnumIter, attributes(strum))] pub fn enum_iter(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse_macro_input!(input as DeriveInput); let toks = macros::enum_iter::enum_iter_inner(&ast).unwrap_or_else(|err| err.to_compile_error()); debug_print_generated(&ast, &toks); toks.into() } /// Add a function to enum that allows accessing variants by its discriminant /// /// This macro adds a standalone function to obtain an enum variant by its discriminant. The macro adds /// `from_repr(discriminant: usize) -> Option` as a standalone function on the enum. For /// variants with additional data, the returned variant will use the `Default` trait to fill the /// data. The discriminant follows the same rules as `rustc`. The first discriminant is zero and each /// successive variant has a discriminant of one greater than the previous variant, expect where an /// explicit discriminant is specified. The type of the discriminant will match the `repr` type if /// it is specifed. /// /// When the macro is applied using rustc >= 1.46 and when there is no additional data on any of /// the variants, the `from_repr` function is marked `const`. rustc >= 1.46 is required /// to allow `match` statements in `const fn`. The no additional data requirement is due to the /// inability to use `Default::default()` in a `const fn`. /// /// You cannot derive `FromRepr` on any type with a lifetime bound (`<'a>`) because the function would surely /// create [unbounded lifetimes](https://doc.rust-lang.org/nightly/nomicon/unbounded-lifetimes.html). /// /// ``` /// /// use strum_macros::FromRepr; /// /// #[derive(FromRepr, Debug, PartialEq)] /// enum Color { /// Red, /// Green { range: usize }, /// Blue(usize), /// Yellow, /// } /// /// assert_eq!(Some(Color::Red), Color::from_repr(0)); /// assert_eq!(Some(Color::Green {range: 0}), Color::from_repr(1)); /// assert_eq!(Some(Color::Blue(0)), Color::from_repr(2)); /// assert_eq!(Some(Color::Yellow), Color::from_repr(3)); /// assert_eq!(None, Color::from_repr(4)); /// /// // Custom discriminant tests /// #[derive(FromRepr, Debug, PartialEq)] /// #[repr(u8)] /// enum Vehicle { /// Car = 1, /// Truck = 3, /// } /// /// assert_eq!(None, Vehicle::from_repr(0)); /// ``` /// /// On versions of rust >= 1.46, the `from_repr` function is marked `const`. /// /// ```rust /// use strum_macros::FromRepr; /// /// #[derive(FromRepr, Debug, PartialEq)] /// #[repr(u8)] /// enum Number { /// One = 1, /// Three = 3, /// } /// /// # #[rustversion::since(1.46)] /// const fn number_from_repr(d: u8) -> Option { /// Number::from_repr(d) /// } /// /// # #[rustversion::before(1.46)] /// # fn number_from_repr(d: u8) -> Option { /// # 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)); /// assert_eq!(Some(Number::Three), number_from_repr(3)); /// assert_eq!(None, number_from_repr(4)); /// ``` #[proc_macro_derive(FromRepr, attributes(strum))] pub fn from_repr(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse_macro_input!(input as DeriveInput); let toks = macros::from_repr::from_repr_inner(&ast).unwrap_or_else(|err| err.to_compile_error()); debug_print_generated(&ast, &toks); toks.into() } /// Add a verbose message to an enum variant. /// /// Encode strings into the enum itself. The `strum_macros::EmumMessage` macro implements the `strum::EnumMessage` trait. /// `EnumMessage` looks for `#[strum(message="...")]` attributes on your variants. /// You can also provided a `detailed_message="..."` attribute to create a seperate more detailed message than the first. /// /// `EnumMessage` also exposes the variants doc comments through `get_documentation()`. This is useful in some scenarios, /// but `get_message` should generally be preferred. Rust doc comments are intended for developer facing documentation, /// not end user messaging. /// /// ``` /// // You need to bring the trait into scope to use it /// use strum::EnumMessage; /// use strum_macros; /// /// #[derive(strum_macros::EnumMessage, Debug)] /// #[allow(dead_code)] /// enum Color { /// /// Danger color. /// #[strum(message = "Red", detailed_message = "This is very red")] /// Red, /// #[strum(message = "Simply Green")] /// Green { range: usize }, /// #[strum(serialize = "b", serialize = "blue")] /// Blue(usize), /// } /// /// // Generated code looks like more or less like this: /// /* /// impl ::strum::EnumMessage for Color { /// fn get_message(&self) -> ::core::option::Option<&'static str> { /// match self { /// &Color::Red => ::core::option::Option::Some("Red"), /// &Color::Green {..} => ::core::option::Option::Some("Simply Green"), /// _ => None /// } /// } /// /// fn get_detailed_message(&self) -> ::core::option::Option<&'static str> { /// match self { /// &Color::Red => ::core::option::Option::Some("This is very red"), /// &Color::Green {..}=> ::core::option::Option::Some("Simply Green"), /// _ => None /// } /// } /// /// fn get_documentation(&self) -> ::std::option::Option<&'static str> { /// match self { /// &Color::Red => ::std::option::Option::Some("Danger color."), /// _ => None /// } /// } /// /// fn get_serializations(&self) -> &'static [&'static str] { /// match self { /// &Color::Red => { /// static ARR: [&'static str; 1] = ["Red"]; /// &ARR /// }, /// &Color::Green {..}=> { /// static ARR: [&'static str; 1] = ["Green"]; /// &ARR /// }, /// &Color::Blue (..) => { /// static ARR: [&'static str; 2] = ["b", "blue"]; /// &ARR /// }, /// } /// } /// } /// */ /// /// let c = Color::Red; /// assert_eq!("Red", c.get_message().unwrap()); /// assert_eq!("This is very red", c.get_detailed_message().unwrap()); /// assert_eq!("Danger color.", c.get_documentation().unwrap()); /// assert_eq!(["Red"], c.get_serializations()); /// ``` #[proc_macro_derive(EnumMessage, attributes(strum))] pub fn enum_messages(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse_macro_input!(input as DeriveInput); let toks = macros::enum_messages::enum_message_inner(&ast) .unwrap_or_else(|err| err.to_compile_error()); debug_print_generated(&ast, &toks); toks.into() } /// Add custom properties to enum variants. /// /// Enables the encoding of arbitary constants into enum variants. This method /// currently only supports adding additional string values. Other types of literals are still /// experimental in the rustc compiler. The generated code works by nesting match statements. /// The first match statement matches on the type of the enum, and the inner match statement /// matches on the name of the property requested. This design works well for enums with a small /// number of variants and properties, but scales linearly with the number of variants so may not /// be the best choice in all situations. /// /// ``` /// /// use strum_macros; /// // bring the trait into scope /// use strum::EnumProperty; /// /// #[derive(strum_macros::EnumProperty, Debug)] /// #[allow(dead_code)] /// enum Color { /// #[strum(props(Red = "255", Blue = "255", Green = "255"))] /// White, /// #[strum(props(Red = "0", Blue = "0", Green = "0"))] /// Black, /// #[strum(props(Red = "0", Blue = "255", Green = "0"))] /// Blue, /// #[strum(props(Red = "255", Blue = "0", Green = "0"))] /// Red, /// #[strum(props(Red = "0", Blue = "0", Green = "255"))] /// Green, /// } /// /// let my_color = Color::Red; /// let display = format!( /// "My color is {:?}. It's RGB is {},{},{}", /// my_color, /// my_color.get_str("Red").unwrap(), /// my_color.get_str("Green").unwrap(), /// my_color.get_str("Blue").unwrap() /// ); /// assert_eq!("My color is Red. It\'s RGB is 255,0,0", &display); /// ``` #[proc_macro_derive(EnumProperty, attributes(strum))] pub fn enum_properties(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse_macro_input!(input as DeriveInput); let toks = macros::enum_properties::enum_properties_inner(&ast) .unwrap_or_else(|err| err.to_compile_error()); debug_print_generated(&ast, &toks); toks.into() } /// Generate a new type with only the discriminant names. /// /// Given an enum named `MyEnum`, generates another enum called `MyEnumDiscriminants` with the same /// variants but without any data fields. This is useful when you wish to determine the variant of /// an `enum` but one or more of the variants contains a non-`Default` field. `From` /// implementations are generated so that you can easily convert from `MyEnum` to /// `MyEnumDiscriminants`. /// /// By default, the generated enum has the following derives: `Clone, Copy, Debug, PartialEq, Eq`. /// You can add additional derives using the `#[strum_discriminants(derive(AdditionalDerive))]` /// attribute. /// /// Note, the variant attributes passed to the discriminant enum are filtered to avoid compilation /// errors due to the derives mismatches, thus only `#[doc]`, `#[cfg]`, `#[allow]`, and `#[deny]` /// are passed through by default. If you want to specify a custom attribute on the discriminant /// variant, wrap it with `#[strum_discriminants(...)]` attribute. /// /// ``` /// // Bring trait into scope /// use std::str::FromStr; /// use strum::{IntoEnumIterator, EnumMessage}; /// use strum_macros::{EnumDiscriminants, EnumIter, EnumString, EnumMessage}; /// /// #[derive(Debug)] /// struct NonDefault; /// /// // simple example /// # #[allow(dead_code)] /// #[derive(Debug, EnumDiscriminants)] /// #[strum_discriminants(derive(EnumString, EnumMessage))] /// enum MyEnum { /// #[strum_discriminants(strum(message = "Variant zero"))] /// Variant0(NonDefault), /// Variant1 { a: NonDefault }, /// } /// /// // You can rename the generated enum using the `#[strum_discriminants(name(OtherName))]` attribute: /// # #[allow(dead_code)] /// #[derive(Debug, EnumDiscriminants)] /// #[strum_discriminants(derive(EnumIter))] /// #[strum_discriminants(name(MyVariants))] /// enum MyEnumR { /// Variant0(bool), /// Variant1 { a: bool }, /// } /// /// // test simple example /// assert_eq!( /// MyEnumDiscriminants::Variant0, /// MyEnumDiscriminants::from_str("Variant0").unwrap() /// ); /// // test rename example combined with EnumIter /// assert_eq!( /// vec![MyVariants::Variant0, MyVariants::Variant1], /// MyVariants::iter().collect::>() /// ); /// /// // Make use of the auto-From conversion to check whether an instance of `MyEnum` matches a /// // `MyEnumDiscriminants` discriminant. /// assert_eq!( /// MyEnumDiscriminants::Variant0, /// MyEnum::Variant0(NonDefault).into() /// ); /// assert_eq!( /// MyEnumDiscriminants::Variant0, /// MyEnumDiscriminants::from(MyEnum::Variant0(NonDefault)) /// ); /// /// // Make use of the EnumMessage on the `MyEnumDiscriminants` discriminant. /// assert_eq!( /// MyEnumDiscriminants::Variant0.get_message(), /// Some("Variant zero") /// ); /// ``` /// /// It is also possible to specify the visibility (e.g. `pub`/`pub(crate)`/etc.) /// of the generated enum. By default, the generated enum inherits the /// visibility of the parent enum it was generated from. /// /// ```nocompile /// use strum_macros::EnumDiscriminants; /// /// // You can set the visibility of the generated enum using the `#[strum_discriminants(vis(..))]` attribute: /// mod inner { /// use strum_macros::EnumDiscriminants; /// /// # #[allow(dead_code)] /// #[derive(Debug, EnumDiscriminants)] /// #[strum_discriminants(vis(pub))] /// #[strum_discriminants(name(PubDiscriminants))] /// enum PrivateEnum { /// Variant0(bool), /// Variant1 { a: bool }, /// } /// } /// /// // test visibility example, `PrivateEnum` should not be accessible here /// assert_ne!( /// inner::PubDiscriminants::Variant0, /// inner::PubDiscriminants::Variant1, /// ); /// ``` #[proc_macro_derive(EnumDiscriminants, attributes(strum, strum_discriminants))] pub fn enum_discriminants(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse_macro_input!(input as DeriveInput); let toks = macros::enum_discriminants::enum_discriminants_inner(&ast) .unwrap_or_else(|err| err.to_compile_error()); debug_print_generated(&ast, &toks); toks.into() } /// Add a constant `usize` equal to the number of variants. /// /// For a given enum generates implementation of `strum::EnumCount`, /// which adds a static property `COUNT` of type usize that holds the number of variants. /// /// ``` /// use strum::{EnumCount, IntoEnumIterator}; /// use strum_macros::{EnumCount as EnumCountMacro, EnumIter}; /// /// #[derive(Debug, EnumCountMacro, EnumIter)] /// enum Week { /// Sunday, /// Monday, /// Tuesday, /// Wednesday, /// Thursday, /// Friday, /// Saturday, /// } /// /// assert_eq!(7, Week::COUNT); /// assert_eq!(Week::iter().count(), Week::COUNT); /// /// ``` #[proc_macro_derive(EnumCount, attributes(strum))] pub fn enum_count(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse_macro_input!(input as DeriveInput); let toks = macros::enum_count::enum_count_inner(&ast).unwrap_or_else(|err| err.to_compile_error()); debug_print_generated(&ast, &toks); toks.into() }