enum_derive/
lib.rs

1/*
2Copyright ⓒ 2015 rust-custom-derive contributors.
3
4Licensed under the MIT license (see LICENSE or <http://opensource.org
5/licenses/MIT>) or the Apache License, Version 2.0 (see LICENSE of
6<http://www.apache.org/licenses/LICENSE-2.0>), at your option. All
7files in the project carrying such notice may not be copied, modified,
8or distributed except according to those terms.
9*/
10/*!
11This crate provides several macros for deriving some useful methods for unitary enums (*i.e.* enums where variants do not have payloads).
12
13All of these macros are designed to be used with the [`custom_derive`](https://crates.io/crates/custom_derive) crate, though they can be used independent of it.
14
15> **Note**: see also the `TryFrom!` macro provided by the [`conv`](https://crates.io/crates/conv) crate to derive a function for creating enum values from integer values.
16
17# Example
18
19Derive iterators that yield all variants of an enum.
20
21```rust
22#[macro_use] extern crate custom_derive;
23#[macro_use] extern crate enum_derive;
24
25custom_derive! {
26    #[derive(Debug, PartialEq, Eq,
27        IterVariants(CandyVariants), IterVariantNames(CandyVariantNames))]
28    pub enum Candy { Musk, FruitRock, BoPeeps, LemonSherbert }
29}
30
31# fn main() {
32let vars: CandyVariants = Candy::iter_variants();
33let names: CandyVariantNames = Candy::iter_variant_names();
34assert_eq!(&*vars.zip(names).collect::<Vec<_>>(), &[
35    (Candy::Musk, "Musk"),
36    (Candy::FruitRock, "FruitRock"),
37    (Candy::BoPeeps, "BoPeeps"),
38    (Candy::LemonSherbert, "LemonSherbert"),
39]);
40# }
41```
42
43Alternately, derive `next_variant` and `prev_variant` methods.
44
45```rust
46#[macro_use] extern crate custom_derive;
47#[macro_use] extern crate enum_derive;
48
49use Hanagami::*;
50
51custom_derive! {
52    #[derive(Debug, PartialEq, Eq, NextVariant, PrevVariant)]
53    pub enum Hanagami { Sakigami, Hasugami, Tsutagami }
54}
55
56# fn main() {
57assert_eq!(Sakigami.next_variant(), Some(Hasugami));
58assert_eq!(Hasugami.next_variant(), Some(Tsutagami));
59assert_eq!(Tsutagami.next_variant(), None);
60
61assert_eq!(Sakigami.prev_variant(), None);
62assert_eq!(Hasugami.prev_variant(), Some(Sakigami));
63assert_eq!(Tsutagami.prev_variant(), Some(Hasugami));
64# }
65```
66
67# Overview
68
69This crate provides macros to derive the following methods for unitary variant enums:
70
71- `EnumDisplay` derives `Display`, which outputs the name of the variant.  Note that for unitary variants, this is identical to the behaviour of a derived `Debug` implementation.
72- `EnumFromStr` derives `FromStr`, allowing `str::parse` to be used.  It requires an exact match of the variant name.
73- `IterVariants` derives `iter_variants()`, which returns an iterator over the variants of the enum in lexical order.
74- `IterVariantNames` derives `iter_variant_names()`, which returns an iterator over the string names of the variants of the enum in lexical order.
75- `NextVariant` derives `next_variant(&self)`, which returns the next variant, or `None` when called for the last.
76- `PrevVariant` derives `prev_variant(&self)`, which returns the previous variant, or `None` when called for the first.
77- `EnumFromInner` derives `From<T>` for each variant's payload, assuming all variants are unary.
78- `EnumInnerAsTrait` derives a method to return a borrowed pointer to the inner value, cast to a trait object.
79
80Both of the `IterVariant*` macros accept a single deriving form.  Taking `IterVariants` as an example, it must be invoked like so:
81
82```rust
83# #[macro_use] extern crate custom_derive;
84# #[macro_use] extern crate enum_derive;
85custom_derive! {
86    #[derive(IterVariants(GetVariants))]
87    pub enum Get { Up, Down, AllAround }
88}
89# fn main() {}
90```
91
92The argument is the name of the iterator type that will be generated.  Neither macro imposes any naming requirements, save the obvious: the name must not conflict with any other types.
93
94`EnumInnerAsTrait` accepts a single deriving form that specifies the name of the method to be derived, whether the borrow should be mutable, and the trait of interest.  For example:
95
96```rust
97# #[macro_use] extern crate custom_derive;
98# #[macro_use] extern crate enum_derive;
99custom_derive! {
100    #[derive(EnumInnerAsTrait(pub as_display -> &std::fmt::Display))]
101    enum Value {
102        U32(u32),
103        U64(u64),
104    }
105}
106
107# fn main() {
108let s = format!("{}", Value::U64(42).as_display());
109assert_eq!(&s[..], "42");
110# }
111```
112
113The other macros take no arguments.
114
115The methods and iterator types generated will be public if the enum itself is public; otherwise, they will be private.
116
117## Using Without `custom_derive!`
118
119Although designed to be used with `custom_derive!`, all of the macros in this crate can be used without it.  The following:
120
121```rust
122# #[macro_use] extern crate custom_derive;
123# #[macro_use] extern crate enum_derive;
124custom_derive! {
125    #[derive(Copy, Clone, Debug, IterVariants(Vars))]
126    enum ItAintRight { BabeNo, NoNo, BoyBoy }
127}
128# fn main() {}
129```
130
131Can also be written as:
132
133```rust
134# #[macro_use] extern crate custom_derive;
135# #[macro_use] extern crate enum_derive;
136#[derive(Copy, Clone, Debug)]
137enum ItAintRight { BabeNo, NoNo, BoyBoy }
138
139IterVariants! { (Vars) enum ItAintRight { BabeNo, NoNo, BoyBoy } }
140# fn main() {}
141```
142
143## Other Examples
144
145This shows how to use `Display` and `FromStr` to perform string round-tripping of enums.
146
147```rust
148#[macro_use] extern crate custom_derive;
149#[macro_use] extern crate enum_derive;
150
151custom_derive! {
152    #[derive(Debug, PartialEq, EnumDisplay, EnumFromStr)]
153    pub enum TrollDigit { One, Two, Three, Many, Lots }
154}
155
156fn to_troll(mut n: u32) -> String {
157    use std::fmt::Write;
158    let mut s = String::new();
159
160    if n == 0 {
161        panic!("I dun' see nuffin'; how's I s'posed to count it?!");
162    }
163
164    while n > 0 {
165        let (del, dig) = match n {
166            n if n >= 16 => (16, TrollDigit::Lots),
167            n if n >= 4 => (4, TrollDigit::Many),
168            n if n >= 3 => (3, TrollDigit::Three),
169            n if n >= 2 => (2, TrollDigit::Two),
170            _ => (1, TrollDigit::One),
171        };
172        n -= del;
173        if s.len() > 0 { s.push_str(" "); }
174        write!(&mut s, "{}", dig).unwrap();
175    }
176
177    s
178}
179
180fn from_troll(s: &str) -> Result<u32, enum_derive::ParseEnumError> {
181    let mut n = 0;
182    for word in s.split_whitespace() {
183        n += match try!(word.parse()) {
184            TrollDigit::One => 1,
185            TrollDigit::Two => 2,
186            TrollDigit::Three => 3,
187            TrollDigit::Many => 4,
188            TrollDigit::Lots => 16,
189        };
190    }
191    if n == 0 {
192        Err(enum_derive::ParseEnumError)
193    } else {
194        Ok(n)
195    }
196}
197
198# fn main() {
199let number = 42;
200let troll_number = to_troll(number);
201assert_eq!(troll_number, "Lots Lots Many Many Two");
202assert_eq!(from_troll(&troll_number), Ok(number));
203# }
204```
205*/
206#![cfg_attr(not(feature = "std"), no_std)]
207
208#[cfg(not(feature = "std"))] extern crate core as std;
209
210use std::fmt;
211
212#[doc(hidden)]
213#[macro_export]
214macro_rules! enum_derive_util {
215    (@as_expr $e:expr) => {$e};
216    (@as_item $($i:item)+) => {$($i)+};
217    (@first_expr $head:expr, $($tail:expr),*) => {$head};
218    (@first_expr $head:expr) => {$head};
219
220    (
221        @collect_unitary_variants ($callback:ident { $($args:tt)* }),
222        ($(,)*) -> ($($var_names:ident,)*)
223    ) => {
224        enum_derive_util! {
225            @as_item
226            $callback!{ $($args)* ($($var_names),*) }
227        }
228    };
229
230    (
231        @collect_unitary_variants $fixed:tt,
232        (#[$_attr:meta] $($tail:tt)*) -> ($($var_names:tt)*)
233    ) => {
234        enum_derive_util! {
235            @collect_unitary_variants $fixed,
236            ($($tail)*) -> ($($var_names)*)
237        }
238    };
239
240    (
241        @collect_unitary_variants $fixed:tt,
242        ($var:ident $(= $_val:expr)*, $($tail:tt)*) -> ($($var_names:tt)*)
243    ) => {
244        enum_derive_util! {
245            @collect_unitary_variants $fixed,
246            ($($tail)*) -> ($($var_names)* $var,)
247        }
248    };
249
250    (
251        @collect_unitary_variants ($name:ident),
252        ($var:ident $_struct:tt, $($tail:tt)*) -> ($($var_names:tt)*)
253    ) => {
254        const _error: () = "cannot parse unitary variants from enum with non-unitary variants";
255    };
256
257    (
258        @collect_unary_variants ($callback:ident { $($args:tt)* }),
259        ($(,)*) -> ($($out:tt)*)
260    ) => {
261        enum_derive_util! {
262            @as_item
263            $callback!{ $($args)* ($($out)*) }
264        }
265    };
266
267    (
268        @collect_unary_variants $fixed:tt,
269        (#[$_attr:meta] $($tail:tt)*) -> ($($out:tt)*)
270    ) => {
271        enum_derive_util! {
272            @collect_unary_variants $fixed,
273            ($($tail)*) -> ($($out)*)
274        }
275    };
276
277    (
278        @collect_unary_variants $fixed:tt,
279        ($var_name:ident($var_ty:ty), $($tail:tt)*) -> ($($out:tt)*)
280    ) => {
281        enum_derive_util! {
282            @collect_unary_variants $fixed,
283            ($($tail)*) -> ($($out)* $var_name($var_ty),)
284        }
285    };
286
287    (
288        @collect_unary_variants $fixed:tt,
289        ($var_name:ident(pub $var_ty:ty), $($tail:tt)*) -> ($($out:tt)*)
290    ) => {
291        enum_derive_util! {
292            @collect_unary_variants $fixed,
293            ($($tail)*) -> ($($out)* $var_name($var_ty),)
294        }
295    };
296
297    (
298        @collect_unary_variants ($name:ident),
299        ($var:ident $_struct:tt, $($tail:tt)*) -> ($($_out:tt)*)
300    ) => {
301        const _error: () = "cannot parse unary variants from enum with non-unary tuple variants";
302    };
303}
304
305#[macro_export]
306macro_rules! IterVariants {
307    (
308        @expand ($($pub_:tt)*) $itername:ident, $name:ident ()
309    ) => {
310        enum_derive_util! { @as_item $($pub_)* struct $itername; }
311
312        impl ::std::iter::Iterator for $itername {
313            type Item = $name;
314            fn next(&mut self) -> ::std::option::Option<Self::Item> {
315                None
316            }
317
318            fn size_hint(&self) -> (usize, ::std::option::Option<usize>) {
319                (0, Some(0))
320            }
321        }
322
323        impl ::std::iter::ExactSizeIterator for $itername { }
324
325        enum_derive_util! {
326            @as_item
327            impl $name {
328                #[allow(dead_code)]
329                $($pub_)* fn iter_variants() -> $itername {
330                    $itername
331                }
332            }
333        }
334    };
335
336    (
337        @expand ($($pub_:tt)*) $itername:ident, $name:ident ($($var_names:ident),*)
338    ) => {
339        enum_derive_util! { @as_item $($pub_)* struct $itername(::std::option::Option<$name>); }
340
341        IterVariants! { @iter ($itername, $name), ($($var_names,)*) -> () () (0usize) }
342
343        enum_derive_util! {
344            @as_item
345            impl $name {
346                #[allow(dead_code)]
347                $($pub_)* fn iter_variants() -> $itername {
348                    $itername(::std::option::Option::Some(enum_derive_util!(@first_expr $($name::$var_names),+)))
349                }
350            }
351        }
352    };
353
354    (
355        @iter ($itername:ident, $name:ident), () -> ($($next_body:tt)*) ($($size_body:tt)*) ($($count:tt)*)
356    ) => {
357        enum_derive_util! {
358            @as_item
359            impl ::std::iter::Iterator for $itername {
360                type Item = $name;
361                fn next(&mut self) -> ::std::option::Option<Self::Item> {
362                    let next_item = match self.0 {
363                        $($next_body)*
364                        None => None
365                    };
366                    ::std::mem::replace(&mut self.0, next_item)
367                }
368
369                fn size_hint(&self) -> (usize, ::std::option::Option<usize>) {
370                    let variants = $($count)*;
371                    let progress = match self.0 {
372                        $($size_body)*
373                        None => variants
374                    };
375                    (variants - progress, ::std::option::Option::Some(variants - progress))
376                }
377            }
378
379            impl ::std::iter::ExactSizeIterator for $itername { }
380        }
381    };
382
383    (
384        @iter ($itername:ident, $name:ident), ($a:ident, $b:ident, $($rest:tt)*) -> ($($next_body:tt)*) ($($size_body:tt)*) ($($count:tt)*)
385    ) => {
386        IterVariants! {
387            @iter ($itername, $name), ($b, $($rest)*)
388            -> (
389                $($next_body)*
390                ::std::option::Option::Some($name::$a) => ::std::option::Option::Some($name::$b),
391            )
392            (
393                $($size_body)*
394                ::std::option::Option::Some($name::$a) => $($count)*,
395            )
396            ($($count)* + 1usize)
397        }
398    };
399
400    (
401        @iter ($itername:ident, $name:ident), ($a:ident,) -> ($($next_body:tt)*) ($($size_body:tt)*) ($($count:tt)*)
402    ) => {
403        IterVariants! {
404            @iter ($itername, $name), ()
405            -> (
406                $($next_body)*
407                ::std::option::Option::Some($name::$a) => ::std::option::Option::None,
408            )
409            (
410                $($size_body)*
411                ::std::option::Option::Some($name::$a) => $($count)*,
412            )
413            ($($count)* + 1usize)
414        }
415    };
416
417    (($itername:ident) pub enum $name:ident { $($body:tt)* }) => {
418        enum_derive_util! {
419            @collect_unitary_variants
420            (IterVariants { @expand (pub) $itername, $name }),
421            ($($body)*,) -> ()
422        }
423    };
424
425    (($itername:ident) enum $name:ident { $($body:tt)* }) => {
426        enum_derive_util! {
427            @collect_unitary_variants
428            (IterVariants { @expand () $itername, $name }),
429            ($($body)*,) -> ()
430        }
431    };
432}
433
434#[macro_export]
435macro_rules! IterVariantNames {
436    (
437        @expand ($($pub_:tt)*) $itername:ident, $name:ident ()
438    ) => {
439        enum_derive_util! { @as_item $($pub_)* struct $itername; }
440
441        impl ::std::iter::Iterator for $itername {
442            type Item = &'static str;
443            fn next(&mut self) -> ::std::option::Option<Self::Item> {
444                None
445            }
446
447            fn size_hint(&self) -> (usize, ::std::option::Option<usize>) {
448                (0, Some(0))
449            }
450        }
451
452        impl ::std::iter::ExactSizeIterator for $itername { }
453
454        enum_derive_util! {
455            @as_item
456            impl $name {
457                #[allow(dead_code)]
458                $($pub_)* fn iter_variant_names() -> $itername {
459                    $itername
460                }
461            }
462        }
463    };
464
465    (
466        @expand ($($pub_:tt)*) $itername:ident, $name:ident ($($var_names:ident),*)
467    ) => {
468        enum_derive_util! { @as_item $($pub_)* struct $itername(::std::option::Option<$name>); }
469
470        IterVariantNames! { @iter ($itername, $name), ($($var_names,)*) -> () () (0usize) }
471
472        enum_derive_util! {
473            @as_item
474            impl $name {
475                #[allow(dead_code)]
476                $($pub_)* fn iter_variant_names() -> $itername {
477                    $itername(::std::option::Option::Some(enum_derive_util!(@first_expr $($name::$var_names),+)))
478                }
479            }
480        }
481    };
482
483    (
484        @iter ($itername:ident, $name:ident), () -> ($($next_body:tt)*) ($($size_body:tt)*) ($($count:tt)*)
485    ) => {
486        enum_derive_util! {
487            @as_item
488            impl ::std::iter::Iterator for $itername {
489                type Item = &'static str;
490                fn next(&mut self) -> ::std::option::Option<Self::Item> {
491                    let (next_state, result) = match self.0 {
492                        $($next_body)*
493                        ::std::option::Option::None => (::std::option::Option::None, ::std::option::Option::None)
494                    };
495                    self.0 = next_state;
496                    result
497                }
498
499                fn size_hint(&self) -> (usize, ::std::option::Option<usize>) {
500                    let variants = $($count)*;
501                    let progress = match self.0 {
502                        $($size_body)*
503                        None => variants
504                    };
505                    (variants - progress, ::std::option::Option::Some(variants - progress))
506                }
507            }
508
509            impl ::std::iter::ExactSizeIterator for $itername { }
510        }
511    };
512
513    (
514        @iter ($itername:ident, $name:ident), ($a:ident, $b:ident, $($rest:tt)*) -> ($($next_body:tt)*) ($($size_body:tt)*) ($($count:tt)*)
515    ) => {
516        IterVariantNames! {
517            @iter ($itername, $name), ($b, $($rest)*)
518            -> (
519                $($next_body)*
520                ::std::option::Option::Some($name::$a)
521                    => (::std::option::Option::Some($name::$b), ::std::option::Option::Some(stringify!($a))),
522            )
523            (
524                $($size_body)*
525                ::std::option::Option::Some($name::$a) => $($count)*,
526            )
527            ($($count)* + 1usize)
528        }
529    };
530
531    (
532        @iter ($itername:ident, $name:ident), ($a:ident,) -> ($($next_body:tt)*) ($($size_body:tt)*) ($($count:tt)*)
533    ) => {
534        IterVariantNames! {
535            @iter ($itername, $name), ()
536            -> (
537                $($next_body)*
538                ::std::option::Option::Some($name::$a)
539                    => (::std::option::Option::None, ::std::option::Option::Some(stringify!($a))),
540            )
541            (
542                $($size_body)*
543                ::std::option::Option::Some($name::$a) => $($count)*,
544            )
545            ($($count)* + 1usize)
546        }
547    };
548
549    (($itername:ident) pub enum $name:ident { $($body:tt)* }) => {
550        enum_derive_util! {
551            @collect_unitary_variants
552            (IterVariantNames { @expand (pub) $itername, $name }),
553            ($($body)*,) -> ()
554        }
555    };
556
557    (($itername:ident) enum $name:ident { $($body:tt)* }) => {
558        enum_derive_util! {
559            @collect_unitary_variants
560            (IterVariantNames { @expand () $itername, $name }),
561            ($($body)*,) -> ()
562        }
563    };
564}
565
566#[macro_export]
567macro_rules! NextVariant {
568    (
569        @expand ($($pub_:tt)*) $name:ident ()
570    ) => {
571        enum_derive_util! {
572            @as_item
573            impl $name {
574                #[allow(dead_code)]
575                $($pub_)* fn next_variant(&self) -> ::std::option::Option<$name> {
576                    loop {} // unreachable
577                }
578            }
579        }
580    };
581
582    (
583        @expand ($($pub_:tt)*) $name:ident ($($var_names:ident),*)
584    ) => {
585        enum_derive_util! {
586            @as_item
587            impl $name {
588                #[allow(dead_code)]
589                $($pub_)* fn next_variant(&self) -> ::std::option::Option<$name> {
590                    NextVariant!(@arms ($name, self), ($($var_names)*) -> ())
591                }
592            }
593        }
594    };
595
596    (
597        @arms ($name:ident, $self_:expr), ($a:ident) -> ($($body:tt)*)
598    ) => {
599        enum_derive_util! {
600            @as_expr
601            match *$self_ {
602                $($body)*
603                $name::$a => ::std::option::Option::None
604            }
605        }
606    };
607
608    (
609        @arms ($name:ident, $self_:expr), ($a:ident $b:ident $($rest:tt)*) -> ($($body:tt)*)
610    ) => {
611        NextVariant! {
612            @arms ($name, $self_), ($b $($rest)*)
613            -> (
614                $($body)*
615                $name::$a => ::std::option::Option::Some($name::$b),
616            )
617        }
618    };
619
620    (() pub enum $name:ident { $($body:tt)* }) => {
621        enum_derive_util! {
622            @collect_unitary_variants
623            (NextVariant { @expand (pub) $name }),
624            ($($body)*,) -> ()
625        }
626    };
627
628    (() enum $name:ident { $($body:tt)* }) => {
629        enum_derive_util! {
630            @collect_unitary_variants
631            (NextVariant { @expand () $name }),
632            ($($body)*,) -> ()
633        }
634    };
635}
636
637#[macro_export]
638macro_rules! PrevVariant {
639    (
640        @expand ($($pub_:tt)*) $name:ident ()
641    ) => {
642        enum_derive_util! {
643            @as_item
644            impl $name {
645                #[allow(dead_code)]
646                $($pub_)* fn prev_variant(&self) -> ::std::option::Option<$name> {
647                    loop {} // unreachable
648                }
649            }
650        }
651    };
652
653    (
654        @expand ($($pub_:tt)*) $name:ident ($($var_names:ident),*)
655    ) => {
656        enum_derive_util! {
657            @as_item
658            impl $name {
659                #[allow(dead_code)]
660                $($pub_)* fn prev_variant(&self) -> ::std::option::Option<$name> {
661                    PrevVariant!(@arms ($name, self), (::std::option::Option::None, $($var_names)*) -> ())
662                }
663            }
664        }
665    };
666
667    (
668        @arms ($name:ident, $self_:expr), ($prev:expr, $a:ident) -> ($($body:tt)*)
669    ) => {
670        enum_derive_util! {
671            @as_expr
672            match *$self_ {
673                $($body)*
674                $name::$a => $prev
675            }
676        }
677    };
678
679    (
680        @arms ($name:ident, $self_:expr), ($prev:expr, $a:ident $($rest:tt)*) -> ($($body:tt)*)
681    ) => {
682        PrevVariant! {
683            @arms ($name, $self_), (::std::option::Option::Some($name::$a), $($rest)*)
684            -> (
685                $($body)*
686                $name::$a => $prev,
687            )
688        }
689    };
690
691    (() pub enum $name:ident { $($body:tt)* }) => {
692        enum_derive_util! {
693            @collect_unitary_variants
694            (PrevVariant { @expand (pub) $name }),
695            ($($body)*,) -> ()
696        }
697    };
698
699    (() enum $name:ident { $($body:tt)* }) => {
700        enum_derive_util! {
701            @collect_unitary_variants
702            (PrevVariant { @expand () $name }),
703            ($($body)*,) -> ()
704        }
705    };
706}
707
708#[macro_export]
709macro_rules! EnumDisplay {
710    (
711        @expand $name:ident ()
712    ) => {
713        enum_derive_util! {
714            @as_item
715            impl ::std::fmt::Display for $name {
716                fn fmt(&self, _: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
717                    loop {} // unreachable
718                }
719            }
720        }
721    };
722
723    (
724        @expand $name:ident ($($var_names:ident),*)
725    ) => {
726        enum_derive_util! {
727            @as_item
728            impl ::std::fmt::Display for $name {
729                fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
730                    EnumDisplay!(@arms ($name, self, f), ($($var_names)*) -> ())
731                }
732            }
733        }
734    };
735
736    (
737        @arms ($name:ident, $self_:expr, $f:ident), ($a:ident) -> ($($body:tt)*)
738    ) => {
739        enum_derive_util! {
740            @as_expr
741            match *$self_ {
742                $($body)*
743                $name::$a => write!($f, stringify!($a)),
744            }
745        }
746    };
747
748    (
749        @arms ($name:ident, $self_:expr, $f:ident), ($a:ident $b:ident $($rest:tt)*) -> ($($body:tt)*)
750    ) => {
751        EnumDisplay! {
752            @arms ($name, $self_, $f), ($b $($rest)*)
753            -> (
754                $($body)*
755                $name::$a => write!($f, stringify!($a)),
756            )
757        }
758    };
759
760    (() pub enum $name:ident { $($body:tt)* }) => {
761        enum_derive_util! {
762            @collect_unitary_variants
763            (EnumDisplay { @expand $name }),
764            ($($body)*,) -> ()
765        }
766    };
767
768    (() enum $name:ident { $($body:tt)* }) => {
769        enum_derive_util! {
770            @collect_unitary_variants
771            (EnumDisplay { @expand $name }),
772            ($($body)*,) -> ()
773        }
774    };
775}
776
777#[macro_export]
778macro_rules! EnumFromStr {
779    (
780        @expand ($($pub_:tt)*) $name:ident ()
781    ) => {
782        enum_derive_util! {
783            @as_item
784            impl ::std::str::FromStr for $name {
785                type Err = $crate::ParseEnumError;
786
787                fn from_str(_: &str) -> ::std::result::Result<Self, Self::Err> {
788                    Err($crate::ParseEnumError)
789                }
790            }
791        }
792    };
793
794    (
795        @expand ($($pub_:tt)*) $name:ident ($($var_names:ident),*)
796    ) => {
797        enum_derive_util! {
798            @as_item
799            impl ::std::str::FromStr for $name {
800                type Err = $crate::ParseEnumError;
801
802                fn from_str(s: &str) -> Result<Self, Self::Err> {
803                    EnumFromStr!(@arms ($name, s), ($($var_names)*) -> ())
804                }
805            }
806        }
807    };
808
809    (
810        @arms ($name:ident, $s:ident), ($a:ident) -> ($($body:tt)*)
811    ) => {
812        enum_derive_util! {
813            @as_expr
814            match $s {
815                $($body)*
816                stringify!($a) => ::std::result::Result::Ok($name::$a),
817                _ => ::std::result::Result::Err($crate::ParseEnumError)
818            }
819        }
820    };
821
822    (
823        @arms ($name:ident, $s:ident), ($a:ident $b:ident $($rest:tt)*) -> ($($body:tt)*)
824    ) => {
825        EnumFromStr! {
826            @arms ($name, $s), ($b $($rest)*)
827            -> (
828                $($body)*
829                stringify!($a) => ::std::result::Result::Ok($name::$a),
830            )
831        }
832    };
833
834    (() pub enum $name:ident { $($body:tt)* }) => {
835        enum_derive_util! {
836            @collect_unitary_variants
837            (EnumFromStr { @expand (pub) $name }),
838            ($($body)*,) -> ()
839        }
840    };
841
842    (() enum $name:ident { $($body:tt)* }) => {
843        enum_derive_util! {
844            @collect_unitary_variants
845            (EnumFromStr { @expand () $name }),
846            ($($body)*,) -> ()
847        }
848    };
849}
850
851/**
852This is the error type used for derived implementations of `FromStr` for unitary enums.
853
854See the crate documentation for the `EnumFromStr!` macro.
855*/
856#[derive(Clone, Debug, Eq, PartialEq)]
857pub struct ParseEnumError;
858
859impl fmt::Display for ParseEnumError {
860    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
861        write!(fmt, "provided string did not match any enum variant")
862    }
863}
864
865#[cfg(feature = "std")]
866impl ::std::error::Error for ParseEnumError {
867    fn description(&self) -> &str {
868        "provided string did not match any enum variant"
869    }
870}
871
872#[macro_export]
873macro_rules! EnumFromInner {
874    (
875        @expand $name:ident ($($var_names:ident($var_tys:ty),)*)
876    ) => {
877        $(
878            impl ::std::convert::From<$var_tys> for $name {
879                fn from(v: $var_tys) -> $name {
880                    $name::$var_names(v)
881                }
882            }
883        )*
884    };
885
886    (() $(pub)* enum $name:ident { $($body:tt)* }) => {
887        enum_derive_util! {
888            @collect_unary_variants
889            (EnumFromInner { @expand $name }),
890            ($($body)*,) -> ()
891        }
892    };
893}
894
895#[macro_export]
896macro_rules! EnumInnerAsTrait {
897    (
898        @expand (pub $fn_name:ident -> &mut $tr:ty), $($tail:tt)*
899    ) => {
900        EnumInnerAsTrait! { @expand_inner (pub), $fn_name, (mut), $tr, $($tail)* }
901    };
902
903    (
904        @expand (pub $fn_name:ident -> &$tr:ty), $($tail:tt)*
905    ) => {
906        EnumInnerAsTrait! { @expand_inner (pub), $fn_name, (), $tr, $($tail)* }
907    };
908
909    (
910        @expand ($fn_name:ident -> &mut $tr:ty), $($tail:tt)*
911    ) => {
912        EnumInnerAsTrait! { @expand_inner (), $fn_name, (mut), $tr, $($tail)* }
913    };
914
915    (
916        @expand ($fn_name:ident -> &$tr:ty), $($tail:tt)*
917    ) => {
918        EnumInnerAsTrait! { @expand_inner (), $fn_name, (), $tr, $($tail)* }
919    };
920
921    (
922        @expand_inner
923        ($($vis:tt)*), $fn_name:ident, (mut), $tr:ty,
924        $ty_name:ident,
925        ($($var_names:ident($_var_tys:ty),)*)
926    ) => {
927        enum_derive_util! {
928            @as_item
929            impl $ty_name {
930                $($vis)* fn $fn_name(&mut self) -> &mut $tr {
931                    match *self {
932                        $(
933                            $ty_name::$var_names(ref mut v) => v as &mut $tr,
934                        )*
935                    }
936                }
937            }
938        }
939    };
940
941    (
942        @expand_inner
943        ($($vis:tt)*), $fn_name:ident, (), $tr:ty,
944        $ty_name:ident,
945        ($($var_names:ident($_var_tys:ty),)*)
946    ) => {
947        enum_derive_util! {
948            @as_item
949            impl $ty_name {
950                $($vis)* fn $fn_name(&self) -> &$tr {
951                    match *self {
952                        $(
953                            $ty_name::$var_names(ref v) => v as &$tr,
954                        )*
955                    }
956                }
957            }
958        }
959    };
960
961    ($arg:tt $(pub)* enum $name:ident { $($body:tt)* }) => {
962        enum_derive_util! {
963            @collect_unary_variants
964            (EnumInnerAsTrait { @expand $arg, $name, }),
965            ($($body)*,) -> ()
966        }
967    };
968}