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