Coverage Report

Created: 2025-02-25 06:39

/rust/registry/src/index.crates.io-6f17d22bba15001f/quick-error-1.2.3/src/lib.rs
Line
Count
Source (jump to first uncovered line)
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]
299
macro_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
0
            fn fmt(&self, fmt: &mut ::std::fmt::Formatter)
637
0
                -> ::std::fmt::Result
638
0
            {
639
0
                match *self {
640
                    $(
641
                        $(#[$imeta])*
642
0
                        quick_error!(ITEM_PATTERN
643
0
                            $name $item: $imode [$( ref $var ),*]
644
0
                        ) => {
645
0
                            let display_fn = quick_error!(FIND_DISPLAY_IMPL
646
0
                                $name $item: $imode
647
0
                                {$( $funcs )*});
648
649
0
                            display_fn(self, fmt)
650
                        }
651
                    )*
652
                }
653
0
            }
654
0
        }
655
0
        #[allow(unused)]
656
0
        #[allow(unknown_lints)]  // no unused_doc_comments in older rust
657
0
        #[allow(renamed_and_removed_lints)]
658
0
        #[allow(unused_doc_comment)]
659
0
        #[allow(unused_doc_comments)]
660
0
        impl ::std::error::Error for $name {
661
0
            fn cause(&self) -> Option<&::std::error::Error> {
662
0
                match *self {
663
                    $(
664
                        $(#[$imeta])*
665
0
                        quick_error!(ITEM_PATTERN
666
0
                            $name $item: $imode [$( ref $var ),*]
667
0
                        ) => {
668
0
                            quick_error!(FIND_CAUSE_IMPL
669
0
                                $item: $imode [$( $var ),*]
670
0
                                {$( $funcs )*})
671
                        }
672
                    )*
673
                }
674
0
            }
675
0
        }
676
0
        $(
677
0
            quick_error!(FIND_FROM_IMPL
678
0
                $name $item: $imode [$( $var:$typ ),*]
679
0
                {$( $funcs )*});
680
0
        )*
681
0
        $(
682
0
            quick_error!(FIND_CONTEXT_IMPL
683
0
                $name $item: $imode [$( $var:$typ ),*]
684
0
                {$( $funcs )*});
685
0
        )*
686
0
    };
687
0
    (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
688
0
        { display($self_:tt) -> ($( $exprs:tt )*) $( $tail:tt )*}
689
0
    ) => {
690
0
        |quick_error!(IDENT $self_): &$name, f: &mut ::std::fmt::Formatter| { write!(f, $( $exprs )*) }
691
0
    };
692
0
    (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
693
0
        { display($pattern:expr) $( $tail:tt )*}
694
0
    ) => {
695
0
        |_, f: &mut ::std::fmt::Formatter| { write!(f, $pattern) }
696
0
    };
697
0
    (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
698
0
        { display($pattern:expr, $( $exprs:tt )*) $( $tail:tt )*}
699
0
    ) => {
700
0
        |_, f: &mut ::std::fmt::Formatter| { write!(f, $pattern, $( $exprs )*) }
Unexecuted instantiation: <resolv_conf::grammar::ParseError as core::fmt::Display>::fmt::{closure#0}
Unexecuted instantiation: <resolv_conf::grammar::ParseError as core::fmt::Display>::fmt::{closure#1}
Unexecuted instantiation: <resolv_conf::grammar::ParseError as core::fmt::Display>::fmt::{closure#2}
Unexecuted instantiation: <resolv_conf::grammar::ParseError as core::fmt::Display>::fmt::{closure#3}
Unexecuted instantiation: <resolv_conf::grammar::ParseError as core::fmt::Display>::fmt::{closure#4}
Unexecuted instantiation: <resolv_conf::grammar::ParseError as core::fmt::Display>::fmt::{closure#5}
Unexecuted instantiation: <resolv_conf::grammar::ParseError as core::fmt::Display>::fmt::{closure#6}
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)]
973
pub struct Context<X, E>(pub X, pub E);
974
975
/// Result extension trait adding a `context` method
976
pub 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
986
impl<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)]
996
mod 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
}