quick_error/
lib.rs

1#![warn(missing_docs)]
2//! A macro which makes errors easy to write
3//!
4//! Minimum type is like this:
5//!
6//! ```rust
7//! #[macro_use] extern crate quick_error;
8//! # fn main() {}
9//!
10//! quick_error! {
11//!     #[derive(Debug)]
12//!     pub enum SomeError {
13//!         Variant1 {}
14//!     }
15//! }
16//! ```
17//! Both ``pub`` and non-public types may be declared, and all meta attributes
18//! (such as ``#[derive(Debug)]``) are forwarded as is. The `Debug` must be
19//! implemented (but you may do that yourself if you like). The documentation
20//! comments ``/// something`` (as well as other meta attrbiutes) on variants
21//! are allowed.
22//!
23//! # Allowed Syntax
24//!
25//! You may add arbitrary parameters to any struct variant:
26//!
27//! ```rust
28//! # #[macro_use] extern crate quick_error;
29//! # fn main() {}
30//! #
31//! quick_error! {
32//!     #[derive(Debug)]
33//!     pub enum SomeError {
34//!         /// IO Error
35//!         Io(err: std::io::Error) {}
36//!         /// Utf8 Error
37//!         Utf8(err: std::str::Utf8Error) {}
38//!     }
39//! }
40//! ```
41//!
42//! Note unlike in normal Enum declarations you declare names of fields (which
43//! are omitted from type). How they can be used is outlined below.
44//!
45//! Now you might have noticed trailing braces `{}`. They are used to define
46//! implementations. By default:
47//!
48//! * `Error::cause()` returns None (even if type wraps some value)
49//! * `Display` outputs debug representation
50//! * No `From` implementations are defined
51//!
52//! ```rust
53//! # #[macro_use] extern crate quick_error;
54//! # fn main() {}
55//! #
56//! quick_error! {
57//!     #[derive(Debug)]
58//!     pub enum SomeError {
59//!         Io(err: std::io::Error) {
60//!             display("{}", err)
61//!         }
62//!         Utf8(err: std::str::Utf8Error) {
63//!             display("utf8 error")
64//!         }
65//!     }
66//! }
67//! ```
68//!
69//! To change `cause` method to return some error, add `cause(value)`, for
70//! example:
71//!
72//! ```rust
73//! # #[macro_use] extern crate quick_error;
74//! # fn main() {}
75//! #
76//! quick_error! {
77//!     #[derive(Debug)]
78//!     pub enum SomeError {
79//!         Io(err: std::io::Error) {
80//!             cause(err)
81//!         }
82//!         Utf8(err: std::str::Utf8Error) {
83//!             display("utf8 error")
84//!         }
85//!         Other(err: Box<std::error::Error>) {
86//!             cause(&**err)
87//!         }
88//!     }
89//! }
90//! ```
91//! Note you don't need to wrap value in `Some`, its implicit. In case you want
92//! `None` returned just omit the `cause`. You can't return `None`
93//! conditionally.
94//!
95//! To change how each clause is `Display`ed add `display(pattern,..args)`,
96//! for example:
97//!
98//! ```rust
99//! # #[macro_use] extern crate quick_error;
100//! # fn main() {}
101//! #
102//! quick_error! {
103//!     #[derive(Debug)]
104//!     pub enum SomeError {
105//!         Io(err: std::io::Error) {
106//!             display("I/O error: {}", err)
107//!         }
108//!         Utf8(err: std::str::Utf8Error) {
109//!             display("Utf8 error, valid up to {}", err.valid_up_to())
110//!         }
111//!     }
112//! }
113//! ```
114//!
115//! If you need a reference to the error when `Display`ing, you can instead use
116//! `display(x) -> (pattern, ..args)`, where `x` sets the name of the reference.
117//!
118//! ```rust
119//! # #[macro_use] extern crate quick_error;
120//! # fn main() {}
121//! #
122//! use std::error::Error; // put methods like `source()` of this trait into scope
123//!
124//! quick_error! {
125//!     #[derive(Debug)]
126//!     pub enum SomeError {
127//!         Io(err: std::io::Error) {
128//!             display(x) -> ("I/O: {}", err)
129//!         }
130//!         Utf8(err: std::str::Utf8Error) {
131//!             display(self_) -> ("UTF-8 error. Valid up to {}", err.valid_up_to())
132//!         }
133//!     }
134//! }
135//! ```
136//!
137//! To convert to the type from any other, use one of the three forms of
138//! `from` clause.
139//!
140//! For example, to convert simple wrapper use bare `from()`:
141//!
142//! ```rust
143//! # #[macro_use] extern crate quick_error;
144//! # fn main() {}
145//! #
146//! quick_error! {
147//!     #[derive(Debug)]
148//!     pub enum SomeError {
149//!         Io(err: std::io::Error) {
150//!             from()
151//!         }
152//!     }
153//! }
154//! ```
155//!
156//! This implements ``From<io::Error>``.
157//!
158//! To convert to singleton enumeration type (discarding the value), use
159//! the `from(type)` form:
160//!
161//! ```rust
162//! # #[macro_use] extern crate quick_error;
163//! # fn main() {}
164//! #
165//! quick_error! {
166//!     #[derive(Debug)]
167//!     pub enum SomeError {
168//!         FormatError {
169//!             from(std::fmt::Error)
170//!         }
171//!     }
172//! }
173//! ```
174//!
175//! And the most powerful form is `from(var: type) -> (arguments...)`. It
176//! might be used to convert to type with multiple arguments or for arbitrary
177//! value conversions:
178//!
179//! ```rust
180//! # #[macro_use] extern crate quick_error;
181//! # fn main() {}
182//! #
183//! quick_error! {
184//!     #[derive(Debug)]
185//!     pub enum SomeError {
186//!         FailedOperation(s: &'static str, errno: i32) {
187//!             from(errno: i32) -> ("os error", errno)
188//!             from(e: std::io::Error) -> ("io error", e.raw_os_error().unwrap())
189//!         }
190//!         /// Converts from both kinds of utf8 errors
191//!         Utf8(err: std::str::Utf8Error) {
192//!             from()
193//!             from(err: std::string::FromUtf8Error) -> (err.utf8_error())
194//!         }
195//!     }
196//! }
197//! ```
198//! # Context
199//!
200//! Since quick-error 1.1 we also have a `context` declaration, which is
201//! similar to (the longest form of) `from`, but allows adding some context to
202//! the error. We need a longer example to demonstrate this:
203//!
204//! ```rust
205//! # #[macro_use] extern crate quick_error;
206//! # use std::io;
207//! # use std::fs::File;
208//! # use std::path::{Path, PathBuf};
209//! #
210//! use quick_error::ResultExt;
211//!
212//! quick_error! {
213//!     #[derive(Debug)]
214//!     pub enum Error {
215//!         File(filename: PathBuf, err: io::Error) {
216//!             context(path: &'a Path, err: io::Error)
217//!                 -> (path.to_path_buf(), err)
218//!         }
219//!     }
220//! }
221//!
222//! fn openfile(path: &Path) -> Result<(), Error> {
223//!     try!(File::open(path).context(path));
224//!
225//!     // If we didn't have context, the line above would be written as;
226//!     //
227//!     // try!(File::open(path)
228//!     //     .map_err(|err| Error::File(path.to_path_buf(), err)));
229//!
230//!     Ok(())
231//! }
232//!
233//! # fn main() {
234//! #     openfile(Path::new("/etc/somefile")).ok();
235//! # }
236//! ```
237//!
238//! Each `context(a: A, b: B)` clause implements
239//! `From<Context<A, B>> for Error`. Which means multiple `context` clauses
240//! are a subject to the normal coherence rules. Unfortunately, we can't
241//! provide full support of generics for the context, but you may either use a
242//! lifetime `'a` for references or `AsRef<Type>` (the latter means `A:
243//! AsRef<Type>`, and `Type` must be concrete). It's also occasionally useful
244//! to use a tuple as a type of the first argument.
245//!
246//! You also need to `use quick_error::ResultExt` extension trait to get
247//! working `.context()` method.
248//!
249//! More info on context in [this article](http://bit.ly/1PsuxDt).
250//!
251//! All forms of `from`, `display`, `cause`, and `context`
252//! clauses can be combined and put in arbitrary order. Only `from` and
253//! `context` can be used multiple times in single variant of enumeration.
254//! Docstrings are also okay.  Empty braces can be omitted as of quick_error
255//! 0.1.3.
256//!
257//! # Private Enums
258//!
259//! Since quick-error 1.2.0 we  have a way to make a private enum that is
260//! wrapped by public structure:
261//!
262//! ```rust
263//! #[macro_use] extern crate quick_error;
264//! # fn main() {}
265//!
266//! quick_error! {
267//!     #[derive(Debug)]
268//!     pub enum PubError wraps ErrorEnum {
269//!         Variant1 {}
270//!     }
271//! }
272//! ```
273//!
274//! This generates data structures like this
275//!
276//! ```rust
277//!
278//! pub struct PubError(ErrorEnum);
279//!
280//! enum ErrorEnum {
281//!     Variant1,
282//! }
283//!
284//! ```
285//!
286//! Which in turn allows you to export just `PubError` in your crate and keep
287//! actual enumeration private to the crate. This is useful to keep backwards
288//! compatibility for error types. Currently there is no shorcuts to define
289//! error constructors for the inner type, but we consider adding some in
290//! future versions.
291//!
292//! It's possible to declare internal enum as public too.
293//!
294//!
295
296
297/// Main macro that does all the work
298#[macro_export]
299macro_rules! quick_error {
300
301    (   $(#[$meta:meta])*
302        pub enum $name:ident { $($chunks:tt)* }
303    ) => {
304        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        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        quick_error!(WRAPPER $enum_name [ pub struct ] $name $(#[$meta])*);
320        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        quick_error!(WRAPPER $enum_name [ pub struct ] $name $(#[$meta])*);
329        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        quick_error!(WRAPPER $enum_name [ struct ] $name $(#[$meta])*);
337        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        quick_error!(WRAPPER $enum_name [ struct ] $name $(#[$meta])*);
346        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 ::std::fmt::Display for $strname {
360            fn fmt(&self, f: &mut ::std::fmt::Formatter)
361                -> ::std::fmt::Result
362            {
363                ::std::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 ::std::error::Error for $strname {
374            #[allow(deprecated)]
375            fn cause(&self) -> Option<&::std::error::Error> {
376                self.0.cause()
377            }
378        }
379    };
380
381    // Queue is empty, can do the work
382    (SORT [enum $name:ident $( #[$meta:meta] )*]
383        items [$($( #[$imeta:meta] )*
384                  => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
385                                {$( $ifuncs:tt )*} )* ]
386        buf [ ]
387        queue [ ]
388    ) => {
389        quick_error!(ENUM_DEFINITION [enum $name $( #[$meta] )*]
390            body []
391            queue [$($( #[$imeta] )*
392                      => $iitem: $imode [$( $ivar: $ityp ),*] )*]
393        );
394        quick_error!(IMPLEMENTATIONS $name {$(
395           $iitem: $imode [$(#[$imeta])*] [$( $ivar: $ityp ),*] {$( $ifuncs )*}
396           )*});
397        $(
398            quick_error!(ERROR_CHECK $imode $($ifuncs)*);
399        )*
400    };
401    (SORT [pub enum $name:ident $( #[$meta:meta] )*]
402        items [$($( #[$imeta:meta] )*
403                  => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
404                                {$( $ifuncs:tt )*} )* ]
405        buf [ ]
406        queue [ ]
407    ) => {
408        quick_error!(ENUM_DEFINITION [pub enum $name $( #[$meta] )*]
409            body []
410            queue [$($( #[$imeta] )*
411                      => $iitem: $imode [$( $ivar: $ityp ),*] )*]
412        );
413        quick_error!(IMPLEMENTATIONS $name {$(
414           $iitem: $imode [$(#[$imeta])*] [$( $ivar: $ityp ),*] {$( $ifuncs )*}
415           )*});
416        $(
417            quick_error!(ERROR_CHECK $imode $($ifuncs)*);
418        )*
419    };
420    // Add meta to buffer
421    (SORT [$( $def:tt )*]
422        items [$($( #[$imeta:meta] )*
423                  => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
424                                {$( $ifuncs:tt )*} )* ]
425        buf [$( #[$bmeta:meta] )*]
426        queue [ #[$qmeta:meta] $( $tail:tt )*]
427    ) => {
428        quick_error!(SORT [$( $def )*]
429            items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
430            buf [$( #[$bmeta] )* #[$qmeta] ]
431            queue [$( $tail )*]);
432    };
433    // Add ident to buffer
434    (SORT [$( $def:tt )*]
435        items [$($( #[$imeta:meta] )*
436                  => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
437                                {$( $ifuncs:tt )*} )* ]
438        buf [$( #[$bmeta:meta] )*]
439        queue [ $qitem:ident $( $tail:tt )*]
440    ) => {
441        quick_error!(SORT [$( $def )*]
442            items [$( $(#[$imeta])*
443                      => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
444            buf [$(#[$bmeta])* => $qitem : UNIT [ ] ]
445            queue [$( $tail )*]);
446    };
447    // Flush buffer on meta after ident
448    (SORT [$( $def:tt )*]
449        items [$($( #[$imeta:meta] )*
450                  => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
451                                {$( $ifuncs:tt )*} )* ]
452        buf [$( #[$bmeta:meta] )*
453            => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ]
454        queue [ #[$qmeta:meta] $( $tail:tt )*]
455    ) => {
456        quick_error!(SORT [$( $def )*]
457            enum [$( $(#[$emeta])* => $eitem $(( $($etyp),* ))* )*
458                     $(#[$bmeta])* => $bitem: $bmode $(( $($btyp),* ))*]
459            items [$($( #[$imeta:meta] )*
460                      => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*
461                     $bitem: $bmode [$( $bvar:$btyp ),*] {} ]
462            buf [ #[$qmeta] ]
463            queue [$( $tail )*]);
464    };
465    // Add tuple enum-variant
466    (SORT [$( $def:tt )*]
467        items [$($( #[$imeta:meta] )*
468                  => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
469                                {$( $ifuncs:tt )*} )* ]
470        buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ]
471        queue [($( $qvar:ident: $qtyp:ty ),+) $( $tail:tt )*]
472    ) => {
473        quick_error!(SORT [$( $def )*]
474            items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
475            buf [$( #[$bmeta] )* => $bitem: TUPLE [$( $qvar:$qtyp ),*] ]
476            queue [$( $tail )*]
477        );
478    };
479    // Add struct enum-variant - e.g. { descr: &'static str }
480    (SORT [$( $def:tt )*]
481        items [$($( #[$imeta:meta] )*
482                  => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
483                                {$( $ifuncs:tt )*} )* ]
484        buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ]
485        queue [{ $( $qvar:ident: $qtyp:ty ),+} $( $tail:tt )*]
486    ) => {
487        quick_error!(SORT [$( $def )*]
488            items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
489            buf [$( #[$bmeta] )* => $bitem: STRUCT [$( $qvar:$qtyp ),*] ]
490            queue [$( $tail )*]);
491    };
492    // Add struct enum-variant, with excess comma - e.g. { descr: &'static str, }
493    (SORT [$( $def:tt )*]
494        items [$($( #[$imeta:meta] )*
495                  => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
496                                {$( $ifuncs:tt )*} )* ]
497        buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ]
498        queue [{$( $qvar:ident: $qtyp:ty ),+ ,} $( $tail:tt )*]
499    ) => {
500        quick_error!(SORT [$( $def )*]
501            items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
502            buf [$( #[$bmeta] )* => $bitem: STRUCT [$( $qvar:$qtyp ),*] ]
503            queue [$( $tail )*]);
504    };
505    // Add braces and flush always on braces
506    (SORT [$( $def:tt )*]
507        items [$($( #[$imeta:meta] )*
508                  => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
509                                {$( $ifuncs:tt )*} )* ]
510        buf [$( #[$bmeta:meta] )*
511                 => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ]
512        queue [ {$( $qfuncs:tt )*} $( $tail:tt )*]
513    ) => {
514        quick_error!(SORT [$( $def )*]
515            items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*
516                      $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {$( $qfuncs )*} ]
517            buf [ ]
518            queue [$( $tail )*]);
519    };
520    // Flush buffer on double ident
521    (SORT [$( $def:tt )*]
522        items [$($( #[$imeta:meta] )*
523                  => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
524                                {$( $ifuncs:tt )*} )* ]
525        buf [$( #[$bmeta:meta] )*
526                 => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ]
527        queue [ $qitem:ident $( $tail:tt )*]
528    ) => {
529        quick_error!(SORT [$( $def )*]
530            items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*
531                     $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {} ]
532            buf [ => $qitem : UNIT [ ] ]
533            queue [$( $tail )*]);
534    };
535    // Flush buffer on end
536    (SORT [$( $def:tt )*]
537        items [$($( #[$imeta:meta] )*
538                  => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
539                                {$( $ifuncs:tt )*} )* ]
540        buf [$( #[$bmeta:meta] )*
541            => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ]
542        queue [ ]
543    ) => {
544        quick_error!(SORT [$( $def )*]
545            items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*
546                     $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {} ]
547            buf [ ]
548            queue [ ]);
549    };
550    // Public enum (Queue Empty)
551    (ENUM_DEFINITION [pub enum $name:ident $( #[$meta:meta] )*]
552        body [$($( #[$imeta:meta] )*
553            => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ]
554        queue [ ]
555    ) => {
556        #[allow(unknown_lints)]  // no unused_doc_comments in older rust
557        #[allow(renamed_and_removed_lints)]
558        #[allow(unused_doc_comment)]
559        #[allow(unused_doc_comments)]
560        $(#[$meta])*
561        pub enum $name {
562            $(
563                $(#[$imeta])*
564                $iitem $(($( $ttyp ),*))* $({$( $svar: $styp ),*})*,
565            )*
566        }
567    };
568    // Private enum (Queue Empty)
569    (ENUM_DEFINITION [enum $name:ident $( #[$meta:meta] )*]
570        body [$($( #[$imeta:meta] )*
571            => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ]
572        queue [ ]
573    ) => {
574        #[allow(unknown_lints)]  // no unused_doc_comments in older rust
575        #[allow(renamed_and_removed_lints)]
576        #[allow(unused_doc_comment)]
577        #[allow(unused_doc_comments)]
578        $(#[$meta])*
579        enum $name {
580            $(
581                $(#[$imeta])*
582                $iitem $(($( $ttyp ),*))* $({$( $svar: $styp ),*})*,
583            )*
584        }
585    };
586    // Unit variant
587    (ENUM_DEFINITION [$( $def:tt )*]
588        body [$($( #[$imeta:meta] )*
589            => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ]
590        queue [$( #[$qmeta:meta] )*
591            => $qitem:ident: UNIT [ ] $( $queue:tt )*]
592    ) => {
593        quick_error!(ENUM_DEFINITION [ $($def)* ]
594            body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )*
595                    $( #[$qmeta] )* => $qitem () {} ]
596            queue [ $($queue)* ]
597        );
598    };
599    // Tuple variant
600    (ENUM_DEFINITION [$( $def:tt )*]
601        body [$($( #[$imeta:meta] )*
602            => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ]
603        queue [$( #[$qmeta:meta] )*
604            => $qitem:ident: TUPLE [$( $qvar:ident: $qtyp:ty ),+] $( $queue:tt )*]
605    ) => {
606        quick_error!(ENUM_DEFINITION [ $($def)* ]
607            body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )*
608                    $( #[$qmeta] )* => $qitem (($( $qtyp ),*)) {} ]
609            queue [ $($queue)* ]
610        );
611    };
612    // Struct variant
613    (ENUM_DEFINITION [$( $def:tt )*]
614        body [$($( #[$imeta:meta] )*
615            => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ]
616        queue [$( #[$qmeta:meta] )*
617            => $qitem:ident: STRUCT [$( $qvar:ident: $qtyp:ty ),*] $( $queue:tt )*]
618    ) => {
619        quick_error!(ENUM_DEFINITION [ $($def)* ]
620            body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )*
621                    $( #[$qmeta] )* => $qitem () {{$( $qvar: $qtyp ),*}} ]
622            queue [ $($queue)* ]
623        );
624    };
625    (IMPLEMENTATIONS
626        $name:ident {$(
627            $item:ident: $imode:tt [$(#[$imeta:meta])*] [$( $var:ident: $typ:ty ),*] {$( $funcs:tt )*}
628        )*}
629    ) => {
630        #[allow(unused)]
631        #[allow(unknown_lints)]  // no unused_doc_comments in older rust
632        #[allow(renamed_and_removed_lints)]
633        #[allow(unused_doc_comment)]
634        #[allow(unused_doc_comments)]
635        impl ::std::fmt::Display for $name {
636            fn fmt(&self, fmt: &mut ::std::fmt::Formatter)
637                -> ::std::fmt::Result
638            {
639                match *self {
640                    $(
641                        $(#[$imeta])*
642                        quick_error!(ITEM_PATTERN
643                            $name $item: $imode [$( ref $var ),*]
644                        ) => {
645                            let display_fn = quick_error!(FIND_DISPLAY_IMPL
646                                $name $item: $imode
647                                {$( $funcs )*});
648
649                            display_fn(self, fmt)
650                        }
651                    )*
652                }
653            }
654        }
655        #[allow(unused)]
656        #[allow(unknown_lints)]  // no unused_doc_comments in older rust
657        #[allow(renamed_and_removed_lints)]
658        #[allow(unused_doc_comment)]
659        #[allow(unused_doc_comments)]
660        impl ::std::error::Error for $name {
661            fn cause(&self) -> Option<&::std::error::Error> {
662                match *self {
663                    $(
664                        $(#[$imeta])*
665                        quick_error!(ITEM_PATTERN
666                            $name $item: $imode [$( ref $var ),*]
667                        ) => {
668                            quick_error!(FIND_CAUSE_IMPL
669                                $item: $imode [$( $var ),*]
670                                {$( $funcs )*})
671                        }
672                    )*
673                }
674            }
675        }
676        $(
677            quick_error!(FIND_FROM_IMPL
678                $name $item: $imode [$( $var:$typ ),*]
679                {$( $funcs )*});
680        )*
681        $(
682            quick_error!(FIND_CONTEXT_IMPL
683                $name $item: $imode [$( $var:$typ ),*]
684                {$( $funcs )*});
685        )*
686    };
687    (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
688        { display($self_:tt) -> ($( $exprs:tt )*) $( $tail:tt )*}
689    ) => {
690        |quick_error!(IDENT $self_): &$name, f: &mut ::std::fmt::Formatter| { write!(f, $( $exprs )*) }
691    };
692    (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
693        { display($pattern:expr) $( $tail:tt )*}
694    ) => {
695        |_, f: &mut ::std::fmt::Formatter| { write!(f, $pattern) }
696    };
697    (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
698        { display($pattern:expr, $( $exprs:tt )*) $( $tail:tt )*}
699    ) => {
700        |_, f: &mut ::std::fmt::Formatter| { write!(f, $pattern, $( $exprs )*) }
701    };
702    (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
703        { $t:tt $( $tail:tt )*}
704    ) => {
705        quick_error!(FIND_DISPLAY_IMPL
706            $name $item: $imode
707            {$( $tail )*})
708    };
709    (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
710        { }
711    ) => {
712        |self_: &$name, f: &mut ::std::fmt::Formatter| {
713            write!(f, "{:?}", self_)
714        }
715    };
716    (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident
717        [$( $var:ident ),*]
718        { description($expr:expr) $( $tail:tt )*}
719    ) => {};
720    (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident
721        [$( $var:ident ),*]
722        { $t:tt $( $tail:tt )*}
723    ) => {};
724    (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident
725        [$( $var:ident ),*]
726        { }
727    ) => {};
728    (FIND_CAUSE_IMPL $item:ident: $imode:tt
729        [$( $var:ident ),*]
730        { cause($expr:expr) $( $tail:tt )*}
731    ) => {
732        Some($expr)
733    };
734    (FIND_CAUSE_IMPL $item:ident: $imode:tt
735        [$( $var:ident ),*]
736        { $t:tt $( $tail:tt )*}
737    ) => {
738        quick_error!(FIND_CAUSE_IMPL
739            $item: $imode [$( $var ),*]
740            { $($tail)* })
741    };
742    (FIND_CAUSE_IMPL $item:ident: $imode:tt
743        [$( $var:ident ),*]
744        { }
745    ) => {
746        None
747    };
748    // ----------------------------- FROM IMPL --------------------------
749    (FIND_FROM_IMPL $name:ident $item:ident: $imode:tt
750        [$( $var:ident: $typ:ty ),*]
751        { from() $( $tail:tt )*}
752    ) => {
753        $(
754            impl From<$typ> for $name {
755                fn from($var: $typ) -> $name {
756                    $name::$item($var)
757                }
758            }
759        )*
760        quick_error!(FIND_FROM_IMPL
761            $name $item: $imode [$( $var:$typ ),*]
762            {$( $tail )*});
763    };
764    (FIND_FROM_IMPL $name:ident $item:ident: UNIT
765        [ ]
766        { from($ftyp:ty) $( $tail:tt )*}
767    ) => {
768        impl From<$ftyp> for $name {
769            fn from(_discarded_error: $ftyp) -> $name {
770                $name::$item
771            }
772        }
773        quick_error!(FIND_FROM_IMPL
774            $name $item: UNIT [  ]
775            {$( $tail )*});
776    };
777    (FIND_FROM_IMPL $name:ident $item:ident: TUPLE
778        [$( $var:ident: $typ:ty ),*]
779        { from($fvar:ident: $ftyp:ty) -> ($( $texpr:expr ),*) $( $tail:tt )*}
780    ) => {
781        impl From<$ftyp> for $name {
782            fn from($fvar: $ftyp) -> $name {
783                $name::$item($( $texpr ),*)
784            }
785        }
786        quick_error!(FIND_FROM_IMPL
787            $name $item: TUPLE [$( $var:$typ ),*]
788            { $($tail)* });
789    };
790    (FIND_FROM_IMPL $name:ident $item:ident: STRUCT
791        [$( $var:ident: $typ:ty ),*]
792        { from($fvar:ident: $ftyp:ty) -> {$( $tvar:ident: $texpr:expr ),*} $( $tail:tt )*}
793    ) => {
794        impl From<$ftyp> for $name {
795            fn from($fvar: $ftyp) -> $name {
796                $name::$item {
797                    $( $tvar: $texpr ),*
798                }
799            }
800        }
801        quick_error!(FIND_FROM_IMPL
802            $name $item: STRUCT [$( $var:$typ ),*]
803            { $($tail)* });
804    };
805    (FIND_FROM_IMPL $name:ident $item:ident: $imode:tt
806        [$( $var:ident: $typ:ty ),*]
807        { $t:tt $( $tail:tt )*}
808    ) => {
809        quick_error!(FIND_FROM_IMPL
810            $name $item: $imode [$( $var:$typ ),*]
811            {$( $tail )*}
812        );
813    };
814    (FIND_FROM_IMPL $name:ident $item:ident: $imode:tt
815        [$( $var:ident: $typ:ty ),*]
816        { }
817    ) => {
818    };
819    // ----------------------------- CONTEXT IMPL --------------------------
820    (FIND_CONTEXT_IMPL $name:ident $item:ident: TUPLE
821        [$( $var:ident: $typ:ty ),*]
822        { context($cvar:ident: AsRef<$ctyp:ty>, $fvar:ident: $ftyp:ty)
823            -> ($( $texpr:expr ),*) $( $tail:tt )* }
824    ) => {
825        impl<T: AsRef<$ctyp>> From<$crate::Context<T, $ftyp>> for $name {
826            fn from(
827                $crate::Context($cvar, $fvar): $crate::Context<T, $ftyp>)
828                -> $name
829            {
830                $name::$item($( $texpr ),*)
831            }
832        }
833        quick_error!(FIND_CONTEXT_IMPL
834            $name $item: TUPLE [$( $var:$typ ),*]
835            { $($tail)* });
836    };
837    (FIND_CONTEXT_IMPL $name:ident $item:ident: TUPLE
838        [$( $var:ident: $typ:ty ),*]
839        { context($cvar:ident: $ctyp:ty, $fvar:ident: $ftyp:ty)
840            -> ($( $texpr:expr ),*) $( $tail:tt )* }
841    ) => {
842        impl<'a> From<$crate::Context<$ctyp, $ftyp>> for $name {
843            fn from(
844                $crate::Context($cvar, $fvar): $crate::Context<$ctyp, $ftyp>)
845                -> $name
846            {
847                $name::$item($( $texpr ),*)
848            }
849        }
850        quick_error!(FIND_CONTEXT_IMPL
851            $name $item: TUPLE [$( $var:$typ ),*]
852            { $($tail)* });
853    };
854    (FIND_CONTEXT_IMPL $name:ident $item:ident: STRUCT
855        [$( $var:ident: $typ:ty ),*]
856        { context($cvar:ident: AsRef<$ctyp:ty>, $fvar:ident: $ftyp:ty)
857            -> {$( $tvar:ident: $texpr:expr ),*} $( $tail:tt )* }
858    ) => {
859        impl<T: AsRef<$ctyp>> From<$crate::Context<T, $ftyp>> for $name {
860            fn from(
861                $crate::Context($cvar, $fvar): $crate::Context<$ctyp, $ftyp>)
862                -> $name
863            {
864                $name::$item {
865                    $( $tvar: $texpr ),*
866                }
867            }
868        }
869        quick_error!(FIND_CONTEXT_IMPL
870            $name $item: STRUCT [$( $var:$typ ),*]
871            { $($tail)* });
872    };
873    (FIND_CONTEXT_IMPL $name:ident $item:ident: STRUCT
874        [$( $var:ident: $typ:ty ),*]
875        { context($cvar:ident: $ctyp:ty, $fvar:ident: $ftyp:ty)
876            -> {$( $tvar:ident: $texpr:expr ),*} $( $tail:tt )* }
877    ) => {
878        impl<'a> From<$crate::Context<$ctyp, $ftyp>> for $name {
879            fn from(
880                $crate::Context($cvar, $fvar): $crate::Context<$ctyp, $ftyp>)
881                -> $name
882            {
883                $name::$item {
884                    $( $tvar: $texpr ),*
885                }
886            }
887        }
888        quick_error!(FIND_CONTEXT_IMPL
889            $name $item: STRUCT [$( $var:$typ ),*]
890            { $($tail)* });
891    };
892    (FIND_CONTEXT_IMPL $name:ident $item:ident: $imode:tt
893        [$( $var:ident: $typ:ty ),*]
894        { $t:tt $( $tail:tt )*}
895    ) => {
896        quick_error!(FIND_CONTEXT_IMPL
897            $name $item: $imode [$( $var:$typ ),*]
898            {$( $tail )*}
899        );
900    };
901    (FIND_CONTEXT_IMPL $name:ident $item:ident: $imode:tt
902        [$( $var:ident: $typ:ty ),*]
903        { }
904    ) => {
905    };
906    // ----------------------------- ITEM IMPL --------------------------
907    (ITEM_BODY $(#[$imeta:meta])* $item:ident: UNIT
908    ) => { };
909    (ITEM_BODY $(#[$imeta:meta])* $item:ident: TUPLE
910        [$( $typ:ty ),*]
911    ) => {
912        ($( $typ ),*)
913    };
914    (ITEM_BODY $(#[$imeta:meta])* $item:ident: STRUCT
915        [$( $var:ident: $typ:ty ),*]
916    ) => {
917        {$( $var:$typ ),*}
918    };
919    (ITEM_PATTERN $name:ident $item:ident: UNIT []
920    ) => {
921        $name::$item
922    };
923    (ITEM_PATTERN $name:ident $item:ident: TUPLE
924        [$( ref $var:ident ),*]
925    ) => {
926        $name::$item ($( ref $var ),*)
927    };
928    (ITEM_PATTERN $name:ident $item:ident: STRUCT
929        [$( ref $var:ident ),*]
930    ) => {
931        $name::$item {$( ref $var ),*}
932    };
933    // This one should match all allowed sequences in "funcs" but not match
934    // anything else.
935    // This is to contrast FIND_* clauses which just find stuff they need and
936    // skip everything else completely
937    (ERROR_CHECK $imode:tt display($self_:tt) -> ($( $exprs:tt )*) $( $tail:tt )*)
938    => { quick_error!(ERROR_CHECK $imode $($tail)*); };
939    (ERROR_CHECK $imode:tt display($pattern: expr) $( $tail:tt )*)
940    => { quick_error!(ERROR_CHECK $imode $($tail)*); };
941    (ERROR_CHECK $imode:tt display($pattern: expr, $( $exprs:tt )*) $( $tail:tt )*)
942    => { quick_error!(ERROR_CHECK $imode $($tail)*); };
943    (ERROR_CHECK $imode:tt description($expr:expr) $( $tail:tt )*)
944    => { quick_error!(ERROR_CHECK $imode $($tail)*); };
945    (ERROR_CHECK $imode:tt cause($expr:expr) $($tail:tt)*)
946    => { quick_error!(ERROR_CHECK $imode $($tail)*); };
947    (ERROR_CHECK $imode:tt from() $($tail:tt)*)
948    => { quick_error!(ERROR_CHECK $imode $($tail)*); };
949    (ERROR_CHECK $imode:tt from($ftyp:ty) $($tail:tt)*)
950    => { quick_error!(ERROR_CHECK $imode $($tail)*); };
951    (ERROR_CHECK TUPLE from($fvar:ident: $ftyp:ty) -> ($( $e:expr ),*) $( $tail:tt )*)
952    => { quick_error!(ERROR_CHECK TUPLE $($tail)*); };
953    (ERROR_CHECK STRUCT from($fvar:ident: $ftyp:ty) -> {$( $v:ident: $e:expr ),*} $( $tail:tt )*)
954    => { quick_error!(ERROR_CHECK STRUCT $($tail)*); };
955
956    (ERROR_CHECK TUPLE context($cvar:ident: $ctyp:ty, $fvar:ident: $ftyp:ty)
957        -> ($( $e:expr ),*) $( $tail:tt )*)
958    => { quick_error!(ERROR_CHECK TUPLE $($tail)*); };
959    (ERROR_CHECK STRUCT context($cvar:ident: $ctyp:ty, $fvar:ident: $ftyp:ty)
960        -> {$( $v:ident: $e:expr ),*} $( $tail:tt )*)
961    => { quick_error!(ERROR_CHECK STRUCT $($tail)*); };
962
963    (ERROR_CHECK $imode:tt ) => {};
964    // Utility functions
965    (IDENT $ident:ident) => { $ident }
966}
967
968
969/// Generic context type
970///
971/// Used mostly as a transport for `ResultExt::context` method
972#[derive(Debug)]
973pub struct Context<X, E>(pub X, pub E);
974
975/// Result extension trait adding a `context` method
976pub trait ResultExt<T, E> {
977    /// The method is use to add context information to current operation
978    ///
979    /// The context data is then used in error constructor to store additional
980    /// information within error. For example, you may add a filename as a
981    /// context for file operation. See crate documentation for the actual
982    /// example.
983    fn context<X>(self, x: X) -> Result<T, Context<X, E>>;
984}
985
986impl<T, E> ResultExt<T, E> for Result<T, E> {
987    fn context<X>(self, x: X) -> Result<T, Context<X, E>> {
988        self.map_err(|e| Context(x, e))
989    }
990}
991
992
993
994#[cfg(test)]
995#[allow(deprecated)]
996mod test {
997    use std::num::{ParseFloatError, ParseIntError};
998    use std::str::Utf8Error;
999    use std::string::FromUtf8Error;
1000    use std::error::Error;
1001    use std::path::{Path, PathBuf};
1002
1003    use super::ResultExt;
1004
1005    quick_error! {
1006        #[derive(Debug)]
1007        pub enum Bare {
1008            One
1009            Two
1010        }
1011    }
1012
1013    #[test]
1014    fn bare_item_direct() {
1015        assert_eq!(format!("{}", Bare::One), "One".to_string());
1016        assert_eq!(format!("{:?}", Bare::One), "One".to_string());
1017        assert!(Bare::One.cause().is_none());
1018    }
1019    #[test]
1020    fn bare_item_trait() {
1021        let err: &Error = &Bare::Two;
1022        assert_eq!(format!("{}", err), "Two".to_string());
1023        assert_eq!(format!("{:?}", err), "Two".to_string());
1024        assert!(err.cause().is_none());
1025    }
1026
1027    quick_error! {
1028        #[derive(Debug)]
1029        pub enum Wrapper wraps Wrapped {
1030            One
1031            Two(s: String) {
1032                display("two: {}", s)
1033                from()
1034            }
1035        }
1036    }
1037
1038    #[test]
1039    fn wrapper() {
1040        assert_eq!(format!("{}", Wrapper::from(Wrapped::One)),
1041            "One".to_string());
1042        assert_eq!(format!("{}",
1043            Wrapper::from(Wrapped::from(String::from("hello")))),
1044            "two: hello".to_string());
1045        assert_eq!(format!("{:?}", Wrapper::from(Wrapped::One)),
1046            "Wrapper(One)".to_string());
1047    }
1048
1049    quick_error! {
1050        #[derive(Debug, PartialEq)]
1051        pub enum TupleWrapper {
1052            /// ParseFloat Error
1053            ParseFloatError(err: ParseFloatError) {
1054                from()
1055                display("parse float error: {err}", err=err)
1056                cause(err)
1057            }
1058            Other(descr: &'static str) {
1059                display("Error: {}", descr)
1060            }
1061            /// FromUtf8 Error
1062            FromUtf8Error(err: Utf8Error, source: Vec<u8>) {
1063                cause(err)
1064                display(me) -> ("{desc} at index {pos}: {err}", desc="utf8 error", pos=err.valid_up_to(), err=err)
1065                from(err: FromUtf8Error) -> (err.utf8_error().clone(), err.into_bytes())
1066            }
1067            Discard {
1068                from(&'static str)
1069            }
1070            Singleton {
1071                display("Just a string")
1072            }
1073        }
1074    }
1075
1076    #[test]
1077    fn tuple_wrapper_err() {
1078        let cause = "one and a half times pi".parse::<f32>().unwrap_err();
1079        let err = TupleWrapper::ParseFloatError(cause.clone());
1080        assert_eq!(format!("{}", err), format!("parse float error: {}", cause));
1081        assert_eq!(format!("{:?}", err), format!("ParseFloatError({:?})", cause));
1082        assert_eq!(format!("{:?}", err.cause().unwrap()), format!("{:?}", cause));
1083    }
1084
1085    #[test]
1086    fn tuple_wrapper_trait_str() {
1087        let desc = "hello";
1088        let err: &Error = &TupleWrapper::Other(desc);
1089        assert_eq!(format!("{}", err), format!("Error: {}", desc));
1090        assert_eq!(format!("{:?}", err), format!("Other({:?})", desc));
1091        assert!(err.cause().is_none());
1092    }
1093
1094    #[test]
1095    fn tuple_wrapper_trait_two_fields() {
1096        let invalid_utf8: Vec<u8> = vec![0, 159, 146, 150];
1097        let cause = String::from_utf8(invalid_utf8.clone()).unwrap_err().utf8_error();
1098        let err: &Error = &TupleWrapper::FromUtf8Error(cause.clone(), invalid_utf8.clone());
1099        assert_eq!(format!("{}", err), format!("{desc} at index {pos}: {cause}", desc="utf8 error", pos=cause.valid_up_to(), cause=cause));
1100        assert_eq!(format!("{:?}", err), format!("FromUtf8Error({:?}, {:?})", cause, invalid_utf8));
1101        assert_eq!(format!("{:?}", err.cause().unwrap()), format!("{:?}", cause));
1102    }
1103
1104    #[test]
1105    fn tuple_wrapper_from() {
1106        let cause = "one and a half times pi".parse::<f32>().unwrap_err();
1107        let err = TupleWrapper::ParseFloatError(cause.clone());
1108        let err_from: TupleWrapper = From::from(cause);
1109        assert_eq!(err_from, err);
1110    }
1111
1112    #[test]
1113    fn tuple_wrapper_custom_from() {
1114        let invalid_utf8: Vec<u8> = vec![0, 159, 146, 150];
1115        let cause = String::from_utf8(invalid_utf8.clone()).unwrap_err();
1116        let err = TupleWrapper::FromUtf8Error(cause.utf8_error().clone(), invalid_utf8);
1117        let err_from: TupleWrapper = From::from(cause);
1118        assert_eq!(err_from, err);
1119    }
1120
1121    #[test]
1122    fn tuple_wrapper_discard() {
1123        let err: TupleWrapper = From::from("hello");
1124        assert_eq!(format!("{}", err), format!("Discard"));
1125        assert_eq!(format!("{:?}", err), format!("Discard"));
1126        assert!(err.cause().is_none());
1127    }
1128
1129    #[test]
1130    fn tuple_wrapper_singleton() {
1131        let err: TupleWrapper = TupleWrapper::Singleton;
1132        assert_eq!(format!("{}", err), format!("Just a string"));
1133        assert_eq!(format!("{:?}", err), format!("Singleton"));
1134        assert!(err.cause().is_none());
1135    }
1136
1137    quick_error! {
1138        #[derive(Debug, PartialEq)]
1139        pub enum StructWrapper {
1140            // Utf8 Error
1141            Utf8Error{ err: Utf8Error, hint: Option<&'static str> } {
1142                cause(err)
1143                display(me) -> ("{desc} at index {pos}: {err}", desc="utf8 error", pos=err.valid_up_to(), err=err)
1144                from(err: Utf8Error) -> { err: err, hint: None }
1145            }
1146            // Utf8 Error
1147            ExcessComma { descr: &'static str, } {
1148                display("Error: {}", descr)
1149            }
1150        }
1151    }
1152
1153    #[test]
1154    fn struct_wrapper_err() {
1155        let invalid_utf8: Vec<u8> = vec![0, 159, 146, 150];
1156        let cause = String::from_utf8(invalid_utf8.clone()).unwrap_err().utf8_error();
1157        let err: &Error = &StructWrapper::Utf8Error{ err: cause.clone(), hint: Some("nonsense") };
1158        assert_eq!(format!("{}", err), format!("{desc} at index {pos}: {cause}", desc="utf8 error", pos=cause.valid_up_to(), cause=cause));
1159        assert_eq!(format!("{:?}", err), format!("Utf8Error {{ err: {:?}, hint: {:?} }}", cause, Some("nonsense")));
1160        assert_eq!(format!("{:?}", err.cause().unwrap()), format!("{:?}", cause));
1161    }
1162
1163    #[test]
1164    fn struct_wrapper_struct_from() {
1165        let invalid_utf8: Vec<u8> = vec![0, 159, 146, 150];
1166        let cause = String::from_utf8(invalid_utf8.clone()).unwrap_err().utf8_error();
1167        let err = StructWrapper::Utf8Error{ err: cause.clone(), hint: None };
1168        let err_from: StructWrapper = From::from(cause);
1169        assert_eq!(err_from, err);
1170    }
1171
1172    #[test]
1173    fn struct_wrapper_excess_comma() {
1174        let descr = "hello";
1175        let err = StructWrapper::ExcessComma { descr: descr };
1176        assert_eq!(format!("{}", err), format!("Error: {}", descr));
1177        assert_eq!(format!("{:?}", err), format!("ExcessComma {{ descr: {:?} }}", descr));
1178        assert!(err.cause().is_none());
1179    }
1180
1181    quick_error! {
1182        #[derive(Debug)]
1183        pub enum ContextErr {
1184            Float(src: String, err: ParseFloatError) {
1185                context(s: &'a str, e: ParseFloatError) -> (s.to_string(), e)
1186                display("Float error {:?}: {}", src, err)
1187            }
1188            Int { src: String, err: ParseIntError } {
1189                context(s: &'a str, e: ParseIntError)
1190                    -> {src: s.to_string(), err: e}
1191                display("Int error {:?}: {}", src, err)
1192            }
1193            Utf8(path: PathBuf, err: Utf8Error) {
1194                context(p: AsRef<Path>, e: Utf8Error)
1195                    -> (p.as_ref().to_path_buf(), e)
1196                display("Path error at {:?}: {}", path, err)
1197            }
1198            Utf8Str(s: String, err: ::std::io::Error) {
1199                context(s: AsRef<str>, e: ::std::io::Error)
1200                    -> (s.as_ref().to_string(), e)
1201                display("Str error {:?}: {}", s, err)
1202            }
1203        }
1204    }
1205
1206    #[test]
1207    fn parse_float_error() {
1208        fn parse_float(s: &str) -> Result<f32, ContextErr> {
1209            Ok(try!(s.parse().context(s)))
1210        }
1211        assert_eq!(format!("{}", parse_float("12ab").unwrap_err()),
1212            r#"Float error "12ab": invalid float literal"#);
1213    }
1214
1215    #[test]
1216    fn parse_int_error() {
1217        fn parse_int(s: &str) -> Result<i32, ContextErr> {
1218            Ok(try!(s.parse().context(s)))
1219        }
1220        assert_eq!(format!("{}", parse_int("12.5").unwrap_err()),
1221            r#"Int error "12.5": invalid digit found in string"#);
1222    }
1223
1224    #[test]
1225    fn debug_context() {
1226        fn parse_int(s: &str) -> i32 {
1227            s.parse().context(s).unwrap()
1228        }
1229        assert_eq!(parse_int("12"), 12);
1230        assert_eq!(format!("{:?}", "x".parse::<i32>().context("x")),
1231            r#"Err(Context("x", ParseIntError { kind: InvalidDigit }))"#);
1232    }
1233
1234    #[test]
1235    fn path_context() {
1236        fn parse_utf<P: AsRef<Path>>(s: &[u8], p: P)
1237            -> Result<(), ContextErr>
1238        {
1239            try!(::std::str::from_utf8(s).context(p));
1240            Ok(())
1241        }
1242        let etext = parse_utf(b"a\x80\x80", "/etc").unwrap_err().to_string();
1243        assert!(etext.starts_with(
1244            "Path error at \"/etc\": invalid utf-8"));
1245        let etext = parse_utf(b"\x80\x80", PathBuf::from("/tmp")).unwrap_err()
1246            .to_string();
1247        assert!(etext.starts_with(
1248            "Path error at \"/tmp\": invalid utf-8"));
1249    }
1250
1251    #[test]
1252    fn conditional_compilation() {
1253        quick_error! {
1254            #[allow(dead_code)]
1255            #[derive(Debug)]
1256            pub enum Test {
1257                #[cfg(feature = "foo")]
1258                Variant
1259            }
1260        }
1261    }
1262}