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