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