2 //! A macro which makes errors easy to write
4 //! Minimum type is like this:
7 //! #[macro_use] extern crate quick_error;
12 //! pub enum SomeError {
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
25 //! You may add arbitrary parameters to any struct variant:
28 //! # #[macro_use] extern crate quick_error;
33 //! pub enum SomeError {
35 //! Io(err: std::io::Error) {}
37 //! Utf8(err: std::str::Utf8Error) {}
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.
45 //! Now you might have noticed trailing braces `{}`. They are used to define
46 //! implementations. By default:
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
53 //! To define description simply add `description(value)` inside braces:
56 //! # #[macro_use] extern crate quick_error;
61 //! pub enum SomeError {
62 //! Io(err: std::io::Error) {
63 //! description(err.description())
65 //! Utf8(err: std::str::Utf8Error) {
66 //! description("utf8 error")
72 //! Normal rules for borrowing apply. So most of the time description either
73 //! returns constant string or forwards description from enclosed type.
75 //! To change `cause` method to return some error, add `cause(value)`, for
79 //! # #[macro_use] extern crate quick_error;
84 //! pub enum SomeError {
85 //! Io(err: std::io::Error) {
87 //! description(err.description())
89 //! Utf8(err: std::str::Utf8Error) {
90 //! description("utf8 error")
92 //! Other(err: Box<std::error::Error>) {
94 //! description(err.description())
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`
103 //! To change how each clause is `Display`ed add `display(pattern,..args)`,
107 //! # #[macro_use] extern crate quick_error;
112 //! pub enum SomeError {
113 //! Io(err: std::io::Error) {
114 //! display("I/O error: {}", err)
116 //! Utf8(err: std::str::Utf8Error) {
117 //! display("Utf8 error, valid up to {}", err.valid_up_to())
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.
127 //! # #[macro_use] extern crate quick_error;
130 //! use std::error::Error; // put methods like `description()` of this trait into scope
134 //! pub enum SomeError {
135 //! Io(err: std::io::Error) {
136 //! display(x) -> ("{}: {}", x.description(), err)
138 //! Utf8(err: std::str::Utf8Error) {
139 //! display(self_) -> ("{}, valid up to {}", self_.description(), err.valid_up_to())
145 //! To convert to the type from any other, use one of the three forms of
148 //! For example, to convert simple wrapper use bare `from()`:
151 //! # #[macro_use] extern crate quick_error;
156 //! pub enum SomeError {
157 //! Io(err: std::io::Error) {
164 //! This implements ``From<io::Error>``.
166 //! To convert to singleton enumeration type (discarding the value), use
167 //! the `from(type)` form:
170 //! # #[macro_use] extern crate quick_error;
175 //! pub enum SomeError {
177 //! from(std::fmt::Error)
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:
188 //! # #[macro_use] extern crate quick_error;
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())
198 //! /// Converts from both kinds of utf8 errors
199 //! Utf8(err: std::str::Utf8Error) {
201 //! from(err: std::string::FromUtf8Error) -> (err.utf8_error())
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:
213 //! # #[macro_use] extern crate quick_error;
215 //! # use std::fs::File;
216 //! # use std::path::{Path, PathBuf};
218 //! use quick_error::ResultExt;
223 //! File(filename: PathBuf, err: io::Error) {
224 //! context(path: &'a Path, err: io::Error)
225 //! -> (path.to_path_buf(), err)
230 //! fn openfile(path: &Path) -> Result<(), Error> {
231 //! try!(File::open(path).context(path));
233 //! // If we didn't have context, the line above would be written as;
235 //! // try!(File::open(path)
236 //! // .map_err(|err| Error::File(path.to_path_buf(), err)));
242 //! # openfile(Path::new("/etc/somefile")).ok();
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.
254 //! You also need to `use quick_error::ResultExt` extension trait to get
255 //! working `.context()` method.
257 //! More info on context in [this article](http://bit.ly/1PsuxDt).
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
267 //! Since quick-error 1.2.0 we have a way to make a private enum that is
268 //! wrapped by public structure:
271 //! #[macro_use] extern crate quick_error;
276 //! pub enum PubError wraps ErrorEnum {
282 //! This generates data structures like this
286 //! pub struct PubError(ErrorEnum);
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
300 //! It's possible to declare internal enum as public too.
305 /// Main macro that does all the work
307 macro_rules
! quick_error
{
310 pub enum $name
:ident { $($chunks:tt)* }
312 quick_error
!(SORT
[pub enum $name $
(#[$meta])* ]
314 queue
[ $
($chunks
)* ]);
317 enum $name
:ident { $($chunks:tt)* }
319 quick_error
!(SORT
[enum $name $
(#[$meta])* ]
321 queue
[ $
($chunks
)* ]);
325 pub enum $name
:ident wraps $enum_name
:ident { $($chunks:tt)* }
327 quick_error
!(WRAPPER $enum_name
[ pub struct ] $name $
(#[$meta])*);
328 quick_error
!(SORT
[enum $enum_name $
(#[$meta])* ]
330 queue
[ $
($chunks
)* ]);
334 pub enum $name
:ident wraps
pub $enum_name
:ident { $($chunks:tt)* }
336 quick_error
!(WRAPPER $enum_name
[ pub struct ] $name $
(#[$meta])*);
337 quick_error
!(SORT
[pub enum $enum_name $
(#[$meta])* ]
339 queue
[ $
($chunks
)* ]);
342 enum $name
:ident wraps $enum_name
:ident { $($chunks:tt)* }
344 quick_error
!(WRAPPER $enum_name
[ struct ] $name $
(#[$meta])*);
345 quick_error
!(SORT
[enum $enum_name $
(#[$meta])* ]
347 queue
[ $
($chunks
)* ]);
351 enum $name
:ident wraps
pub $enum_name
:ident { $($chunks:tt)* }
353 quick_error
!(WRAPPER $enum_name
[ struct ] $name $
(#[$meta])*);
354 quick_error
!(SORT
[pub enum $enum_name $
(#[$meta])* ]
356 queue
[ $
($chunks
)* ]);
361 WRAPPER $internal
:ident
[ $
($strdef
:tt
)* ] $strname
:ident
365 $
($strdef
)* $
strname ( $internal
);
367 impl ::std
::fmt
::Display
for $strname
{
368 fn fmt(&self, f
: &mut ::std
::fmt
::Formatter
)
369 -> ::std
::fmt
::Result
371 ::std
::fmt
::Display
::fmt(&self.0, f
)
375 impl From
<$internal
> for $strname
{
376 fn from(err
: $internal
) -> Self {
381 impl ::std
::error
::Error
for $strname
{
382 fn description(&self) -> &str {
385 fn cause(&self) -> Option
<&::std
::error
::Error
> {
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 )*}
)* ]
399 quick_error
!(ENUM_DEFINITION
[enum $name $
( #[$meta] )*]
401 queue
[$
($
( #[$imeta] )*
402 => $iitem
: $imode
[$
( $ivar
: $ityp
),*] )*]
404 quick_error
!(IMPLEMENTATIONS $name
{$
(
405 $iitem
: $imode
[$
(#[$imeta])*] [$( $ivar: $ityp ),*] {$( $ifuncs )*}
408 quick_error
!(ERROR_CHECK $imode $
($ifuncs
)*);
411 (SORT
[pub enum $name
:ident $
( #[$meta:meta] )*]
412 items
[$
($
( #[$imeta:meta] )*
413 => $iitem
:ident
: $imode
:tt
[$
( $ivar
:ident
: $ityp
:ty
),*]
414 {$( $ifuncs:tt )*}
)* ]
418 quick_error
!(ENUM_DEFINITION
[pub enum $name $
( #[$meta] )*]
420 queue
[$
($
( #[$imeta] )*
421 => $iitem
: $imode
[$
( $ivar
: $ityp
),*] )*]
423 quick_error
!(IMPLEMENTATIONS $name
{$
(
424 $iitem
: $imode
[$
(#[$imeta])*] [$( $ivar: $ityp ),*] {$( $ifuncs )*}
427 quick_error
!(ERROR_CHECK $imode $
($ifuncs
)*);
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 )*]
438 quick_error
!(SORT
[$
( $def
)*]
439 items
[$
( $
(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
440 buf
[$
( #[$bmeta] )* #[$qmeta] ]
441 queue
[$
( $tail
)*]);
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
)*]
451 quick_error
!(SORT
[$
( $def
)*]
452 items
[$
( $
(#[$imeta])*
453 => $iitem
: $imode
[$
( $ivar
:$ityp
),*] {$( $ifuncs )*}
)*]
454 buf
[$
(#[$bmeta])* => $qitem : UNIT [ ] ]
455 queue
[$
( $tail
)*]);
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 )*]
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
),*] {}
]
473 queue
[$
( $tail
)*]);
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
)*]
483 quick_error
!(SORT
[$
( $def
)*]
484 items
[$
( $
(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
485 buf
[$
( #[$bmeta] )* => $bitem: TUPLE [$( $qvar:$qtyp ),*] ]
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
)*]
497 quick_error
!(SORT
[$
( $def
)*]
498 items
[$
( $
(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
499 buf
[$
( #[$bmeta] )* => $bitem: STRUCT [$( $qvar:$qtyp ),*] ]
500 queue
[$
( $tail
)*]);
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
)*]
510 quick_error
!(SORT
[$
( $def
)*]
511 items
[$
( $
(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
512 buf
[$
( #[$bmeta] )* => $bitem: STRUCT [$( $qvar:$qtyp ),*] ]
513 queue
[$
( $tail
)*]);
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
)*]
524 quick_error
!(SORT
[$
( $def
)*]
525 items
[$
( $
(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*
526 $
(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {$( $qfuncs )*} ]
528 queue
[$
( $tail
)*]);
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
)*]
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
)*]);
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
),*] ]
554 quick_error
!(SORT
[$
( $def
)*]
555 items
[$
( $
(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*
556 $
(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {} ]
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 ),*}
)*} )* ]
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)]
574 $iitem $
(($
( $ttyp
),*))* $
({$( $svar: $styp ),*}
)*,
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 ),*}
)*} )* ]
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)]
592 $iitem $
(($
( $ttyp
),*))* $
({$( $svar: $styp ),*}
)*,
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
)*]
603 quick_error
!(ENUM_DEFINITION
[ $
($def
)* ]
604 body
[$
($
( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )*
605 $
( #[$qmeta] )* => $qitem () {} ]
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
)*]
616 quick_error
!(ENUM_DEFINITION
[ $
($def
)* ]
617 body
[$
($
( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )*
618 $
( #[$qmeta] )* => $qitem (($( $qtyp ),*)) {} ]
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
)*]
629 quick_error
!(ENUM_DEFINITION
[ $
($def
)* ]
630 body
[$
($
( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )*
631 $
( #[$qmeta] )* => $qitem () {{$( $qvar: $qtyp ),*}} ]
637 $item
:ident
: $imode
:tt
[$
(#[$imeta:meta])*] [$( $var:ident: $typ:ty ),*] {$( $funcs:tt )*}
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
652 quick_error
!(ITEM_PATTERN
653 $name $item
: $imode
[$
( ref $var
),*]
655 let display_fn
= quick_error
!(FIND_DISPLAY_IMPL
659 display_fn(self, fmt
)
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 {
675 quick_error
!(ITEM_PATTERN
676 $name $item
: $imode
[$
( ref $var
),*]
678 quick_error
!(FIND_DESCRIPTION_IMPL
679 $item
: $imode
self fmt
[$
( $var
),*]
685 fn cause(&self) -> Option
<&::std
::error
::Error
> {
689 quick_error
!(ITEM_PATTERN
690 $name $item
: $imode
[$
( ref $var
),*]
692 quick_error
!(FIND_CAUSE_IMPL
693 $item
: $imode
[$
( $var
),*]
701 quick_error
!(FIND_FROM_IMPL
702 $name $item
: $imode
[$
( $var
:$typ
),*]
706 quick_error
!(FIND_CONTEXT_IMPL
707 $name $item
: $imode
[$
( $var
:$typ
),*]
711 (FIND_DISPLAY_IMPL $name
:ident $item
:ident
: $imode
:tt
712 { display($self_:tt) -> ($( $exprs:tt )*) $( $tail:tt )*}
714 |quick_error
!(IDENT $self_
): &$name
, f
: &mut ::std
::fmt
::Formatter
| { write!(f, $( $exprs )*) }
716 (FIND_DISPLAY_IMPL $name
:ident $item
:ident
: $imode
:tt
717 { display($pattern:expr) $( $tail:tt )*}
719 |_
, f
: &mut ::std
::fmt
::Formatter
| { write!(f, $pattern) }
721 (FIND_DISPLAY_IMPL $name
:ident $item
:ident
: $imode
:tt
722 { display($pattern:expr, $( $exprs:tt )*) $( $tail:tt )*}
724 |_
, f
: &mut ::std
::fmt
::Formatter
| { write!(f, $pattern, $( $exprs )*) }
726 (FIND_DISPLAY_IMPL $name
:ident $item
:ident
: $imode
:tt
727 { $t:tt $( $tail:tt )*}
729 quick_error
!(FIND_DISPLAY_IMPL
733 (FIND_DISPLAY_IMPL $name
:ident $item
:ident
: $imode
:tt
736 |self_
: &$name
, f
: &mut ::std
::fmt
::Formatter
| {
737 write
!(f
, "{}", ::std
::error
::Error
::description(self_
))
740 (FIND_DESCRIPTION_IMPL $item
:ident
: $imode
:tt $me
:ident $fmt
:ident
742 { description($expr:expr) $( $tail:tt )*}
746 (FIND_DESCRIPTION_IMPL $item
:ident
: $imode
:tt $me
:ident $fmt
:ident
748 { $t:tt $( $tail:tt )*}
750 quick_error
!(FIND_DESCRIPTION_IMPL
751 $item
: $imode $me $fmt
[$
( $var
),*]
754 (FIND_DESCRIPTION_IMPL $item
:ident
: $imode
:tt $me
:ident $fmt
:ident
760 (FIND_CAUSE_IMPL $item
:ident
: $imode
:tt
762 { cause($expr:expr) $( $tail:tt )*}
766 (FIND_CAUSE_IMPL $item
:ident
: $imode
:tt
768 { $t:tt $( $tail:tt )*}
770 quick_error
!(FIND_CAUSE_IMPL
771 $item
: $imode
[$
( $var
),*]
774 (FIND_CAUSE_IMPL $item
:ident
: $imode
:tt
780 // ----------------------------- FROM IMPL --------------------------
781 (FIND_FROM_IMPL $name
:ident $item
:ident
: $imode
:tt
782 [$
( $var
:ident
: $typ
:ty
),*]
783 { from() $( $tail:tt )*}
786 impl From
<$typ
> for $name
{
787 fn from($var
: $typ
) -> $name
{
792 quick_error
!(FIND_FROM_IMPL
793 $name $item
: $imode
[$
( $var
:$typ
),*]
796 (FIND_FROM_IMPL $name
:ident $item
:ident
: UNIT
798 { from($ftyp:ty) $( $tail:tt )*}
800 impl From
<$ftyp
> for $name
{
801 fn from(_discarded_error
: $ftyp
) -> $name
{
805 quick_error
!(FIND_FROM_IMPL
806 $name $item
: UNIT
[ ]
809 (FIND_FROM_IMPL $name
:ident $item
:ident
: TUPLE
810 [$
( $var
:ident
: $typ
:ty
),*]
811 { from($fvar:ident: $ftyp:ty) -> ($( $texpr:expr ),*) $( $tail:tt )*}
813 impl From
<$ftyp
> for $name
{
814 fn from($fvar
: $ftyp
) -> $name
{
815 $name
::$
item($
( $texpr
),*)
818 quick_error
!(FIND_FROM_IMPL
819 $name $item
: TUPLE
[$
( $var
:$typ
),*]
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
)*}
826 impl From
<$ftyp
> for $name
{
827 fn from($fvar
: $ftyp
) -> $name
{
833 quick_error
!(FIND_FROM_IMPL
834 $name $item
: STRUCT
[$
( $var
:$typ
),*]
837 (FIND_FROM_IMPL $name
:ident $item
:ident
: $imode
:tt
838 [$
( $var
:ident
: $typ
:ty
),*]
839 { $t:tt $( $tail:tt )*}
841 quick_error
!(FIND_FROM_IMPL
842 $name $item
: $imode
[$
( $var
:$typ
),*]
846 (FIND_FROM_IMPL $name
:ident $item
:ident
: $imode
:tt
847 [$
( $var
:ident
: $typ
:ty
),*]
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
)* }
857 impl<T
: AsRef
<$ctyp
>> From
<$
crate::Context
<T
, $ftyp
>> for $name
{
859 $
crate::Context($cvar
, $fvar
): $
crate::Context
<T
, $ftyp
>)
862 $name
::$
item($
( $texpr
),*)
865 quick_error
!(FIND_CONTEXT_IMPL
866 $name $item
: TUPLE
[$
( $var
:$typ
),*]
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
)* }
874 impl<'a
> From
<$
crate::Context
<$ctyp
, $ftyp
>> for $name
{
876 $
crate::Context($cvar
, $fvar
): $
crate::Context
<$ctyp
, $ftyp
>)
879 $name
::$
item($
( $texpr
),*)
882 quick_error
!(FIND_CONTEXT_IMPL
883 $name $item
: TUPLE
[$
( $var
:$typ
),*]
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
)* }
891 impl<T
: AsRef
<$ctyp
>> From
<$
crate::Context
<T
, $ftyp
>> for $name
{
893 $
crate::Context($cvar
, $fvar
): $
crate::Context
<$ctyp
, $ftyp
>)
901 quick_error
!(FIND_CONTEXT_IMPL
902 $name $item
: STRUCT
[$
( $var
:$typ
),*]
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
)* }
910 impl<'a
> From
<$
crate::Context
<$ctyp
, $ftyp
>> for $name
{
912 $
crate::Context($cvar
, $fvar
): $
crate::Context
<$ctyp
, $ftyp
>)
920 quick_error
!(FIND_CONTEXT_IMPL
921 $name $item
: STRUCT
[$
( $var
:$typ
),*]
924 (FIND_CONTEXT_IMPL $name
:ident $item
:ident
: $imode
:tt
925 [$
( $var
:ident
: $typ
:ty
),*]
926 { $t:tt $( $tail:tt )*}
928 quick_error
!(FIND_CONTEXT_IMPL
929 $name $item
: $imode
[$
( $var
:$typ
),*]
933 (FIND_CONTEXT_IMPL $name
:ident $item
:ident
: $imode
:tt
934 [$
( $var
:ident
: $typ
:ty
),*]
938 // ----------------------------- ITEM IMPL --------------------------
939 (ITEM_BODY $
(#[$imeta:meta])* $item:ident: UNIT
941 (ITEM_BODY $
(#[$imeta:meta])* $item:ident: TUPLE
946 (ITEM_BODY $
(#[$imeta:meta])* $item:ident: STRUCT
947 [$
( $var
:ident
: $typ
:ty
),*]
951 (ITEM_PATTERN $name
:ident $item
:ident
: UNIT
[]
955 (ITEM_PATTERN $name
:ident $item
:ident
: TUPLE
956 [$
( ref $var
:ident
),*]
958 $name
::$
item ($
( ref $var
),*)
960 (ITEM_PATTERN $name
:ident $item
:ident
: STRUCT
961 [$
( ref $var
:ident
),*]
963 $name
::$item {$( ref $var ),*}
965 // This one should match all allowed sequences in "funcs" but not match
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)*); }
;
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)*); }
;
995 (ERROR_CHECK $imode
:tt
) => {}
;
997 (IDENT $ident
:ident
) => { $ident }
1001 /// Generic context type
1003 /// Used mostly as a transport for `ResultExt::context` method
1005 pub struct Context
<X
, E
>(pub X
, pub E
);
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
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
1015 fn context
<X
>(self, x
: X
) -> Result
<T
, Context
<X
, E
>>;
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
))
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}
;
1034 use super::ResultExt
;
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());
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());
1062 pub enum Wrapper wraps Wrapped
{
1065 display("two: {}", s
)
1073 assert_eq
!(format
!("{}", Wrapper
::from(Wrapped
::One
)),
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(),
1085 #[derive(Debug, PartialEq)]
1086 pub enum TupleWrapper
{
1087 /// ParseFloat Error
1088 ParseFloatError(err
: ParseFloatError
) {
1090 description(err
.description())
1091 display("parse float error: {err}", err
=err
)
1094 Other(descr
: &'
static str) {
1096 display("Error: {}", descr
)
1099 FromUtf8Error(err
: Utf8Error
, source
: Vec
<u8>) {
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())
1109 display("Just a string")
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
));
1125 fn tuple_wrapper_trait_str() {
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());
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
));
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
);
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
);
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());
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());
1181 #[derive(Debug, PartialEq)]
1182 pub enum StructWrapper
{
1184 Utf8Error{ err: Utf8Error, hint: Option<&'static str> }
{
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 }
1191 ExcessComma { descr: &'static str, }
{
1193 display("Error: {}", descr
)
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
));
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
);
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());
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
)
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
)
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
)
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
)
1254 fn parse_float_error() {
1255 fn parse_float(s
: &str) -> Result
<f32, ContextErr
> {
1256 Ok(try
!(s
.parse().context(s
)))
1258 assert_eq
!(format
!("{}", parse_float("12ab").unwrap_err()),
1259 r
#"Float error "12ab": invalid float literal"#);
1263 fn parse_int_error() {
1264 fn parse_int(s
: &str) -> Result
<i32, ContextErr
> {
1265 Ok(try
!(s
.parse().context(s
)))
1267 assert_eq
!(format
!("{}", parse_int("12.5").unwrap_err()),
1268 r
#"Int error "12.5": invalid digit found in string"#);
1272 fn debug_context() {
1273 fn parse_int(s
: &str) -> i32 {
1274 s
.parse().context(s
).unwrap()
1276 assert_eq
!(parse_int("12"), 12);
1277 assert_eq
!(format
!("{:?}", "x".parse
::<i32>().context("x")),
1278 r
#"Err(Context("x", ParseIntError { kind: InvalidDigit }))"#);
1283 fn parse_utf
<P
: AsRef
<Path
>>(s
: &[u8], p
: P
)
1284 -> Result
<(), ContextErr
>
1286 try
!(::std
::str::from_utf8(s
).context(p
));
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()
1294 assert
!(etext
.starts_with(
1295 "Path error at \"/tmp\": invalid utf-8"));
1299 fn conditional_compilation() {
1304 #[cfg(feature = "foo")]