strum_macros/
lib.rs

1//! # Strum
2//!
3//! Strum is a set of macros and traits for working with
4//! enums and strings easier in Rust.
5//!
6
7#![recursion_limit = "128"]
8
9extern crate proc_macro;
10
11mod helpers;
12mod macros;
13
14use proc_macro2::TokenStream;
15use std::env;
16use syn::DeriveInput;
17
18fn debug_print_generated(ast: &DeriveInput, toks: &TokenStream) {
19    let debug = env::var("STRUM_DEBUG");
20    if let Ok(s) = debug {
21        if s == "1" {
22            println!("{}", toks);
23        }
24
25        if ast.ident == s {
26            println!("{}", toks);
27        }
28    }
29}
30
31/// Converts strings to enum variants based on their name.
32///
33/// auto-derives `std::str::FromStr` on the enum (for Rust 1.34 and above, std::convert::TryFrom<&str>
34/// will be derived as well). Each variant of the enum will match on it's own name.
35/// This can be overridden using `serialize="DifferentName"` or `to_string="DifferentName"`
36/// on the attribute as shown below.
37/// Multiple deserializations can be added to the same variant. If the variant contains additional data,
38/// they will be set to their default values upon deserialization.
39///
40/// The `default` attribute can be applied to a tuple variant with a single data parameter. When a match isn't
41/// found, the given variant will be returned and the input string will be captured in the parameter.
42///
43/// Note that the implementation of `FromStr` by default only matches on the name of the
44/// variant. There is an option to match on different case conversions through the
45/// `#[strum(serialize_all = "snake_case")]` type attribute.
46///
47/// See the [Additional Attributes](https://docs.rs/strum/0.22/strum/additional_attributes/index.html)
48/// Section for more information on using this feature.
49///
50/// # Example howto use EnumString
51/// ```
52/// use std::str::FromStr;
53/// use strum_macros::EnumString;
54///
55/// #[derive(Debug, PartialEq, EnumString)]
56/// enum Color {
57///     Red,
58///     // The Default value will be inserted into range if we match "Green".
59///     Green {
60///         range: usize,
61///     },
62///
63///     // We can match on multiple different patterns.
64///     #[strum(serialize = "blue", serialize = "b")]
65///     Blue(usize),
66///
67///     // Notice that we can disable certain variants from being found
68///     #[strum(disabled)]
69///     Yellow,
70///
71///     // We can make the comparison case insensitive (however Unicode is not supported at the moment)
72///     #[strum(ascii_case_insensitive)]
73///     Black,
74/// }
75///
76/// /*
77/// //The generated code will look like:
78/// impl std::str::FromStr for Color {
79///     type Err = ::strum::ParseError;
80///
81///     fn from_str(s: &str) -> ::std::result::Result<Color, Self::Err> {
82///         match s {
83///             "Red" => ::std::result::Result::Ok(Color::Red),
84///             "Green" => ::std::result::Result::Ok(Color::Green { range:Default::default() }),
85///             "blue" => ::std::result::Result::Ok(Color::Blue(Default::default())),
86///             "b" => ::std::result::Result::Ok(Color::Blue(Default::default())),
87///             s if s.eq_ignore_ascii_case("Black") => ::std::result::Result::Ok(Color::Black),
88///             _ => ::std::result::Result::Err(::strum::ParseError::VariantNotFound),
89///         }
90///     }
91/// }
92/// */
93///
94/// // simple from string
95/// let color_variant = Color::from_str("Red").unwrap();
96/// assert_eq!(Color::Red, color_variant);
97/// // short version works too
98/// let color_variant = Color::from_str("b").unwrap();
99/// assert_eq!(Color::Blue(0), color_variant);
100/// // was disabled for parsing = returns parse-error
101/// let color_variant = Color::from_str("Yellow");
102/// assert!(color_variant.is_err());
103/// // however the variant is still normally usable
104/// println!("{:?}", Color::Yellow);
105/// let color_variant = Color::from_str("bLACk").unwrap();
106/// assert_eq!(Color::Black, color_variant);
107/// ```
108#[proc_macro_derive(EnumString, attributes(strum))]
109pub fn from_string(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
110    let ast = syn::parse_macro_input!(input as DeriveInput);
111
112    let toks =
113        macros::from_string::from_string_inner(&ast).unwrap_or_else(|err| err.to_compile_error());
114    debug_print_generated(&ast, &toks);
115    toks.into()
116}
117
118/// Converts enum variants to `&'static str`.
119///
120/// Implements `AsRef<str>` on your enum using the same rules as
121/// `Display` for determining what string is returned. The difference is that `as_ref()` returns
122/// a `&str` instead of a `String` so you don't allocate any additional memory with each call.
123///
124/// ```
125/// // You need to bring the AsRef trait into scope to use it
126/// use std::convert::AsRef;
127/// use strum_macros::AsRefStr;
128///
129/// #[derive(AsRefStr, Debug)]
130/// enum Color {
131///     #[strum(serialize = "redred")]
132///     Red,
133///     Green {
134///         range: usize,
135///     },
136///     Blue(usize),
137///     Yellow,
138/// }
139///
140/// // uses the serialize string for Display
141/// let red = Color::Red;
142/// assert_eq!("redred", red.as_ref());
143/// // by default the variants Name
144/// let yellow = Color::Yellow;
145/// assert_eq!("Yellow", yellow.as_ref());
146/// // or for string formatting
147/// println!(
148///     "blue: {} green: {}",
149///     Color::Blue(10).as_ref(),
150///     Color::Green { range: 42 }.as_ref()
151/// );
152/// ```
153#[proc_macro_derive(AsRefStr, attributes(strum))]
154pub fn as_ref_str(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
155    let ast = syn::parse_macro_input!(input as DeriveInput);
156
157    let toks =
158        macros::as_ref_str::as_ref_str_inner(&ast).unwrap_or_else(|err| err.to_compile_error());
159    debug_print_generated(&ast, &toks);
160    toks.into()
161}
162
163/// Implements Strum::VariantNames which adds an associated constant `VARIANTS` which is an array of discriminant names.
164///
165/// Adds an `impl` block for the `enum` that adds a static `VARIANTS` array of `&'static str` that are the discriminant names.
166/// This will respect the `serialize_all` attribute on the `enum` (like `#[strum(serialize_all = "snake_case")]`.
167///
168/// ```
169/// // import the macros needed
170/// use strum_macros::{EnumString, EnumVariantNames};
171/// // You need to import the trait, to have access to VARIANTS
172/// use strum::VariantNames;
173///
174/// #[derive(Debug, EnumString, EnumVariantNames)]
175/// #[strum(serialize_all = "kebab_case")]
176/// enum Color {
177///     Red,
178///     Blue,
179///     Yellow,
180///     RebeccaPurple,
181/// }
182/// assert_eq!(["red", "blue", "yellow", "rebecca-purple"], Color::VARIANTS);
183/// ```
184#[proc_macro_derive(EnumVariantNames, attributes(strum))]
185pub fn variant_names(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
186    let ast = syn::parse_macro_input!(input as DeriveInput);
187
188    let toks = macros::enum_variant_names::enum_variant_names_inner(&ast)
189        .unwrap_or_else(|err| err.to_compile_error());
190    debug_print_generated(&ast, &toks);
191    toks.into()
192}
193
194#[proc_macro_derive(AsStaticStr, attributes(strum))]
195#[deprecated(
196    since = "0.22.0",
197    note = "please use `#[derive(IntoStaticStr)]` instead"
198)]
199pub fn as_static_str(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
200    let ast = syn::parse_macro_input!(input as DeriveInput);
201
202    let toks = macros::as_ref_str::as_static_str_inner(
203        &ast,
204        macros::as_ref_str::GenerateTraitVariant::AsStaticStr,
205    )
206    .unwrap_or_else(|err| err.to_compile_error());
207    debug_print_generated(&ast, &toks);
208    toks.into()
209}
210
211/// Implements `From<MyEnum> for &'static str` on an enum.
212///
213/// Implements `From<YourEnum>` and `From<&'a YourEnum>` for `&'static str`. This is
214/// useful for turning an enum variant into a static string.
215/// The Rust `std` provides a blanket impl of the reverse direction - i.e. `impl Into<&'static str> for YourEnum`.
216///
217/// ```
218/// use strum_macros::IntoStaticStr;
219///
220/// #[derive(IntoStaticStr)]
221/// enum State<'a> {
222///     Initial(&'a str),
223///     Finished,
224/// }
225///
226/// fn verify_state<'a>(s: &'a str) {
227///     let mut state = State::Initial(s);
228///     // The following won't work because the lifetime is incorrect:
229///     // let wrong: &'static str = state.as_ref();
230///     // using the trait implemented by the derive works however:
231///     let right: &'static str = state.into();
232///     assert_eq!("Initial", right);
233///     state = State::Finished;
234///     let done: &'static str = state.into();
235///     assert_eq!("Finished", done);
236/// }
237///
238/// verify_state(&"hello world".to_string());
239/// ```
240#[proc_macro_derive(IntoStaticStr, attributes(strum))]
241pub fn into_static_str(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
242    let ast = syn::parse_macro_input!(input as DeriveInput);
243
244    let toks = macros::as_ref_str::as_static_str_inner(
245        &ast,
246        macros::as_ref_str::GenerateTraitVariant::From,
247    )
248    .unwrap_or_else(|err| err.to_compile_error());
249    debug_print_generated(&ast, &toks);
250    toks.into()
251}
252
253/// implements `std::string::ToString` on en enum
254///
255/// ```
256/// // You need to bring the ToString trait into scope to use it
257/// use std::string::ToString;
258/// use strum_macros;
259///
260/// #[derive(strum_macros::ToString, Debug)]
261/// enum Color {
262///     #[strum(serialize = "redred")]
263///     Red,
264///     Green {
265///         range: usize,
266///     },
267///     Blue(usize),
268///     Yellow,
269/// }
270///
271/// // uses the serialize string for Display
272/// let red = Color::Red;
273/// assert_eq!(String::from("redred"), red.to_string());
274/// // by default the variants Name
275/// let yellow = Color::Yellow;
276/// assert_eq!(String::from("Yellow"), yellow.to_string());
277/// ```
278#[deprecated(
279    since = "0.22.0",
280    note = "please use `#[derive(Display)]` instead. See issue https://github.com/Peternator7/strum/issues/132"
281)]
282#[proc_macro_derive(ToString, attributes(strum))]
283pub fn to_string(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
284    let ast = syn::parse_macro_input!(input as DeriveInput);
285
286    let toks =
287        macros::to_string::to_string_inner(&ast).unwrap_or_else(|err| err.to_compile_error());
288    debug_print_generated(&ast, &toks);
289    toks.into()
290}
291
292/// Converts enum variants to strings.
293///
294/// Deriving `Display` on an enum prints out the given enum. This enables you to perform round
295/// trip style conversions from enum into string and back again for unit style variants. `Display`
296/// choose which serialization to used based on the following criteria:
297///
298/// 1. If there is a `to_string` property, this value will be used. There can only be one per variant.
299/// 1. Of the various `serialize` properties, the value with the longest length is chosen. If that
300///    behavior isn't desired, you should use `to_string`.
301/// 1. The name of the variant will be used if there are no `serialize` or `to_string` attributes.
302///
303/// ```
304/// // You need to bring the ToString trait into scope to use it
305/// use std::string::ToString;
306/// use strum_macros::Display;
307///
308/// #[derive(Display, Debug)]
309/// enum Color {
310///     #[strum(serialize = "redred")]
311///     Red,
312///     Green {
313///         range: usize,
314///     },
315///     Blue(usize),
316///     Yellow,
317/// }
318///
319/// // uses the serialize string for Display
320/// let red = Color::Red;
321/// assert_eq!(String::from("redred"), format!("{}", red));
322/// // by default the variants Name
323/// let yellow = Color::Yellow;
324/// assert_eq!(String::from("Yellow"), yellow.to_string());
325/// // or for string formatting
326/// println!(
327///     "blue: {} green: {}",
328///     Color::Blue(10),
329///     Color::Green { range: 42 }
330/// );
331/// ```
332#[proc_macro_derive(Display, attributes(strum))]
333pub fn display(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
334    let ast = syn::parse_macro_input!(input as DeriveInput);
335
336    let toks = macros::display::display_inner(&ast).unwrap_or_else(|err| err.to_compile_error());
337    debug_print_generated(&ast, &toks);
338    toks.into()
339}
340
341/// Creates a new type that iterates of the variants of an enum.
342///
343/// Iterate over the variants of an Enum. Any additional data on your variants will be set to `Default::default()`.
344/// The macro implements `strum::IntoEnumIter` on your enum and creates a new type called `YourEnumIter` that is the iterator object.
345/// You cannot derive `EnumIter` on any type with a lifetime bound (`<'a>`) because the iterator would surely
346/// create [unbounded lifetimes](https://doc.rust-lang.org/nightly/nomicon/unbounded-lifetimes.html).
347///
348/// ```
349///
350/// // You need to bring the trait into scope to use it!
351/// use strum::IntoEnumIterator;
352/// use strum_macros::EnumIter;
353///
354/// #[derive(EnumIter, Debug, PartialEq)]
355/// enum Color {
356///     Red,
357///     Green { range: usize },
358///     Blue(usize),
359///     Yellow,
360/// }
361///
362/// // It's simple to iterate over the variants of an enum.
363/// for color in Color::iter() {
364///     println!("My favorite color is {:?}", color);
365/// }
366///
367/// let mut ci = Color::iter();
368/// assert_eq!(Some(Color::Red), ci.next());
369/// assert_eq!(Some(Color::Green {range: 0}), ci.next());
370/// assert_eq!(Some(Color::Blue(0)), ci.next());
371/// assert_eq!(Some(Color::Yellow), ci.next());
372/// assert_eq!(None, ci.next());
373/// ```
374#[proc_macro_derive(EnumIter, attributes(strum))]
375pub fn enum_iter(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
376    let ast = syn::parse_macro_input!(input as DeriveInput);
377
378    let toks =
379        macros::enum_iter::enum_iter_inner(&ast).unwrap_or_else(|err| err.to_compile_error());
380    debug_print_generated(&ast, &toks);
381    toks.into()
382}
383
384/// Add a function to enum that allows accessing variants by its discriminant
385///
386/// This macro adds a standalone function to obtain an enum variant by its discriminant. The macro adds
387/// `from_repr(discriminant: usize) -> Option<YourEnum>` as a standalone function on the enum. For
388/// variants with additional data, the returned variant will use the `Default` trait to fill the
389/// data. The discriminant follows the same rules as `rustc`. The first discriminant is zero and each
390/// successive variant has a discriminant of one greater than the previous variant, expect where an
391/// explicit discriminant is specified. The type of the discriminant will match the `repr` type if
392/// it is specifed.
393///
394/// When the macro is applied using rustc >= 1.46 and when there is no additional data on any of
395/// the variants, the `from_repr` function is marked `const`. rustc >= 1.46 is required
396/// to allow `match` statements in `const fn`. The no additional data requirement is due to the
397/// inability to use `Default::default()` in a `const fn`.
398///
399/// You cannot derive `FromRepr` on any type with a lifetime bound (`<'a>`) because the function would surely
400/// create [unbounded lifetimes](https://doc.rust-lang.org/nightly/nomicon/unbounded-lifetimes.html).
401///
402/// ```
403///
404/// use strum_macros::FromRepr;
405///
406/// #[derive(FromRepr, Debug, PartialEq)]
407/// enum Color {
408///     Red,
409///     Green { range: usize },
410///     Blue(usize),
411///     Yellow,
412/// }
413///
414/// assert_eq!(Some(Color::Red), Color::from_repr(0));
415/// assert_eq!(Some(Color::Green {range: 0}), Color::from_repr(1));
416/// assert_eq!(Some(Color::Blue(0)), Color::from_repr(2));
417/// assert_eq!(Some(Color::Yellow), Color::from_repr(3));
418/// assert_eq!(None, Color::from_repr(4));
419///
420/// // Custom discriminant tests
421/// #[derive(FromRepr, Debug, PartialEq)]
422/// #[repr(u8)]
423/// enum Vehicle {
424///     Car = 1,
425///     Truck = 3,
426/// }
427///
428/// assert_eq!(None, Vehicle::from_repr(0));
429/// ```
430///
431/// On versions of rust >= 1.46, the `from_repr` function is marked `const`.
432///
433/// ```rust
434/// use strum_macros::FromRepr;
435///
436/// #[derive(FromRepr, Debug, PartialEq)]
437/// #[repr(u8)]
438/// enum Number {
439///     One = 1,
440///     Three = 3,
441/// }
442///
443/// # #[rustversion::since(1.46)]
444/// const fn number_from_repr(d: u8) -> Option<Number> {
445///     Number::from_repr(d)
446/// }
447///
448/// # #[rustversion::before(1.46)]
449/// # fn number_from_repr(d: u8) -> Option<Number> {
450/// #     Number::from_repr(d)
451/// # }
452/// assert_eq!(None, number_from_repr(0));
453/// assert_eq!(Some(Number::One), number_from_repr(1));
454/// assert_eq!(None, number_from_repr(2));
455/// assert_eq!(Some(Number::Three), number_from_repr(3));
456/// assert_eq!(None, number_from_repr(4));
457/// ```
458
459#[proc_macro_derive(FromRepr, attributes(strum))]
460pub fn from_repr(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
461    let ast = syn::parse_macro_input!(input as DeriveInput);
462
463    let toks =
464        macros::from_repr::from_repr_inner(&ast).unwrap_or_else(|err| err.to_compile_error());
465    debug_print_generated(&ast, &toks);
466    toks.into()
467}
468
469/// Add a verbose message to an enum variant.
470///
471/// Encode strings into the enum itself. The `strum_macros::EmumMessage` macro implements the `strum::EnumMessage` trait.
472/// `EnumMessage` looks for `#[strum(message="...")]` attributes on your variants.
473/// You can also provided a `detailed_message="..."` attribute to create a seperate more detailed message than the first.
474/// ```
475/// // You need to bring the trait into scope to use it
476/// use strum::EnumMessage;
477/// use strum_macros;
478///
479/// #[derive(strum_macros::EnumMessage, Debug)]
480/// #[allow(dead_code)]
481/// enum Color {
482///     #[strum(message = "Red", detailed_message = "This is very red")]
483///     Red,
484///     #[strum(message = "Simply Green")]
485///     Green { range: usize },
486///     #[strum(serialize = "b", serialize = "blue")]
487///     Blue(usize),
488/// }
489///
490/// // Generated code looks like more or less like this:
491/// /*
492/// impl ::strum::EnumMessage for Color {
493///     fn get_message(&self) -> ::std::option::Option<&'static str> {
494///         match self {
495///             &Color::Red => ::std::option::Option::Some("Red"),
496///             &Color::Green {..} => ::std::option::Option::Some("Simply Green"),
497///             _ => None
498///         }
499///     }
500///
501///     fn get_detailed_message(&self) -> ::std::option::Option<&'static str> {
502///         match self {
503///             &Color::Red => ::std::option::Option::Some("This is very red"),
504///             &Color::Green {..}=> ::std::option::Option::Some("Simply Green"),
505///             _ => None
506///         }
507///     }
508///
509///     fn get_serializations(&self) -> &'static [&'static str] {
510///         match self {
511///             &Color::Red => {
512///                 static ARR: [&'static str; 1] = ["Red"];
513///                 &ARR
514///             },
515///             &Color::Green {..}=> {
516///                 static ARR: [&'static str; 1] = ["Green"];
517///                 &ARR
518///             },
519///             &Color::Blue (..) => {
520///                 static ARR: [&'static str; 2] = ["b", "blue"];
521///                 &ARR
522///             },
523///         }
524///     }
525/// }
526/// */
527///
528/// let c = Color::Red;
529/// assert_eq!("Red", c.get_message().unwrap());
530/// assert_eq!("This is very red", c.get_detailed_message().unwrap());
531/// assert_eq!(["Red"], c.get_serializations());
532/// ```
533#[proc_macro_derive(EnumMessage, attributes(strum))]
534pub fn enum_messages(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
535    let ast = syn::parse_macro_input!(input as DeriveInput);
536
537    let toks = macros::enum_messages::enum_message_inner(&ast)
538        .unwrap_or_else(|err| err.to_compile_error());
539    debug_print_generated(&ast, &toks);
540    toks.into()
541}
542
543/// Add custom properties to enum variants.
544///
545/// Enables the encoding of arbitary constants into enum variants. This method
546/// currently only supports adding additional string values. Other types of literals are still
547/// experimental in the rustc compiler. The generated code works by nesting match statements.
548/// The first match statement matches on the type of the enum, and the inner match statement
549/// matches on the name of the property requested. This design works well for enums with a small
550/// number of variants and properties, but scales linearly with the number of variants so may not
551/// be the best choice in all situations.
552///
553/// ```
554///
555/// use strum_macros;
556/// // bring the trait into scope
557/// use strum::EnumProperty;
558///
559/// #[derive(strum_macros::EnumProperty, Debug)]
560/// #[allow(dead_code)]
561/// enum Color {
562///     #[strum(props(Red = "255", Blue = "255", Green = "255"))]
563///     White,
564///     #[strum(props(Red = "0", Blue = "0", Green = "0"))]
565///     Black,
566///     #[strum(props(Red = "0", Blue = "255", Green = "0"))]
567///     Blue,
568///     #[strum(props(Red = "255", Blue = "0", Green = "0"))]
569///     Red,
570///     #[strum(props(Red = "0", Blue = "0", Green = "255"))]
571///     Green,
572/// }
573///
574/// let my_color = Color::Red;
575/// let display = format!(
576///     "My color is {:?}. It's RGB is {},{},{}",
577///     my_color,
578///     my_color.get_str("Red").unwrap(),
579///     my_color.get_str("Green").unwrap(),
580///     my_color.get_str("Blue").unwrap()
581/// );
582/// assert_eq!("My color is Red. It\'s RGB is 255,0,0", &display);
583/// ```
584
585#[proc_macro_derive(EnumProperty, attributes(strum))]
586pub fn enum_properties(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
587    let ast = syn::parse_macro_input!(input as DeriveInput);
588
589    let toks = macros::enum_properties::enum_properties_inner(&ast)
590        .unwrap_or_else(|err| err.to_compile_error());
591    debug_print_generated(&ast, &toks);
592    toks.into()
593}
594
595/// Generate a new type with only the discriminant names.
596///
597/// Given an enum named `MyEnum`, generates another enum called `MyEnumDiscriminants` with the same
598/// variants but without any data fields. This is useful when you wish to determine the variant of
599/// an `enum` but one or more of the variants contains a non-`Default` field. `From`
600/// implementations are generated so that you can easily convert from `MyEnum` to
601/// `MyEnumDiscriminants`.
602///
603/// By default, the generated enum has the following derives: `Clone, Copy, Debug, PartialEq, Eq`.
604/// You can add additional derives using the `#[strum_discriminants(derive(AdditionalDerive))]`
605/// attribute.
606///
607/// Note, the variant attributes passed to the discriminant enum are filtered to avoid compilation
608/// errors due to the derives mismatches, thus only `#[doc]`, `#[cfg]`, `#[allow]`, and `#[deny]`
609/// are passed through by default. If you want to specify a custom attribute on the discriminant
610/// variant, wrap it with `#[strum_discriminants(...)]` attribute.
611///
612/// ```
613/// // Bring trait into scope
614/// use std::str::FromStr;
615/// use strum::{IntoEnumIterator, EnumMessage};
616/// use strum_macros::{EnumDiscriminants, EnumIter, EnumString, EnumMessage};
617///
618/// #[derive(Debug)]
619/// struct NonDefault;
620///
621/// // simple example
622/// # #[allow(dead_code)]
623/// #[derive(Debug, EnumDiscriminants)]
624/// #[strum_discriminants(derive(EnumString, EnumMessage))]
625/// enum MyEnum {
626///     #[strum_discriminants(strum(message = "Variant zero"))]
627///     Variant0(NonDefault),
628///     Variant1 { a: NonDefault },
629/// }
630///
631/// // You can rename the generated enum using the `#[strum_discriminants(name(OtherName))]` attribute:
632/// # #[allow(dead_code)]
633/// #[derive(Debug, EnumDiscriminants)]
634/// #[strum_discriminants(derive(EnumIter))]
635/// #[strum_discriminants(name(MyVariants))]
636/// enum MyEnumR {
637///     Variant0(bool),
638///     Variant1 { a: bool },
639/// }
640///
641/// // test simple example
642/// assert_eq!(
643///     MyEnumDiscriminants::Variant0,
644///     MyEnumDiscriminants::from_str("Variant0").unwrap()
645/// );
646/// // test rename example combined with EnumIter
647/// assert_eq!(
648///     vec![MyVariants::Variant0, MyVariants::Variant1],
649///     MyVariants::iter().collect::<Vec<_>>()
650/// );
651///
652/// // Make use of the auto-From conversion to check whether an instance of `MyEnum` matches a
653/// // `MyEnumDiscriminants` discriminant.
654/// assert_eq!(
655///     MyEnumDiscriminants::Variant0,
656///     MyEnum::Variant0(NonDefault).into()
657/// );
658/// assert_eq!(
659///     MyEnumDiscriminants::Variant0,
660///     MyEnumDiscriminants::from(MyEnum::Variant0(NonDefault))
661/// );
662///
663/// // Make use of the EnumMessage on the `MyEnumDiscriminants` discriminant.
664/// assert_eq!(
665///     MyEnumDiscriminants::Variant0.get_message(),
666///     Some("Variant zero")
667/// );
668/// ```
669///
670/// It is also possible to specify the visibility (e.g. `pub`/`pub(crate)`/etc.)
671/// of the generated enum. By default, the generated enum inherits the
672/// visibility of the parent enum it was generated from.
673///
674/// ```nocompile
675/// use strum_macros::EnumDiscriminants;
676///
677/// // You can set the visibility of the generated enum using the `#[strum_discriminants(vis(..))]` attribute:
678/// mod inner {
679///     use strum_macros::EnumDiscriminants;
680///
681///     # #[allow(dead_code)]
682///     #[derive(Debug, EnumDiscriminants)]
683///     #[strum_discriminants(vis(pub))]
684///     #[strum_discriminants(name(PubDiscriminants))]
685///     enum PrivateEnum {
686///         Variant0(bool),
687///         Variant1 { a: bool },
688///     }
689/// }
690///
691/// // test visibility example, `PrivateEnum` should not be accessible here
692/// assert_ne!(
693///     inner::PubDiscriminants::Variant0,
694///     inner::PubDiscriminants::Variant1,
695/// );
696/// ```
697#[proc_macro_derive(EnumDiscriminants, attributes(strum, strum_discriminants))]
698pub fn enum_discriminants(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
699    let ast = syn::parse_macro_input!(input as DeriveInput);
700
701    let toks = macros::enum_discriminants::enum_discriminants_inner(&ast)
702        .unwrap_or_else(|err| err.to_compile_error());
703    debug_print_generated(&ast, &toks);
704    toks.into()
705}
706
707/// Add a constant `usize` equal to the number of variants.
708///
709/// For a given enum generates implementation of `strum::EnumCount`,
710/// which adds a static property `COUNT` of type usize that holds the number of variants.
711///
712/// ```
713/// use strum::{EnumCount, IntoEnumIterator};
714/// use strum_macros::{EnumCount as EnumCountMacro, EnumIter};
715///
716/// #[derive(Debug, EnumCountMacro, EnumIter)]
717/// enum Week {
718///     Sunday,
719///     Monday,
720///     Tuesday,
721///     Wednesday,
722///     Thursday,
723///     Friday,
724///     Saturday,
725/// }
726///
727/// assert_eq!(7, Week::COUNT);
728/// assert_eq!(Week::iter().count(), Week::COUNT);
729///
730/// ```
731#[proc_macro_derive(EnumCount, attributes(strum))]
732pub fn enum_count(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
733    let ast = syn::parse_macro_input!(input as DeriveInput);
734    let toks =
735        macros::enum_count::enum_count_inner(&ast).unwrap_or_else(|err| err.to_compile_error());
736    debug_print_generated(&ast, &toks);
737    toks.into()
738}