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