error_chain/
impl_error_chain_kind.rs

1/// From https://github.com/tailhook/quick-error
2/// Changes:
3///   - replace `impl Error` by `impl Item::description`
4///   - $imeta
5
6/// Because of the `#[macro_export(local_inner_macros)]` usage on `impl_error_chain_kind` that macro
7/// will only look inside this crate for macros to invoke. So using `stringify` or `write` from
8/// the standard library will fail. Thus we here create simple wrappers for them that are not
9/// exported as `local_inner_macros`, and thus they can in turn use the standard library macros.
10#[macro_export]
11macro_rules! stringify_internal {
12    ($($t:tt)*) => { stringify!($($t)*) }
13}
14
15/// Macro used interally for output expanding an expression
16#[macro_export]
17macro_rules! write_internal {
18    ($dst:expr, $($arg:tt)*) => (write!($dst, $($arg)*))
19}
20
21#[macro_export(local_inner_macros)]
22#[doc(hidden)]
23macro_rules! impl_error_chain_kind {
24    (   $(#[$meta:meta])*
25        pub enum $name:ident { $($chunks:tt)* }
26    ) => {
27        impl_error_chain_kind!(SORT [pub enum $name $(#[$meta])* ]
28            items [] buf []
29            queue [ $($chunks)* ]);
30    };
31    // Queue is empty, can do the work
32    (SORT [pub enum $name:ident $( #[$meta:meta] )*]
33        items [$($( #[$imeta:meta] )*
34                  => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
35                                {$( $ifuncs:tt )*} )* ]
36        buf [ ]
37        queue [ ]
38    ) => {
39        impl_error_chain_kind!(ENUM_DEFINITION [pub enum $name $( #[$meta] )*]
40            body []
41            queue [$($( #[$imeta] )*
42                      => $iitem: $imode [$( $ivar: $ityp ),*] )*]
43        );
44        impl_error_chain_kind!(IMPLEMENTATIONS $name {$(
45           $iitem: $imode [$(#[$imeta])*] [$( $ivar: $ityp ),*] {$( $ifuncs )*}
46           )*});
47        $(
48            impl_error_chain_kind!(ERROR_CHECK $imode $($ifuncs)*);
49        )*
50    };
51    // Add meta to buffer
52    (SORT [$( $def:tt )*]
53        items [$($( #[$imeta:meta] )*
54                  => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
55                                {$( $ifuncs:tt )*} )* ]
56        buf [$( #[$bmeta:meta] )*]
57        queue [ #[$qmeta:meta] $( $tail:tt )*]
58    ) => {
59        impl_error_chain_kind!(SORT [$( $def )*]
60            items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
61            buf [$( #[$bmeta] )* #[$qmeta] ]
62            queue [$( $tail )*]);
63    };
64    // Add ident to buffer
65    (SORT [$( $def:tt )*]
66        items [$($( #[$imeta:meta] )*
67                  => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
68                                {$( $ifuncs:tt )*} )* ]
69        buf [$( #[$bmeta:meta] )*]
70        queue [ $qitem:ident $( $tail:tt )*]
71    ) => {
72        impl_error_chain_kind!(SORT [$( $def )*]
73            items [$( $(#[$imeta])*
74                      => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
75            buf [$(#[$bmeta])* => $qitem : UNIT [ ] ]
76            queue [$( $tail )*]);
77    };
78    // Flush buffer on meta after ident
79    (SORT [$( $def:tt )*]
80        items [$($( #[$imeta:meta] )*
81                  => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
82                                {$( $ifuncs:tt )*} )* ]
83        buf [$( #[$bmeta:meta] )*
84            => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ]
85        queue [ #[$qmeta:meta] $( $tail:tt )*]
86    ) => {
87        impl_error_chain_kind!(SORT [$( $def )*]
88            enum [$(#[$bmeta])* => $bitem: $bmode $(( $($btyp),* ))*]
89            items [$($( #[$imeta:meta] )*
90                      => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*
91                     $bitem: $bmode [$( $bvar:$btyp ),*] {} ]
92            buf [ #[$qmeta] ]
93            queue [$( $tail )*]);
94    };
95    // Add tuple enum-variant
96    (SORT [$( $def:tt )*]
97        items [$($( #[$imeta:meta] )*
98                  => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
99                                {$( $ifuncs:tt )*} )* ]
100        buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ]
101        queue [($( $qvar:ident: $qtyp:ty ),+) $( $tail:tt )*]
102    ) => {
103        impl_error_chain_kind!(SORT [$( $def )*]
104            items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
105            buf [$( #[$bmeta] )* => $bitem: TUPLE [$( $qvar:$qtyp ),+] ]
106            queue [$( $tail )*]
107        );
108    };
109    // Add struct enum-variant - e.g. { descr: &'static str }
110    (SORT [$( $def:tt )*]
111        items [$($( #[$imeta:meta] )*
112                  => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
113                                {$( $ifuncs:tt )*} )* ]
114        buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ]
115        queue [{ $( $qvar:ident: $qtyp:ty ),+} $( $tail:tt )*]
116    ) => {
117        impl_error_chain_kind!(SORT [$( $def )*]
118            items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
119            buf [$( #[$bmeta] )* => $bitem: STRUCT [$( $qvar:$qtyp ),+] ]
120            queue [$( $tail )*]);
121    };
122    // Add struct enum-variant, with excess comma - e.g. { descr: &'static str, }
123    (SORT [$( $def:tt )*]
124        items [$($( #[$imeta:meta] )*
125                  => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
126                                {$( $ifuncs:tt )*} )* ]
127        buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ]
128        queue [{$( $qvar:ident: $qtyp:ty ),+ ,} $( $tail:tt )*]
129    ) => {
130        impl_error_chain_kind!(SORT [$( $def )*]
131            items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
132            buf [$( #[$bmeta] )* => $bitem: STRUCT [$( $qvar:$qtyp ),+] ]
133            queue [$( $tail )*]);
134    };
135    // Add braces and flush always on braces
136    (SORT [$( $def:tt )*]
137        items [$($( #[$imeta:meta] )*
138                  => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
139                                {$( $ifuncs:tt )*} )* ]
140        buf [$( #[$bmeta:meta] )*
141                 => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ]
142        queue [ {$( $qfuncs:tt )*} $( $tail:tt )*]
143    ) => {
144        impl_error_chain_kind!(SORT [$( $def )*]
145            items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*
146                      $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {$( $qfuncs )*} ]
147            buf [ ]
148            queue [$( $tail )*]);
149    };
150    // Flush buffer on double ident
151    (SORT [$( $def:tt )*]
152        items [$($( #[$imeta:meta] )*
153                  => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
154                                {$( $ifuncs:tt )*} )* ]
155        buf [$( #[$bmeta:meta] )*
156                 => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ]
157        queue [ $qitem:ident $( $tail:tt )*]
158    ) => {
159        impl_error_chain_kind!(SORT [$( $def )*]
160            items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*
161                     $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {} ]
162            buf [ => $qitem : UNIT [ ] ]
163            queue [$( $tail )*]);
164    };
165    // Flush buffer on end
166    (SORT [$( $def:tt )*]
167        items [$($( #[$imeta:meta] )*
168                  => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
169                                {$( $ifuncs:tt )*} )* ]
170        buf [$( #[$bmeta:meta] )*
171            => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ]
172        queue [ ]
173    ) => {
174        impl_error_chain_kind!(SORT [$( $def )*]
175            items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*
176                     $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {} ]
177            buf [ ]
178            queue [ ]);
179    };
180    // Public enum (Queue Empty)
181    (ENUM_DEFINITION [pub enum $name:ident $( #[$meta:meta] )*]
182        body [$($( #[$imeta:meta] )*
183            => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ]
184        queue [ ]
185    ) => {
186        $(#[$meta])*
187        pub enum $name {
188            $(
189                $(#[$imeta])*
190                $iitem $(($( $ttyp ),+))* $({$( $svar: $styp ),*})*,
191            )*
192
193            #[doc(hidden)]
194            __Nonexhaustive {}
195        }
196    };
197    // Unit variant
198    (ENUM_DEFINITION [$( $def:tt )*]
199        body [$($( #[$imeta:meta] )*
200            => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ]
201        queue [$( #[$qmeta:meta] )*
202            => $qitem:ident: UNIT [ ] $( $queue:tt )*]
203    ) => {
204        impl_error_chain_kind!(ENUM_DEFINITION [ $($def)* ]
205            body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )*
206                    $( #[$qmeta] )* => $qitem () {} ]
207            queue [ $($queue)* ]
208        );
209    };
210    // Tuple variant
211    (ENUM_DEFINITION [$( $def:tt )*]
212        body [$($( #[$imeta:meta] )*
213            => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ]
214        queue [$( #[$qmeta:meta] )*
215            => $qitem:ident: TUPLE [$( $qvar:ident: $qtyp:ty ),+] $( $queue:tt )*]
216    ) => {
217        impl_error_chain_kind!(ENUM_DEFINITION [ $($def)* ]
218            body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )*
219                    $( #[$qmeta] )* => $qitem (($( $qtyp ),+)) {} ]
220            queue [ $($queue)* ]
221        );
222    };
223    // Struct variant
224    (ENUM_DEFINITION [$( $def:tt )*]
225        body [$($( #[$imeta:meta] )*
226            => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ]
227        queue [$( #[$qmeta:meta] )*
228            => $qitem:ident: STRUCT [$( $qvar:ident: $qtyp:ty ),*] $( $queue:tt )*]
229    ) => {
230        impl_error_chain_kind!(ENUM_DEFINITION [ $($def)* ]
231            body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )*
232                    $( #[$qmeta] )* => $qitem () {{$( $qvar: $qtyp ),*}} ]
233            queue [ $($queue)* ]
234        );
235    };
236    (IMPLEMENTATIONS
237        $name:ident {$(
238            $item:ident: $imode:tt [$(#[$imeta:meta])*] [$( $var:ident: $typ:ty ),*] {$( $funcs:tt )*}
239        )*}
240    ) => {
241        #[allow(unknown_lints, unused, renamed_and_removed_lints)]
242        #[allow(unused_doc_comment, unused_doc_comments)]
243        impl ::std::fmt::Display for $name {
244            fn fmt(&self, fmt: &mut ::std::fmt::Formatter)
245                -> ::std::fmt::Result
246            {
247                match *self {
248                    $(
249                        $(#[$imeta])*
250                        impl_error_chain_kind!(ITEM_PATTERN
251                            $name $item: $imode [$( ref $var ),*]
252                        ) => {
253                            let display_fn = impl_error_chain_kind!(FIND_DISPLAY_IMPL
254                                $name $item: $imode
255                                {$( $funcs )*});
256
257                            display_fn(self, fmt)
258                        }
259                    )*
260
261                    _ => Ok(())
262                }
263            }
264        }
265        #[allow(unknown_lints, unused, renamed_and_removed_lints)]
266        #[allow(unused_doc_comment, unused_doc_comments)]
267        impl $name {
268            /// A string describing the error kind.
269            pub fn description(&self) -> &str {
270                match *self {
271                    $(
272                        $(#[$imeta])*
273                        impl_error_chain_kind!(ITEM_PATTERN
274                            $name $item: $imode [$( ref $var ),*]
275                        ) => {
276                            impl_error_chain_kind!(FIND_DESCRIPTION_IMPL
277                                $item: $imode self fmt [$( $var ),*]
278                                {$( $funcs )*})
279                        }
280                    )*
281
282                    _ => "",
283                }
284            }
285        }
286    };
287    (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
288        { display($self_:tt) -> ($( $exprs:tt )*) $( $tail:tt )*}
289    ) => {
290        |impl_error_chain_kind!(IDENT $self_): &$name, f: &mut ::std::fmt::Formatter| {
291            write_internal!(f, $( $exprs )*)
292        }
293    };
294    (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
295        { display($pattern:expr) $( $tail:tt )*}
296    ) => {
297        |_, f: &mut ::std::fmt::Formatter| { write_internal!(f, $pattern) }
298    };
299    (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
300        { display($pattern:expr, $( $exprs:tt )*) $( $tail:tt )*}
301    ) => {
302        |_, f: &mut ::std::fmt::Formatter| { write_internal!(f, $pattern, $( $exprs )*) }
303    };
304    (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
305        { $t:tt $( $tail:tt )*}
306    ) => {
307        impl_error_chain_kind!(FIND_DISPLAY_IMPL
308            $name $item: $imode
309            {$( $tail )*})
310    };
311    (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
312        { }
313    ) => {
314        |self_: &$name, f: &mut ::std::fmt::Formatter| {
315            write_internal!(f, "{}", self_.description())
316        }
317    };
318    (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident
319        [$( $var:ident ),*]
320        { description($expr:expr) $( $tail:tt )*}
321    ) => {
322        $expr
323    };
324    (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident
325        [$( $var:ident ),*]
326        { $t:tt $( $tail:tt )*}
327    ) => {
328        impl_error_chain_kind!(FIND_DESCRIPTION_IMPL
329            $item: $imode $me $fmt [$( $var ),*]
330            {$( $tail )*})
331    };
332    (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident
333        [$( $var:ident ),*]
334        { }
335    ) => {
336        stringify_internal!($item)
337    };
338    (ITEM_BODY $(#[$imeta:meta])* $item:ident: UNIT
339    ) => { };
340    (ITEM_BODY $(#[$imeta:meta])* $item:ident: TUPLE
341        [$( $typ:ty ),*]
342    ) => {
343        ($( $typ ),*)
344    };
345    (ITEM_BODY $(#[$imeta:meta])* $item:ident: STRUCT
346        [$( $var:ident: $typ:ty ),*]
347    ) => {
348        {$( $var:$typ ),*}
349    };
350    (ITEM_PATTERN $name:ident $item:ident: UNIT []
351    ) => {
352        $name::$item
353    };
354    (ITEM_PATTERN $name:ident $item:ident: TUPLE
355        [$( ref $var:ident ),*]
356    ) => {
357        $name::$item ($( ref $var ),*)
358    };
359    (ITEM_PATTERN $name:ident $item:ident: STRUCT
360        [$( ref $var:ident ),*]
361    ) => {
362        $name::$item {$( ref $var ),*}
363    };
364    // This one should match all allowed sequences in "funcs" but not match
365    // anything else.
366    // This is to contrast FIND_* clauses which just find stuff they need and
367    // skip everything else completely
368    (ERROR_CHECK $imode:tt display($self_:tt) -> ($( $exprs:tt )*) $( $tail:tt )*)
369    => { impl_error_chain_kind!(ERROR_CHECK_COMMA $imode $($tail)*); };
370    (ERROR_CHECK $imode:tt display($pattern: expr) $( $tail:tt )*)
371    => { impl_error_chain_kind!(ERROR_CHECK_COMMA $imode $($tail)*); };
372    (ERROR_CHECK $imode:tt display($pattern: expr, $( $exprs:tt )*) $( $tail:tt )*)
373    => { impl_error_chain_kind!(ERROR_CHECK_COMMA $imode $($tail)*); };
374    (ERROR_CHECK $imode:tt description($expr:expr) $( $tail:tt )*)
375    => { impl_error_chain_kind!(ERROR_CHECK_COMMA $imode $($tail)*); };
376    (ERROR_CHECK $imode:tt ) => {};
377    (ERROR_CHECK_COMMA $imode:tt , $( $tail:tt )*)
378    => { impl_error_chain_kind!(ERROR_CHECK $imode $($tail)*); };
379    (ERROR_CHECK_COMMA $imode:tt $( $tail:tt )*)
380    => { impl_error_chain_kind!(ERROR_CHECK $imode $($tail)*); };
381    // Utility functions
382    (IDENT $ident:ident) => { $ident }
383}