1#![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 {} }
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 {} }
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 {} }
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#[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}