]> git.proxmox.com Git - rustc.git/blob - src/vendor/failure/book/src/fail.md
New upstream version 1.28.0~beta.14+dfsg1
[rustc.git] / src / vendor / failure / book / src / fail.md
1 # The `Fail` trait
2
3 The `Fail` trait is a replacement for [`std::error::Error`][stderror]. It has
4 been designed to support a number of operations:
5
6 - Because it is bound by both `Debug` and `Display`, any failure can be
7 printed in two ways.
8 - It has both a `backtrace` and a `cause` method, allowing users to get
9 information about how the error occurred.
10 - It supports wrapping failures in additional contextual information.
11 - Because it is bound by `Send` and `Sync`, failures can be moved and share
12 between threads easily.
13 - Because it is bound by `'static`, the abstract `Fail` trait object can be
14 downcast into concrete types.
15
16 Every new error type in your code should implement Fail, so it can be
17 integrated into the entire system built around this trait. You can manually
18 implement `Fail` yourself, or you can use the derive for Fail defined
19 in a separate crate and documented [here][derive-docs].
20
21 Implementors of this trait are called 'failures'.
22
23 ## Cause
24
25 Often, an error type contains (or could contain) another underlying error type
26 which represents the "cause" of this error - for example, if your custom error
27 contains an `io::Error`, that is the cause of your error.
28
29 The cause method on the Fail trait allows all errors to expose their underlying
30 cause - if they have one - in a consistent way. Users can loop over the chain
31 of causes, for example, getting the entire series of causes for an error:
32
33 ```rust
34 // Assume err is a type that implements Fail;
35 let mut fail: &Fail = err;
36
37 while let Some(cause) = fail.cause() {
38 println!("{}", cause);
39
40 // Make `fail` the reference to the cause of the previous fail, making the
41 // loop "dig deeper" into the cause chain.
42 fail = cause;
43 }
44 ```
45
46 Because `&Fail` supports downcasting, you can also inspect causes in more
47 detail if you are expecting a certain failure:
48
49 ```rust
50 while let Some(cause) = fail.cause() {
51
52 if let Some(err) = cause.downcast_ref::<io::Error>() {
53 // treat io::Error specially
54 } else {
55 // fallback case
56 }
57
58 fail = cause;
59 }
60 ```
61
62 ## Backtraces
63
64 Errors can also generate a backtrace when they are constructed, helping you
65 determine the place the error was generated and every function that called into
66 that. Like causes, this is entirely optional - the authors of each failure
67 have to decide if generating a backtrace is appropriate in their use case.
68
69 The backtrace method allows all errors to expose their backtrace if they have
70 one. This enables a consistent method for getting the backtrace from an error:
71
72 ```rust
73 // We don't even know the type of the cause, but we can still get its
74 // backtrace.
75 if let Some(bt) = err.cause().and_then(|cause| cause.backtrace()) {
76 println!("{}", bt)
77 }
78 ```
79
80 The Backtrace type exposed by failure is different from the Backtrace exposed
81 by the backtrace crate, in that it has several optimizations:
82
83 - It has a no_std compatible form which will never be generate (because
84 backtraces require heap allocation), and should be entirely compiled out.
85 - It will not be generated unless the RUST_BACKTRACE environmental variable has
86 been set at runtime.
87 - Symbol resolution is delayed until the backtrace is actually printed, because
88 this is the most expensive part of generating a backtrace.
89
90 ## Context
91
92 Often, the libraries you are using will present error messages that don't
93 provide very helpful information about what exactly has gone wrong. For
94 example, if an `io::Error` says that an entity was "Not Found," that doesn't
95 communicate much about what specific file was missing - if it even was a file
96 (as opposed to a directory for example).
97
98 You can inject additional context to be carried with this error value,
99 providing semantic information about the nature of the error appropriate to the
100 level of abstraction that the code you are writing operates at. The `context`
101 method on `Fail` takes any displayable value (such as a string) to act as
102 context for this error.
103
104 Using the `ResultExt` trait, you can also get context as a convenient method on
105 `Result` directly. For example, suppose that your code attempted to read from a
106 Cargo.toml. You can wrap the io::Errors that occur with additional context
107 about what operation has failed:
108
109 ```rust
110 use failure::ResultExt;
111
112 let mut file = File::open(cargo_toml_path).context("Missing Cargo.toml")?;
113 file.read_to_end(&buffer).context("Could not read Cargo.toml")?;
114 ```
115
116 The `Context` object also has a constructor that does not take an underlying
117 error, allowing you to create ad hoc Context errors alongside those created by
118 applying the context method to an underlying error.
119
120 ## Backwards compatibility
121
122 We've taken several steps to make transitioning from std::error to failure as
123 painless as possible.
124
125 First, there is a blanket implementation of `Fail` for all types that implement
126 `std::error::Error`, as long as they are Send, Sync, and 'static. If you are
127 dealing with a library that hasn't shifted to `Fail`, it is automatically
128 compatible with failure already.
129
130 Second, `Fail` contains a method called compat, which produces a type that
131 implements `std::error::Error`. If you have a type that implements `Fail`, but
132 not the older Error trait, you can call compat to get a type that does
133 implement that trait (for example, if you need to return a `Box<Error>`).
134
135 The biggest hole in our backwards compatibility story is that you cannot
136 implement `std::error::Error` and also override the backtrace and cause methods
137 on `Fail`. We intend to enable this with specialization when it becomes stable.
138
139 [derive-docs]: https://boats.gitlab.io/failure/derive-fail.html
140 [stderror]: https://doc.rust-lang.org/std/error/trait.Error.html