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