1#![cfg_attr(not(test), no_std)]
2#![warn(missing_docs, rust_2018_idioms)]
3#[macro_export]
299macro_rules! ai_quick_error {
300
301 ( $(#[$meta:meta])*
302 pub enum $name:ident { $($chunks:tt)* }
303 ) => {
304 ai_quick_error!(SORT [pub enum $name $(#[$meta])* ]
305 items [] buf []
306 queue [ $($chunks)* ]);
307 };
308 ( $(#[$meta:meta])*
309 enum $name:ident { $($chunks:tt)* }
310 ) => {
311 ai_quick_error!(SORT [enum $name $(#[$meta])* ]
312 items [] buf []
313 queue [ $($chunks)* ]);
314 };
315
316 ( $(#[$meta:meta])*
317 pub enum $name:ident wraps $enum_name:ident { $($chunks:tt)* }
318 ) => {
319 ai_quick_error!(WRAPPER $enum_name [ pub struct ] $name $(#[$meta])*);
320 ai_quick_error!(SORT [enum $enum_name $(#[$meta])* ]
321 items [] buf []
322 queue [ $($chunks)* ]);
323 };
324
325 ( $(#[$meta:meta])*
326 pub enum $name:ident wraps pub $enum_name:ident { $($chunks:tt)* }
327 ) => {
328 ai_quick_error!(WRAPPER $enum_name [ pub struct ] $name $(#[$meta])*);
329 ai_quick_error!(SORT [pub enum $enum_name $(#[$meta])* ]
330 items [] buf []
331 queue [ $($chunks)* ]);
332 };
333 ( $(#[$meta:meta])*
334 enum $name:ident wraps $enum_name:ident { $($chunks:tt)* }
335 ) => {
336 ai_quick_error!(WRAPPER $enum_name [ struct ] $name $(#[$meta])*);
337 ai_quick_error!(SORT [enum $enum_name $(#[$meta])* ]
338 items [] buf []
339 queue [ $($chunks)* ]);
340 };
341
342 ( $(#[$meta:meta])*
343 enum $name:ident wraps pub $enum_name:ident { $($chunks:tt)* }
344 ) => {
345 ai_quick_error!(WRAPPER $enum_name [ struct ] $name $(#[$meta])*);
346 ai_quick_error!(SORT [pub enum $enum_name $(#[$meta])* ]
347 items [] buf []
348 queue [ $($chunks)* ]);
349 };
350
351
352 (
353 WRAPPER $internal:ident [ $($strdef:tt)* ] $strname:ident
354 $(#[$meta:meta])*
355 ) => {
356 $(#[$meta])*
357 $($strdef)* $strname ( $internal );
358
359 impl ::core::fmt::Display for $strname {
360 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>)
361 -> ::core::fmt::Result
362 {
363 ::core::fmt::Display::fmt(&self.0, f)
364 }
365 }
366
367 impl From<$internal> for $strname {
368 fn from(err: $internal) -> Self {
369 $strname(err)
370 }
371 }
372
373 impl ::core::error::Error for $strname {
374 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
375 self.0.source()
376 }
377 }
378 };
379
380 (SORT [enum $name:ident $( #[$meta:meta] )*]
382 items [$($( #[$imeta:meta] )*
383 => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
384 {$( $ifuncs:tt )*} )* ]
385 buf [ ]
386 queue [ ]
387 ) => {
388 ai_quick_error!(ENUM_DEFINITION [enum $name $( #[$meta] )*]
389 body []
390 queue [$($( #[$imeta] )*
391 => $iitem: $imode [$( $ivar: $ityp ),*] )*]
392 );
393 ai_quick_error!(IMPLEMENTATIONS $name {$(
394 $iitem: $imode [$(#[$imeta])*] [$( $ivar: $ityp ),*] {$( $ifuncs )*}
395 )*});
396 $(
397 ai_quick_error!(ERROR_CHECK $imode $($ifuncs)*);
398 )*
399 };
400 (SORT [pub enum $name:ident $( #[$meta:meta] )*]
401 items [$($( #[$imeta:meta] )*
402 => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
403 {$( $ifuncs:tt )*} )* ]
404 buf [ ]
405 queue [ ]
406 ) => {
407 ai_quick_error!(ENUM_DEFINITION [pub enum $name $( #[$meta] )*]
408 body []
409 queue [$($( #[$imeta] )*
410 => $iitem: $imode [$( $ivar: $ityp ),*] )*]
411 );
412 ai_quick_error!(IMPLEMENTATIONS $name {$(
413 $iitem: $imode [$(#[$imeta])*] [$( $ivar: $ityp ),*] {$( $ifuncs )*}
414 )*});
415 $(
416 ai_quick_error!(ERROR_CHECK $imode $($ifuncs)*);
417 )*
418 };
419 (SORT [$( $def:tt )*]
421 items [$($( #[$imeta:meta] )*
422 => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
423 {$( $ifuncs:tt )*} )* ]
424 buf [$( #[$bmeta:meta] )*]
425 queue [ #[$qmeta:meta] $( $tail:tt )*]
426 ) => {
427 ai_quick_error!(SORT [$( $def )*]
428 items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
429 buf [$( #[$bmeta] )* #[$qmeta] ]
430 queue [$( $tail )*]);
431 };
432 (SORT [$( $def:tt )*]
434 items [$($( #[$imeta:meta] )*
435 => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
436 {$( $ifuncs:tt )*} )* ]
437 buf [$( #[$bmeta:meta] )*]
438 queue [ $qitem:ident $( $tail:tt )*]
439 ) => {
440 ai_quick_error!(SORT [$( $def )*]
441 items [$( $(#[$imeta])*
442 => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
443 buf [$(#[$bmeta])* => $qitem : UNIT [ ] ]
444 queue [$( $tail )*]);
445 };
446 (SORT [$( $def:tt )*]
448 items [$($( #[$imeta:meta] )*
449 => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
450 {$( $ifuncs:tt )*} )* ]
451 buf [$( #[$bmeta:meta] )*
452 => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ]
453 queue [ #[$qmeta:meta] $( $tail:tt )*]
454 ) => {
455 ai_quick_error!(SORT [$( $def )*]
456 items [$($( #[$imeta:meta] )*
457 => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*
458 $bitem: $bmode [$( $bvar:$btyp ),*] {} ]
459 buf [ #[$qmeta] ]
460 queue [$( $tail )*]);
461 };
462 (SORT [$( $def:tt )*]
464 items [$($( #[$imeta:meta] )*
465 => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
466 {$( $ifuncs:tt )*} )* ]
467 buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ]
468 queue [($( $qvar:ident: $qtyp:ty ),+) $( $tail:tt )*]
469 ) => {
470 ai_quick_error!(SORT [$( $def )*]
471 items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
472 buf [$( #[$bmeta] )* => $bitem: TUPLE [$( $qvar:$qtyp ),+] ]
473 queue [$( $tail )*]
474 );
475 };
476 (SORT [$( $def:tt )*]
478 items [$($( #[$imeta:meta] )*
479 => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
480 {$( $ifuncs:tt )*} )* ]
481 buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ]
482 queue [{ $( $qvar:ident: $qtyp:ty ),+} $( $tail:tt )*]
483 ) => {
484 ai_quick_error!(SORT [$( $def )*]
485 items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
486 buf [$( #[$bmeta] )* => $bitem: STRUCT [$( $qvar:$qtyp ),+] ]
487 queue [$( $tail )*]);
488 };
489 (SORT [$( $def:tt )*]
491 items [$($( #[$imeta:meta] )*
492 => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
493 {$( $ifuncs:tt )*} )* ]
494 buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ]
495 queue [{$( $qvar:ident: $qtyp:ty ),+ ,} $( $tail:tt )*]
496 ) => {
497 ai_quick_error!(SORT [$( $def )*]
498 items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
499 buf [$( #[$bmeta] )* => $bitem: STRUCT [$( $qvar:$qtyp ),+] ]
500 queue [$( $tail )*]);
501 };
502 (SORT [$( $def:tt )*]
504 items [$($( #[$imeta:meta] )*
505 => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
506 {$( $ifuncs:tt )*} )* ]
507 buf [$( #[$bmeta:meta] )*
508 => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ]
509 queue [ {$( $qfuncs:tt )*} $( $tail:tt )*]
510 ) => {
511 ai_quick_error!(SORT [$( $def )*]
512 items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*
513 $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {$( $qfuncs )*} ]
514 buf [ ]
515 queue [$( $tail )*]);
516 };
517 (SORT [$( $def:tt )*]
519 items [$($( #[$imeta:meta] )*
520 => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
521 {$( $ifuncs:tt )*} )* ]
522 buf [$( #[$bmeta:meta] )*
523 => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ]
524 queue [ $qitem:ident $( $tail:tt )*]
525 ) => {
526 ai_quick_error!(SORT [$( $def )*]
527 items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*
528 $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {} ]
529 buf [ => $qitem : UNIT [ ] ]
530 queue [$( $tail )*]);
531 };
532 (SORT [$( $def:tt )*]
534 items [$($( #[$imeta:meta] )*
535 => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
536 {$( $ifuncs:tt )*} )* ]
537 buf [$( #[$bmeta:meta] )*
538 => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ]
539 queue [ ]
540 ) => {
541 ai_quick_error!(SORT [$( $def )*]
542 items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*
543 $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {} ]
544 buf [ ]
545 queue [ ]);
546 };
547 (ENUM_DEFINITION [pub enum $name:ident $( #[$meta:meta] )*]
549 body [$($( #[$imeta:meta] )*
550 => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ]
551 queue [ ]
552 ) => {
553 #[allow(unknown_lints)] #[allow(renamed_and_removed_lints)]
555 #[allow(unused_doc_comment)]
556 #[allow(unused_doc_comments)]
557 $(#[$meta])*
558 pub enum $name {
559 $(
560 $(#[$imeta])*
561 $iitem $(($( $ttyp ),+))* $({$( $svar: $styp ),*})*,
562 )*
563 }
564 };
565 (ENUM_DEFINITION [enum $name:ident $( #[$meta:meta] )*]
567 body [$($( #[$imeta:meta] )*
568 => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ]
569 queue [ ]
570 ) => {
571 #[allow(unknown_lints)] #[allow(renamed_and_removed_lints)]
573 #[allow(unused_doc_comment)]
574 #[allow(unused_doc_comments)]
575 $(#[$meta])*
576 enum $name {
577 $(
578 $(#[$imeta])*
579 $iitem $(($( $ttyp ),+))* $({$( $svar: $styp ),*})*,
580 )*
581 }
582 };
583 (ENUM_DEFINITION [$( $def:tt )*]
585 body [$($( #[$imeta:meta] )*
586 => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ]
587 queue [$( #[$qmeta:meta] )*
588 => $qitem:ident: UNIT [ ] $( $queue:tt )*]
589 ) => {
590 ai_quick_error!(ENUM_DEFINITION [ $($def)* ]
591 body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )*
592 $( #[$qmeta] )* => $qitem () {} ]
593 queue [ $($queue)* ]
594 );
595 };
596 (ENUM_DEFINITION [$( $def:tt )*]
598 body [$($( #[$imeta:meta] )*
599 => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ]
600 queue [$( #[$qmeta:meta] )*
601 => $qitem:ident: TUPLE [$( $qvar:ident: $qtyp:ty ),+] $( $queue:tt )*]
602 ) => {
603 ai_quick_error!(ENUM_DEFINITION [ $($def)* ]
604 body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )*
605 $( #[$qmeta] )* => $qitem (($( $qtyp ),+)) {} ]
606 queue [ $($queue)* ]
607 );
608 };
609 (ENUM_DEFINITION [$( $def:tt )*]
611 body [$($( #[$imeta:meta] )*
612 => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ]
613 queue [$( #[$qmeta:meta] )*
614 => $qitem:ident: STRUCT [$( $qvar:ident: $qtyp:ty ),*] $( $queue:tt )*]
615 ) => {
616 ai_quick_error!(ENUM_DEFINITION [ $($def)* ]
617 body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )*
618 $( #[$qmeta] )* => $qitem () {{$( $qvar: $qtyp ),*}} ]
619 queue [ $($queue)* ]
620 );
621 };
622 (IMPLEMENTATIONS
623 $name:ident {$(
624 $item:ident: $imode:tt [$(#[$imeta:meta])*] [$( $var:ident: $typ:ty ),*] {$( $funcs:tt )*}
625 )*}
626 ) => {
627 #[allow(unused_variables)]
628 #[allow(unknown_lints)] #[allow(renamed_and_removed_lints)]
630 #[allow(unused_doc_comment)]
631 #[allow(unused_doc_comments)]
632 impl ::core::fmt::Display for $name {
633 fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>)
634 -> ::core::fmt::Result
635 {
636 match *self {
637 $(
638 $(#[$imeta])*
639 ai_quick_error!(ITEM_PATTERN
640 $name $item: $imode [$( ref $var ),*]
641 ) => {
642 let display_fn = ai_quick_error!(FIND_DISPLAY_IMPL
643 $name $item: $imode
644 {$( $funcs )*});
645
646 display_fn(self, fmt)
647 }
648 )*
649 }
650 }
651 }
652 #[allow(unused_variables)]
653 #[allow(unknown_lints)] #[allow(renamed_and_removed_lints)]
655 #[allow(unused_doc_comment)]
656 #[allow(unused_doc_comments)]
657 impl ::core::error::Error for $name {
658 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
659 match *self {
660 $(
661 $(#[$imeta])*
662 ai_quick_error!(ITEM_PATTERN
663 $name $item: $imode [$( ref $var ),*]
664 ) => {
665 ai_quick_error!(FIND_SOURCE_IMPL
666 $item: $imode [$( $var ),*]
667 {$( $funcs )*})
668 }
669 )*
670 }
671 }
672 }
673 $(
674 ai_quick_error!(FIND_FROM_IMPL
675 $name $item: $imode [$( $var:$typ ),*]
676 {$( $funcs )*});
677 )*
678 $(
679 ai_quick_error!(FIND_CONTEXT_IMPL
680 $name $item: $imode [$( $var:$typ ),*]
681 {$( $funcs )*});
682 )*
683 };
684 (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
685 { display($self_:tt) -> ($( $exprs:tt )*) $( $tail:tt )*}
686 ) => {
687 |ai_quick_error!(IDENT $self_): &$name, f: &mut ::core::fmt::Formatter<'_>| { write!(f, $( $exprs )*) }
688 };
689 (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
690 { display($pattern:expr) $( $tail:tt )*}
691 ) => {
692 |_, f: &mut ::core::fmt::Formatter<'_>| { write!(f, $pattern) }
693 };
694 (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
695 { display($pattern:expr, $( $exprs:tt )*) $( $tail:tt )*}
696 ) => {
697 |_, f: &mut ::core::fmt::Formatter<'_>| { write!(f, $pattern, $( $exprs )*) }
698 };
699 (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
700 { $t:tt $( $tail:tt )*}
701 ) => {
702 ai_quick_error!(FIND_DISPLAY_IMPL
703 $name $item: $imode
704 {$( $tail )*})
705 };
706 (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
707 { }
708 ) => {
709 |self_: &$name, f: &mut ::core::fmt::Formatter<'_>| {
710 write!(f, "{:?}", self_)
711 }
712 };
713 (FIND_SOURCE_IMPL $item:ident: $imode:tt
714 [$( $var:ident ),*]
715 { source($expr:expr) $( $tail:tt )*}
716 ) => {
717 Some($expr)
718 };
719 (FIND_SOURCE_IMPL $item:ident: $imode:tt
720 [$( $var:ident ),*]
721 { $t:tt $( $tail:tt )*}
722 ) => {
723 ai_quick_error!(FIND_SOURCE_IMPL
724 $item: $imode [$( $var ),*]
725 { $($tail)* })
726 };
727 (FIND_SOURCE_IMPL $item:ident: $imode:tt
728 [$( $var:ident ),*]
729 { }
730 ) => {
731 None
732 };
733 (FIND_FROM_IMPL $name:ident $item:ident: $imode:tt
735 [$( $var:ident: $typ:ty ),*]
736 { from() $( $tail:tt )*}
737 ) => {
738 $(
739 impl From<$typ> for $name {
740 fn from($var: $typ) -> $name {
741 $name::$item($var)
742 }
743 }
744 )*
745 ai_quick_error!(FIND_FROM_IMPL
746 $name $item: $imode [$( $var:$typ ),*]
747 {$( $tail )*});
748 };
749 (FIND_FROM_IMPL $name:ident $item:ident: UNIT
750 [ ]
751 { from($ftyp:ty) $( $tail:tt )*}
752 ) => {
753 impl From<$ftyp> for $name {
754 fn from(_discarded_error: $ftyp) -> $name {
755 $name::$item
756 }
757 }
758 ai_quick_error!(FIND_FROM_IMPL
759 $name $item: UNIT [ ]
760 {$( $tail )*});
761 };
762 (FIND_FROM_IMPL $name:ident $item:ident: TUPLE
763 [$( $var:ident: $typ:ty ),*]
764 { from($fvar:ident: $ftyp:ty) -> ($( $texpr:expr ),*) $( $tail:tt )*}
765 ) => {
766 impl From<$ftyp> for $name {
767 fn from($fvar: $ftyp) -> $name {
768 $name::$item($( $texpr ),*)
769 }
770 }
771 ai_quick_error!(FIND_FROM_IMPL
772 $name $item: TUPLE [$( $var:$typ ),*]
773 { $($tail)* });
774 };
775 (FIND_FROM_IMPL $name:ident $item:ident: STRUCT
776 [$( $var:ident: $typ:ty ),*]
777 { from($fvar:ident: $ftyp:ty) -> {$( $tvar:ident: $texpr:expr ),*} $( $tail:tt )*}
778 ) => {
779 impl From<$ftyp> for $name {
780 fn from($fvar: $ftyp) -> $name {
781 $name::$item {
782 $( $tvar: $texpr ),*
783 }
784 }
785 }
786 ai_quick_error!(FIND_FROM_IMPL
787 $name $item: STRUCT [$( $var:$typ ),*]
788 { $($tail)* });
789 };
790 (FIND_FROM_IMPL $name:ident $item:ident: $imode:tt
791 [$( $var:ident: $typ:ty ),*]
792 { $t:tt $( $tail:tt )*}
793 ) => {
794 ai_quick_error!(FIND_FROM_IMPL
795 $name $item: $imode [$( $var:$typ ),*]
796 {$( $tail )*}
797 );
798 };
799 (FIND_FROM_IMPL $name:ident $item:ident: $imode:tt
800 [$( $var:ident: $typ:ty ),*]
801 { }
802 ) => {
803 };
804 (FIND_CONTEXT_IMPL $name:ident $item:ident: TUPLE
806 [$( $var:ident: $typ:ty ),*]
807 { context($cvar:ident: AsRef<$ctyp:ty>, $fvar:ident: $ftyp:ty)
808 -> ($( $texpr:expr ),*) $( $tail:tt )* }
809 ) => {
810 impl<T: AsRef<$ctyp>> From<$crate::Context<T, $ftyp>> for $name {
811 fn from(
812 $crate::Context($cvar, $fvar): $crate::Context<T, $ftyp>)
813 -> $name
814 {
815 $name::$item($( $texpr ),*)
816 }
817 }
818 ai_quick_error!(FIND_CONTEXT_IMPL
819 $name $item: TUPLE [$( $var:$typ ),*]
820 { $($tail)* });
821 };
822 (FIND_CONTEXT_IMPL $name:ident $item:ident: TUPLE
823 [$( $var:ident: $typ:ty ),*]
824 { context($cvar:ident: $ctyp:ty, $fvar:ident: $ftyp:ty)
825 -> ($( $texpr:expr ),*) $( $tail:tt )* }
826 ) => {
827 impl<'a> From<$crate::Context<$ctyp, $ftyp>> for $name {
828 fn from(
829 $crate::Context($cvar, $fvar): $crate::Context<$ctyp, $ftyp>)
830 -> $name
831 {
832 $name::$item($( $texpr ),*)
833 }
834 }
835 ai_quick_error!(FIND_CONTEXT_IMPL
836 $name $item: TUPLE [$( $var:$typ ),*]
837 { $($tail)* });
838 };
839 (FIND_CONTEXT_IMPL $name:ident $item:ident: STRUCT
840 [$( $var:ident: $typ:ty ),*]
841 { context($cvar:ident: AsRef<$ctyp:ty>, $fvar:ident: $ftyp:ty)
842 -> {$( $tvar:ident: $texpr:expr ),*} $( $tail:tt )* }
843 ) => {
844 impl<T: AsRef<$ctyp>> From<$crate::Context<T, $ftyp>> for $name {
845 fn from(
846 $crate::Context($cvar, $fvar): $crate::Context<$ctyp, $ftyp>)
847 -> $name
848 {
849 $name::$item {
850 $( $tvar: $texpr ),*
851 }
852 }
853 }
854 ai_quick_error!(FIND_CONTEXT_IMPL
855 $name $item: STRUCT [$( $var:$typ ),*]
856 { $($tail)* });
857 };
858 (FIND_CONTEXT_IMPL $name:ident $item:ident: STRUCT
859 [$( $var:ident: $typ:ty ),*]
860 { context($cvar:ident: $ctyp:ty, $fvar:ident: $ftyp:ty)
861 -> {$( $tvar:ident: $texpr:expr ),*} $( $tail:tt )* }
862 ) => {
863 impl<'a> From<$crate::Context<$ctyp, $ftyp>> for $name {
864 fn from(
865 $crate::Context($cvar, $fvar): $crate::Context<$ctyp, $ftyp>)
866 -> $name
867 {
868 $name::$item {
869 $( $tvar: $texpr ),*
870 }
871 }
872 }
873 ai_quick_error!(FIND_CONTEXT_IMPL
874 $name $item: STRUCT [$( $var:$typ ),*]
875 { $($tail)* });
876 };
877 (FIND_CONTEXT_IMPL $name:ident $item:ident: $imode:tt
878 [$( $var:ident: $typ:ty ),*]
879 { $t:tt $( $tail:tt )*}
880 ) => {
881 ai_quick_error!(FIND_CONTEXT_IMPL
882 $name $item: $imode [$( $var:$typ ),*]
883 {$( $tail )*}
884 );
885 };
886 (FIND_CONTEXT_IMPL $name:ident $item:ident: $imode:tt
887 [$( $var:ident: $typ:ty ),*]
888 { }
889 ) => {
890 };
891 (ITEM_BODY $(#[$imeta:meta])* $item:ident: UNIT
893 ) => { };
894 (ITEM_BODY $(#[$imeta:meta])* $item:ident: TUPLE
895 [$( $typ:ty ),*]
896 ) => {
897 ($( $typ ),*)
898 };
899 (ITEM_BODY $(#[$imeta:meta])* $item:ident: STRUCT
900 [$( $var:ident: $typ:ty ),*]
901 ) => {
902 {$( $var:$typ ),*}
903 };
904 (ITEM_PATTERN $name:ident $item:ident: UNIT []
905 ) => {
906 $name::$item
907 };
908 (ITEM_PATTERN $name:ident $item:ident: TUPLE
909 [$( ref $var:ident ),*]
910 ) => {
911 $name::$item ($( ref $var ),*)
912 };
913 (ITEM_PATTERN $name:ident $item:ident: STRUCT
914 [$( ref $var:ident ),*]
915 ) => {
916 $name::$item {$( ref $var ),*}
917 };
918 (ERROR_CHECK $imode:tt display($self_:tt) -> ($( $exprs:tt )*) $( $tail:tt )*)
923 => { ai_quick_error!(ERROR_CHECK $imode $($tail)*); };
924 (ERROR_CHECK $imode:tt display($pattern: expr) $( $tail:tt )*)
925 => { ai_quick_error!(ERROR_CHECK $imode $($tail)*); };
926 (ERROR_CHECK $imode:tt display($pattern: expr, $( $exprs:tt )*) $( $tail:tt )*)
927 => { ai_quick_error!(ERROR_CHECK $imode $($tail)*); };
928 (ERROR_CHECK $imode:tt source($expr:expr) $($tail:tt)*)
929 => { ai_quick_error!(ERROR_CHECK $imode $($tail)*); };
930 (ERROR_CHECK $imode:tt from() $($tail:tt)*)
931 => { ai_quick_error!(ERROR_CHECK $imode $($tail)*); };
932 (ERROR_CHECK $imode:tt from($ftyp:ty) $($tail:tt)*)
933 => { ai_quick_error!(ERROR_CHECK $imode $($tail)*); };
934 (ERROR_CHECK TUPLE from($fvar:ident: $ftyp:ty) -> ($( $e:expr ),*) $( $tail:tt )*)
935 => { ai_quick_error!(ERROR_CHECK TUPLE $($tail)*); };
936 (ERROR_CHECK STRUCT from($fvar:ident: $ftyp:ty) -> {$( $v:ident: $e:expr ),*} $( $tail:tt )*)
937 => { ai_quick_error!(ERROR_CHECK STRUCT $($tail)*); };
938
939 (ERROR_CHECK TUPLE context($cvar:ident: $ctyp:ty, $fvar:ident: $ftyp:ty)
940 -> ($( $e:expr ),*) $( $tail:tt )*)
941 => { ai_quick_error!(ERROR_CHECK TUPLE $($tail)*); };
942 (ERROR_CHECK STRUCT context($cvar:ident: $ctyp:ty, $fvar:ident: $ftyp:ty)
943 -> {$( $v:ident: $e:expr ),*} $( $tail:tt )*)
944 => { ai_quick_error!(ERROR_CHECK STRUCT $($tail)*); };
945
946 (ERROR_CHECK $imode:tt ) => {};
947 (IDENT $ident:ident) => { $ident }
949}
950
951#[derive(Debug)]
955pub struct Context<X, E>(pub X, pub E);
956
957pub trait ResultExt<T, E> {
959 fn context<X>(self, x: X) -> Result<T, Context<X, E>>;
966}
967
968impl<T, E> ResultExt<T, E> for Result<T, E> {
969 fn context<X>(self, x: X) -> Result<T, Context<X, E>> {
970 self.map_err(|e| Context(x, e))
971 }
972}
973
974#[cfg(test)]
975mod test {
976 use std::error::Error;
977 use std::num::{ParseFloatError, ParseIntError};
978 use std::path::{Path, PathBuf};
979 use std::str::Utf8Error;
980 use std::string::FromUtf8Error;
981
982 use super::ResultExt;
983
984 ai_quick_error! {
985 #[derive(Debug)]
986 pub enum Bare {
987 One
988 Two
989 }
990 }
991
992 #[test]
993 fn bare_item_direct() {
994 assert_eq!(format!("{}", Bare::One), "One".to_string());
995 assert_eq!(format!("{:?}", Bare::One), "One".to_string());
996 assert!(Bare::One.source().is_none());
997 }
998
999 #[test]
1000 fn bare_item_trait() {
1001 let err: &dyn Error = &Bare::Two;
1002 assert_eq!(format!("{}", err), "Two".to_string());
1003 assert_eq!(format!("{:?}", err), "Two".to_string());
1004 assert!(err.source().is_none());
1005 }
1006
1007 ai_quick_error! {
1008 #[derive(Debug)]
1009 pub enum Wrapper wraps Wrapped {
1010 One
1011 Two(s: String) {
1012 display("two: {}", s)
1013 from()
1014 }
1015 }
1016 }
1017
1018 #[test]
1019 fn wrapper() {
1020 assert_eq!(
1021 format!("{}", Wrapper::from(Wrapped::One)),
1022 "One".to_string()
1023 );
1024 assert_eq!(
1025 format!("{}", Wrapper::from(Wrapped::from(String::from("hello")))),
1026 "two: hello".to_string()
1027 );
1028 assert_eq!(
1029 format!("{:?}", Wrapper::from(Wrapped::One)),
1030 "Wrapper(One)".to_string()
1031 );
1032 }
1033
1034 ai_quick_error! {
1035 #[derive(Debug, PartialEq)]
1036 pub enum TupleWrapper {
1037 ParseFloatError(err: ParseFloatError) {
1039 from()
1040 display("parse float error: {err}", err=err)
1041 source(err)
1042 }
1043 Other(descr: &'static str) {
1044 display("Error: {}", descr)
1045 }
1046 FromUtf8Error(err: Utf8Error, source: Vec<u8>) {
1048 source(err)
1049 display(me) -> ("{desc} at index {pos}: {err}", desc="utf8 error", pos=err.valid_up_to(), err=err)
1050 from(err: FromUtf8Error) -> (err.utf8_error().clone(), err.into_bytes())
1051 }
1052 Discard {
1053 from(&'static str)
1054 }
1055 Singleton {
1056 display("Just a string")
1057 }
1058 }
1059 }
1060
1061 #[test]
1062 fn tuple_wrapper_err() {
1063 let source = "one and a half times pi".parse::<f32>().unwrap_err();
1064 let err = TupleWrapper::ParseFloatError(source.clone());
1065 assert_eq!(format!("{}", err), format!("parse float error: {}", source));
1066 assert_eq!(
1067 format!("{:?}", err),
1068 format!("ParseFloatError({:?})", source)
1069 );
1070 assert_eq!(
1071 format!("{:?}", err.source().unwrap()),
1072 format!("{:?}", source)
1073 );
1074 }
1075
1076 #[test]
1077 fn tuple_wrapper_trait_str() {
1078 let desc = "hello";
1079 let err: &dyn Error = &TupleWrapper::Other(desc);
1080 assert_eq!(format!("{}", err), format!("Error: {}", desc));
1081 assert_eq!(format!("{:?}", err), format!("Other({:?})", desc));
1082 assert!(err.source().is_none());
1083 }
1084
1085 #[test]
1086 fn tuple_wrapper_trait_two_fields() {
1087 let invalid_utf8: Vec<u8> = vec![0, 159, 146, 150];
1088 let source = String::from_utf8(invalid_utf8.clone())
1089 .unwrap_err()
1090 .utf8_error();
1091 let err: &dyn Error = &TupleWrapper::FromUtf8Error(source.clone(), invalid_utf8.clone());
1092 assert_eq!(
1093 format!("{}", err),
1094 format!(
1095 "{desc} at index {pos}: {source}",
1096 desc = "utf8 error",
1097 pos = source.valid_up_to(),
1098 source = source
1099 )
1100 );
1101 assert_eq!(
1102 format!("{:?}", err),
1103 format!("FromUtf8Error({:?}, {:?})", source, invalid_utf8)
1104 );
1105 assert_eq!(
1106 format!("{:?}", err.source().unwrap()),
1107 format!("{:?}", source)
1108 );
1109 }
1110
1111 #[test]
1112 fn tuple_wrapper_from() {
1113 let source = "one and a half times pi".parse::<f32>().unwrap_err();
1114 let err = TupleWrapper::ParseFloatError(source.clone());
1115 let err_from: TupleWrapper = From::from(source);
1116 assert_eq!(err_from, err);
1117 }
1118
1119 #[test]
1120 fn tuple_wrapper_custom_from() {
1121 let invalid_utf8: Vec<u8> = vec![0, 159, 146, 150];
1122 let source = String::from_utf8(invalid_utf8.clone()).unwrap_err();
1123 let err = TupleWrapper::FromUtf8Error(source.utf8_error().clone(), invalid_utf8);
1124 let err_from: TupleWrapper = From::from(source);
1125 assert_eq!(err_from, err);
1126 }
1127
1128 #[test]
1129 fn tuple_wrapper_discard() {
1130 let err: TupleWrapper = From::from("hello");
1131 assert_eq!(format!("{}", err), format!("Discard"));
1132 assert_eq!(format!("{:?}", err), format!("Discard"));
1133 assert!(err.source().is_none());
1134 }
1135
1136 #[test]
1137 fn tuple_wrapper_singleton() {
1138 let err: TupleWrapper = TupleWrapper::Singleton;
1139 assert_eq!(format!("{}", err), format!("Just a string"));
1140 assert_eq!(format!("{:?}", err), format!("Singleton"));
1141 assert!(err.source().is_none());
1142 }
1143
1144 ai_quick_error! {
1145 #[derive(Debug, PartialEq)]
1146 pub enum StructWrapper {
1147 Utf8Error{ err: Utf8Error, hint: Option<&'static str> } {
1149 source(err)
1150 display(me) -> ("{desc} at index {pos}: {err}", desc="utf8 error", pos=err.valid_up_to(), err=err)
1151 from(err: Utf8Error) -> { err: err, hint: None }
1152 }
1153 ExcessComma { descr: &'static str, } {
1155 display("Error: {}", descr)
1156 }
1157 }
1158 }
1159
1160 #[test]
1161 fn struct_wrapper_err() {
1162 let invalid_utf8: Vec<u8> = vec![0, 159, 146, 150];
1163 let source = String::from_utf8(invalid_utf8.clone())
1164 .unwrap_err()
1165 .utf8_error();
1166 let err: &dyn Error = &StructWrapper::Utf8Error {
1167 err: source.clone(),
1168 hint: Some("nonsense"),
1169 };
1170 assert_eq!(
1171 format!("{}", err),
1172 format!(
1173 "{desc} at index {pos}: {source}",
1174 desc = "utf8 error",
1175 pos = source.valid_up_to(),
1176 source = source
1177 )
1178 );
1179 assert_eq!(
1180 format!("{:?}", err),
1181 format!(
1182 "Utf8Error {{ err: {:?}, hint: {:?} }}",
1183 source,
1184 Some("nonsense")
1185 )
1186 );
1187 assert_eq!(
1188 format!("{:?}", err.source().unwrap()),
1189 format!("{:?}", source)
1190 );
1191 }
1192
1193 #[test]
1194 fn struct_wrapper_struct_from() {
1195 let invalid_utf8: Vec<u8> = vec![0, 159, 146, 150];
1196 let source = String::from_utf8(invalid_utf8.clone())
1197 .unwrap_err()
1198 .utf8_error();
1199 let err = StructWrapper::Utf8Error {
1200 err: source.clone(),
1201 hint: None,
1202 };
1203 let err_from: StructWrapper = From::from(source);
1204 assert_eq!(err_from, err);
1205 }
1206
1207 #[test]
1208 fn struct_wrapper_excess_comma() {
1209 let descr = "hello";
1210 let err = StructWrapper::ExcessComma { descr: descr };
1211 assert_eq!(format!("{}", err), format!("Error: {}", descr));
1212 assert_eq!(
1213 format!("{:?}", err),
1214 format!("ExcessComma {{ descr: {:?} }}", descr)
1215 );
1216 assert!(err.source().is_none());
1217 }
1218
1219 ai_quick_error! {
1220 #[derive(Debug)]
1221 pub enum ContextErr {
1222 Float(src: String, err: ParseFloatError) {
1223 context(s: &'a str, e: ParseFloatError) -> (s.to_string(), e)
1224 display("Float error {:?}: {}", src, err)
1225 }
1226 Int { src: String, err: ParseIntError } {
1227 context(s: &'a str, e: ParseIntError)
1228 -> {src: s.to_string(), err: e}
1229 display("Int error {:?}: {}", src, err)
1230 }
1231 Utf8(path: PathBuf, err: Utf8Error) {
1232 context(p: AsRef<Path>, e: Utf8Error)
1233 -> (p.as_ref().to_path_buf(), e)
1234 display("Path error at {:?}: {}", path, err)
1235 }
1236 Utf8Str(s: String, err: ::std::io::Error) {
1237 context(s: AsRef<str>, e: ::std::io::Error)
1238 -> (s.as_ref().to_string(), e)
1239 display("Str error {:?}: {}", s, err)
1240 }
1241 }
1242 }
1243
1244 #[test]
1245 fn parse_float_error() {
1246 fn parse_float(s: &str) -> Result<f32, ContextErr> {
1247 Ok(s.parse().context(s)?)
1248 }
1249 assert_eq!(
1250 format!("{}", parse_float("12ab").unwrap_err()),
1251 r#"Float error "12ab": invalid float literal"#
1252 );
1253 }
1254
1255 #[test]
1256 fn parse_int_error() {
1257 fn parse_int(s: &str) -> Result<i32, ContextErr> {
1258 Ok(s.parse().context(s)?)
1259 }
1260 assert_eq!(
1261 format!("{}", parse_int("12.5").unwrap_err()),
1262 r#"Int error "12.5": invalid digit found in string"#
1263 );
1264 }
1265
1266 #[test]
1267 fn debug_context() {
1268 fn parse_int(s: &str) -> i32 {
1269 s.parse().context(s).unwrap()
1270 }
1271 assert_eq!(parse_int("12"), 12);
1272 assert_eq!(
1273 format!("{:?}", "x".parse::<i32>().context("x")),
1274 r#"Err(Context("x", ParseIntError { kind: InvalidDigit }))"#
1275 );
1276 }
1277
1278 #[test]
1279 fn path_context() {
1280 fn parse_utf<P: AsRef<Path>>(s: &[u8], p: P) -> Result<(), ContextErr> {
1281 ::std::str::from_utf8(s).context(p)?;
1282 Ok(())
1283 }
1284 let etext = parse_utf(b"a\x80\x80", "/etc").unwrap_err().to_string();
1285 assert!(etext.starts_with("Path error at \"/etc\": invalid utf-8"));
1286 let etext = parse_utf(b"\x80\x80", PathBuf::from("/tmp"))
1287 .unwrap_err()
1288 .to_string();
1289 assert!(etext.starts_with("Path error at \"/tmp\": invalid utf-8"));
1290 }
1291
1292 #[test]
1293 fn conditional_compilation() {
1294 ai_quick_error! {
1295 #[allow(dead_code)]
1296 #[derive(Debug)]
1297 pub enum Test {
1298 #[cfg(feature = "foo")]
1299 Variant
1300 }
1301 }
1302 }
1303
1304 #[test]
1305 #[allow(deprecated)]
1306 fn cause_struct_wrapper_err() {
1307 let invalid_utf8: Vec<u8> = vec![0, 159, 146, 150];
1308 let cause = String::from_utf8(invalid_utf8.clone())
1309 .unwrap_err()
1310 .utf8_error();
1311 let err: &dyn Error = &StructWrapper::Utf8Error {
1312 err: cause.clone(),
1313 hint: Some("nonsense"),
1314 };
1315 assert_eq!(
1316 format!("{}", err),
1317 format!(
1318 "{desc} at index {pos}: {cause}",
1319 desc = "utf8 error",
1320 pos = cause.valid_up_to(),
1321 cause = cause
1322 )
1323 );
1324 assert_eq!(
1325 format!("{:?}", err),
1326 format!(
1327 "Utf8Error {{ err: {:?}, hint: {:?} }}",
1328 cause,
1329 Some("nonsense")
1330 )
1331 );
1332 assert_eq!(
1333 format!("{:?}", err.cause().unwrap()),
1334 format!("{:?}", cause)
1335 );
1336 }
1337}