]> git.proxmox.com Git - rustc.git/blob - src/vendor/failure/book/src/error.md
New upstream version 1.28.0~beta.14+dfsg1
[rustc.git] / src / vendor / failure / book / src / error.md
1 # The `Error` type
2
3 In addition to the trait `Fail`, failure provides a type called `Error`. Any
4 type that implements `Fail` can be cast into `Error` using From and Into, which
5 allows users to throw errors using `?` which have different types, if the
6 function returns an `Error`.
7
8 For example:
9
10 ```rust
11 // Something you can deserialize
12 #[derive(Deserialize)]
13 struct Object {
14 ...
15 }
16
17 impl Object {
18 // This throws both IO Errors and JSON Errors, but they both get converted
19 // into the Error type.
20 fn from_file(path: &Path) -> Result<Object, Error> {
21 let mut string = String::new();
22 File::open(path)?.read_to_string(&mut string)?;
23 let object = json::from_str(&string)?;
24 Ok(object)
25 }
26 }
27 ```
28
29 ## Causes and Backtraces
30
31 The Error type has all of the methods from the Fail trait, with a few notable
32 differences. Most importantly, the cause and backtrace methods on Error do not
33 return Options - an Error is *guaranteed* to have a cause and a backtrace.
34
35 ```rust
36 // Both methods are guaranteed to return an &Fail and an &Backtrace
37 println!("{}, {}", error.cause(), error.backtrace())
38 ```
39
40 An `Error`'s cause is always the failure that was cast into this `Error`.
41 That failure may have further underlying causes. Unlike Fail, this means that
42 the cause of an Error will have the same Display representation as the Error
43 itself.
44
45 As to the error's guaranteed backtrace, when the conversion into the Error type
46 happens, if the underlying failure does not provide a backtrace, a new
47 backtrace is constructed pointing to that conversion point (rather than the
48 origin of the error). This construction only happens if there is no underlying
49 backtrace; if it does have a backtrace no new backtrace is constructed.
50
51 ## Downcasting
52
53 The Error type also supports downcasting into any concrete Fail type. It can be
54 downcast by reference or by value - when downcasting by value, the return type
55 is `Result<T, Error>`, allowing you to get the error back out of it.
56
57 ```rust
58 match error.downcast::<io::Error>() {
59 Ok(io_error) => { ... }
60 Err(error) => { ... }
61 }
62 ```
63
64 ## Implementation details
65
66 `Error` is essentially a trait object, but with some fanciness to store the
67 backtrace it may generate if the underlying failure did not have one. In
68 particular, we use a custom dynamically sized type to store the backtrace
69 information inline with the trait object data.
70
71 ```rust
72 struct Error {
73 // Inner<Fail> is a dynamically sized type
74 inner: Box<Inner<Fail>>,
75 }
76
77 struct Inner<F: Fail> {
78 backtrace: Backtrace,
79 failure: F,
80 }
81 ```
82
83 By storing the backtrace in the heap this way, we avoid increasing the size of
84 the Error type beyond that of two non-nullable pointers. This keeps the size of
85 the `Result` type from getting too large, avoiding having a negative impact on
86 the "happy path" of returning Ok. For example, a `Result<(), Error>` should be
87 represented as a pair of nullable pointers, with the null case representing
88 `Ok`. Similar optimizations can be applied to values up to at least a pointer
89 in size.
90
91 To emphasize: Error is intended for use cases where the error case is
92 considered relatively uncommon. This optimization makes the overhead of an
93 error less than it otherwise would be for the Ok branch. In cases where errors
94 are going to be returned extremely frequently, returning this Error type is
95 probably not appropriate, but you should benchmark in those cases.
96
97 (As a rule of thumb: if you're not sure if you can afford to have a trait
98 object, you probably *can* afford it. Heap allocations are not nearly as cheap
99 as stack allocations, but they're cheap enough that you can almost always
100 afford them.)