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