enum_derive_2018/
lib.rs

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