/// From https://github.com/tailhook/quick-error /// Changes: /// - replace `impl Error` by `impl Item::description` /// - $imeta /// Because of the `#[macro_export(local_inner_macros)]` usage on `impl_error_chain_kind` that macro /// will only look inside this crate for macros to invoke. So using `stringify` or `write` from /// the standard library will fail. Thus we here create simple wrappers for them that are not /// exported as `local_inner_macros`, and thus they can in turn use the standard library macros. #[macro_export] macro_rules! stringify_internal { ($($t:tt)*) => { stringify!($($t)*) } } /// Macro used interally for output expanding an expression #[macro_export] macro_rules! write_internal { ($dst:expr, $($arg:tt)*) => (write!($dst, $($arg)*)) } #[macro_export(local_inner_macros)] #[doc(hidden)] macro_rules! impl_error_chain_kind { ( $(#[$meta:meta])* pub enum $name:ident { $($chunks:tt)* } ) => { impl_error_chain_kind!(SORT [pub enum $name $(#[$meta])* ] items [] buf [] queue [ $($chunks)* ]); }; // Queue is empty, can do the work (SORT [pub enum $name:ident $( #[$meta:meta] )*] items [$($( #[$imeta:meta] )* => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] {$( $ifuncs:tt )*} )* ] buf [ ] queue [ ] ) => { impl_error_chain_kind!(ENUM_DEFINITION [pub enum $name $( #[$meta] )*] body [] queue [$($( #[$imeta] )* => $iitem: $imode [$( $ivar: $ityp ),*] )*] ); impl_error_chain_kind!(IMPLEMENTATIONS $name {$( $iitem: $imode [$(#[$imeta])*] [$( $ivar: $ityp ),*] {$( $ifuncs )*} )*}); $( impl_error_chain_kind!(ERROR_CHECK $imode $($ifuncs)*); )* }; // Add meta to buffer (SORT [$( $def:tt )*] items [$($( #[$imeta:meta] )* => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] {$( $ifuncs:tt )*} )* ] buf [$( #[$bmeta:meta] )*] queue [ #[$qmeta:meta] $( $tail:tt )*] ) => { impl_error_chain_kind!(SORT [$( $def )*] items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] buf [$( #[$bmeta] )* #[$qmeta] ] queue [$( $tail )*]); }; // Add ident to buffer (SORT [$( $def:tt )*] items [$($( #[$imeta:meta] )* => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] {$( $ifuncs:tt )*} )* ] buf [$( #[$bmeta:meta] )*] queue [ $qitem:ident $( $tail:tt )*] ) => { impl_error_chain_kind!(SORT [$( $def )*] items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] buf [$(#[$bmeta])* => $qitem : UNIT [ ] ] queue [$( $tail )*]); }; // Flush buffer on meta after ident (SORT [$( $def:tt )*] items [$($( #[$imeta:meta] )* => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] {$( $ifuncs:tt )*} )* ] buf [$( #[$bmeta:meta] )* => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ] queue [ #[$qmeta:meta] $( $tail:tt )*] ) => { impl_error_chain_kind!(SORT [$( $def )*] enum [$(#[$bmeta])* => $bitem: $bmode $(( $($btyp),* ))*] items [$($( #[$imeta:meta] )* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )* $bitem: $bmode [$( $bvar:$btyp ),*] {} ] buf [ #[$qmeta] ] queue [$( $tail )*]); }; // Add tuple enum-variant (SORT [$( $def:tt )*] items [$($( #[$imeta:meta] )* => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] {$( $ifuncs:tt )*} )* ] buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ] queue [($( $qvar:ident: $qtyp:ty ),+) $( $tail:tt )*] ) => { impl_error_chain_kind!(SORT [$( $def )*] items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] buf [$( #[$bmeta] )* => $bitem: TUPLE [$( $qvar:$qtyp ),+] ] queue [$( $tail )*] ); }; // Add struct enum-variant - e.g. { descr: &'static str } (SORT [$( $def:tt )*] items [$($( #[$imeta:meta] )* => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] {$( $ifuncs:tt )*} )* ] buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ] queue [{ $( $qvar:ident: $qtyp:ty ),+} $( $tail:tt )*] ) => { impl_error_chain_kind!(SORT [$( $def )*] items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] buf [$( #[$bmeta] )* => $bitem: STRUCT [$( $qvar:$qtyp ),+] ] queue [$( $tail )*]); }; // Add struct enum-variant, with excess comma - e.g. { descr: &'static str, } (SORT [$( $def:tt )*] items [$($( #[$imeta:meta] )* => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] {$( $ifuncs:tt )*} )* ] buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ] queue [{$( $qvar:ident: $qtyp:ty ),+ ,} $( $tail:tt )*] ) => { impl_error_chain_kind!(SORT [$( $def )*] items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] buf [$( #[$bmeta] )* => $bitem: STRUCT [$( $qvar:$qtyp ),+] ] queue [$( $tail )*]); }; // Add braces and flush always on braces (SORT [$( $def:tt )*] items [$($( #[$imeta:meta] )* => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] {$( $ifuncs:tt )*} )* ] buf [$( #[$bmeta:meta] )* => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ] queue [ {$( $qfuncs:tt )*} $( $tail:tt )*] ) => { impl_error_chain_kind!(SORT [$( $def )*] items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )* $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {$( $qfuncs )*} ] buf [ ] queue [$( $tail )*]); }; // Flush buffer on double ident (SORT [$( $def:tt )*] items [$($( #[$imeta:meta] )* => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] {$( $ifuncs:tt )*} )* ] buf [$( #[$bmeta:meta] )* => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ] queue [ $qitem:ident $( $tail:tt )*] ) => { impl_error_chain_kind!(SORT [$( $def )*] items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )* $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {} ] buf [ => $qitem : UNIT [ ] ] queue [$( $tail )*]); }; // Flush buffer on end (SORT [$( $def:tt )*] items [$($( #[$imeta:meta] )* => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] {$( $ifuncs:tt )*} )* ] buf [$( #[$bmeta:meta] )* => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ] queue [ ] ) => { impl_error_chain_kind!(SORT [$( $def )*] items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )* $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {} ] buf [ ] queue [ ]); }; // Public enum (Queue Empty) (ENUM_DEFINITION [pub enum $name:ident $( #[$meta:meta] )*] body [$($( #[$imeta:meta] )* => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ] queue [ ] ) => { $(#[$meta])* pub enum $name { $( $(#[$imeta])* $iitem $(($( $ttyp ),+))* $({$( $svar: $styp ),*})*, )* #[doc(hidden)] __Nonexhaustive {} } }; // Unit variant (ENUM_DEFINITION [$( $def:tt )*] body [$($( #[$imeta:meta] )* => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ] queue [$( #[$qmeta:meta] )* => $qitem:ident: UNIT [ ] $( $queue:tt )*] ) => { impl_error_chain_kind!(ENUM_DEFINITION [ $($def)* ] body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )* $( #[$qmeta] )* => $qitem () {} ] queue [ $($queue)* ] ); }; // Tuple variant (ENUM_DEFINITION [$( $def:tt )*] body [$($( #[$imeta:meta] )* => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ] queue [$( #[$qmeta:meta] )* => $qitem:ident: TUPLE [$( $qvar:ident: $qtyp:ty ),+] $( $queue:tt )*] ) => { impl_error_chain_kind!(ENUM_DEFINITION [ $($def)* ] body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )* $( #[$qmeta] )* => $qitem (($( $qtyp ),+)) {} ] queue [ $($queue)* ] ); }; // Struct variant (ENUM_DEFINITION [$( $def:tt )*] body [$($( #[$imeta:meta] )* => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ] queue [$( #[$qmeta:meta] )* => $qitem:ident: STRUCT [$( $qvar:ident: $qtyp:ty ),*] $( $queue:tt )*] ) => { impl_error_chain_kind!(ENUM_DEFINITION [ $($def)* ] body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )* $( #[$qmeta] )* => $qitem () {{$( $qvar: $qtyp ),*}} ] queue [ $($queue)* ] ); }; (IMPLEMENTATIONS $name:ident {$( $item:ident: $imode:tt [$(#[$imeta:meta])*] [$( $var:ident: $typ:ty ),*] {$( $funcs:tt )*} )*} ) => { #[allow(unknown_lints, unused, renamed_and_removed_lints)] #[allow(unused_doc_comment, unused_doc_comments)] impl ::std::fmt::Display for $name { fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { match *self { $( $(#[$imeta])* impl_error_chain_kind!(ITEM_PATTERN $name $item: $imode [$( ref $var ),*] ) => { let display_fn = impl_error_chain_kind!(FIND_DISPLAY_IMPL $name $item: $imode {$( $funcs )*}); display_fn(self, fmt) } )* _ => Ok(()) } } } #[allow(unknown_lints, unused, renamed_and_removed_lints)] #[allow(unused_doc_comment, unused_doc_comments)] impl $name { /// A string describing the error kind. pub fn description(&self) -> &str { match *self { $( $(#[$imeta])* impl_error_chain_kind!(ITEM_PATTERN $name $item: $imode [$( ref $var ),*] ) => { impl_error_chain_kind!(FIND_DESCRIPTION_IMPL $item: $imode self fmt [$( $var ),*] {$( $funcs )*}) } )* _ => "", } } } }; (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt { display($self_:tt) -> ($( $exprs:tt )*) $( $tail:tt )*} ) => { |impl_error_chain_kind!(IDENT $self_): &$name, f: &mut ::std::fmt::Formatter| { write_internal!(f, $( $exprs )*) } }; (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt { display($pattern:expr) $( $tail:tt )*} ) => { |_, f: &mut ::std::fmt::Formatter| { write_internal!(f, $pattern) } }; (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt { display($pattern:expr, $( $exprs:tt )*) $( $tail:tt )*} ) => { |_, f: &mut ::std::fmt::Formatter| { write_internal!(f, $pattern, $( $exprs )*) } }; (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt { $t:tt $( $tail:tt )*} ) => { impl_error_chain_kind!(FIND_DISPLAY_IMPL $name $item: $imode {$( $tail )*}) }; (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt { } ) => { |self_: &$name, f: &mut ::std::fmt::Formatter| { write_internal!(f, "{}", self_.description()) } }; (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident [$( $var:ident ),*] { description($expr:expr) $( $tail:tt )*} ) => { $expr }; (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident [$( $var:ident ),*] { $t:tt $( $tail:tt )*} ) => { impl_error_chain_kind!(FIND_DESCRIPTION_IMPL $item: $imode $me $fmt [$( $var ),*] {$( $tail )*}) }; (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident [$( $var:ident ),*] { } ) => { stringify_internal!($item) }; (ITEM_BODY $(#[$imeta:meta])* $item:ident: UNIT ) => { }; (ITEM_BODY $(#[$imeta:meta])* $item:ident: TUPLE [$( $typ:ty ),*] ) => { ($( $typ ),*) }; (ITEM_BODY $(#[$imeta:meta])* $item:ident: STRUCT [$( $var:ident: $typ:ty ),*] ) => { {$( $var:$typ ),*} }; (ITEM_PATTERN $name:ident $item:ident: UNIT [] ) => { $name::$item }; (ITEM_PATTERN $name:ident $item:ident: TUPLE [$( ref $var:ident ),*] ) => { $name::$item ($( ref $var ),*) }; (ITEM_PATTERN $name:ident $item:ident: STRUCT [$( ref $var:ident ),*] ) => { $name::$item {$( ref $var ),*} }; // This one should match all allowed sequences in "funcs" but not match // anything else. // This is to contrast FIND_* clauses which just find stuff they need and // skip everything else completely (ERROR_CHECK $imode:tt display($self_:tt) -> ($( $exprs:tt )*) $( $tail:tt )*) => { impl_error_chain_kind!(ERROR_CHECK_COMMA $imode $($tail)*); }; (ERROR_CHECK $imode:tt display($pattern: expr) $( $tail:tt )*) => { impl_error_chain_kind!(ERROR_CHECK_COMMA $imode $($tail)*); }; (ERROR_CHECK $imode:tt display($pattern: expr, $( $exprs:tt )*) $( $tail:tt )*) => { impl_error_chain_kind!(ERROR_CHECK_COMMA $imode $($tail)*); }; (ERROR_CHECK $imode:tt description($expr:expr) $( $tail:tt )*) => { impl_error_chain_kind!(ERROR_CHECK_COMMA $imode $($tail)*); }; (ERROR_CHECK $imode:tt ) => {}; (ERROR_CHECK_COMMA $imode:tt , $( $tail:tt )*) => { impl_error_chain_kind!(ERROR_CHECK $imode $($tail)*); }; (ERROR_CHECK_COMMA $imode:tt $( $tail:tt )*) => { impl_error_chain_kind!(ERROR_CHECK $imode $($tail)*); }; // Utility functions (IDENT $ident:ident) => { $ident } }