1
- Anyhow &ensp ; ¯\\\_ (ツ)\_ /¯
1
+ Eyre &ensp ; ¯\\\_ (ツ)\_ /¯
2
2
=========================
3
3
4
- [ ![ Build Status] ( https://api.travis-ci.com/dtolnay/anyhow.svg?branch=master )] ( https://travis-ci.com/dtolnay/anyhow )
5
- [ ![ Latest Version] ( https://img.shields.io/crates/v/anyhow.svg )] ( https://crates.io/crates/anyhow )
6
- [ ![ Rust Documentation] ( https://img.shields.io/badge/api-rustdoc-blue.svg )] ( https://docs.rs/anyhow )
4
+ [ ![ Build Status] [ actions-badge ]] [ actions-url ]
5
+ [ ![ Latest Version] ( https://img.shields.io/crates/v/eyre.svg )] ( https://crates.io/crates/eyre )
6
+ [ ![ Rust Documentation] ( https://img.shields.io/badge/api-rustdoc-blue.svg )] ( https://docs.rs/eyre )
7
+
8
+ This library provides [ ` eyre::ErrReport ` ] [ ErrReport ] , a trait object based
9
+ error handling type for easy idiomatic error handling and reporting in Rust
10
+ applications.
11
+
12
+ First and foremost, this crate is a fork of ` anyhow ` by @dtolnay . My goal in
13
+ writing this crate is to explore new directions of handling context and to
14
+ explore new ways to communicate the intended usage of this crate via changes to
15
+ the API.
16
+
17
+ The main changes this crate brings to anyhow are
18
+
19
+ * Addition of the [ ` eyre::EyreContext ` ] trait and a type parameter on the core error
20
+ handling type which users can use to insert custom forms of context into
21
+ their general error type.
22
+ * Rebranding the type as principally for error reporting, rather than
23
+ describing it as an error type in its own right. This type is not an error,
24
+ it contains errors that it masqerades as, and provides helpers for creating
25
+ new errors to wrap those errors and for displaying those chains of errors,
26
+ and the included context, to the end user. The goal is to make it obvious
27
+ that this type is meant to be used when the only way you expect to handle
28
+ errors is to print them.
29
+ * Changing the [ ` anyhow::Context ` ] trait to [ ` eyre::WrapErr ` ] to make it clear
30
+ that it is unrelated to the [ ` eyre::EyreContext ` ] and the context member, and
31
+ is only for inserting new errors into the chain of errors.
32
+ * Addition of a new ` context ` function on [ ` eyre::ErrReport ` ] to assist with
33
+ extracting members from the inner Context, which is used by
34
+ [ ` eyre::ErrReport ` ] to extract [ ` std::backtrace::Backtrace ` ] 's from generic
35
+ contexts types.
36
+
37
+ These changes were made in order to facilitate the usage of
38
+ [ ` tracing::SpanTrace ` ] with anyhow, which is a Backtrace-like type for
39
+ rendering custom defined runtime context.
40
+
41
+ ** Note** : The way the ` eyre! ` macro works in practice differs from how
42
+ ` anyhow! ` works due to the addition of the generic type parameter. In anyhow
43
+ the following is valid.
44
+
45
+ ``` rust
46
+ let val = get_optional_val . ok_or_else (|| anyhow! (" failed to get value)).unwrap();
47
+ ```
48
+
49
+ Where as with `eyre!` this will fail due to being unable to infer the type for
50
+ the Context parameter. The solution to this problem, should you encounter it,
51
+ is to give the compiler a hint for what type it should be resolving to, either
52
+ via your return type or a type annotation.
53
+
54
+ ```rust
55
+ // Will work fine
56
+ let val: ErrReport = get_optional_val.ok_or_else(|| eyre!(" failed to get value )). unwrap ();
57
+ ```
58
+
59
+ [ ErrReport ] : https://docs.rs/eyre/1.0/eyre/struct.ErrReport.html
60
+ [ actions-badge ] : https://github.com/yaahc/eyre/workflows/ci/badge.svg
61
+ [ actions-url ] :https://github.com/yaahc/eyre/actions?query=workflow%3Aci
62
+
63
+ ## Customization
64
+
65
+ In order to insert your own custom context type you must first implement the
66
+ ` eyre::EyreContext ` trait for said type, which has four required methods.
67
+
68
+ * ` fn default(error: &Error) -> Self ` - For constructing default context while
69
+ allowing special case handling depending on the content of the error you're
70
+ wrapping.
71
+
72
+ This is essentially ` Default::default ` but more flexible, for example, the
73
+ ` eyre::DefaultContext ` type provide by this crate uses this to only capture a
74
+ ` Backtrace ` if the inner ` Error ` does not already have one.
75
+
76
+ ``` rust
77
+ fn default (error : & (dyn StdError + 'static )) -> Self {
78
+ let backtrace = backtrace_if_absent! (error );
79
+
80
+ Self { backtrace }
81
+ }
82
+ ```
83
+
84
+ * ` fn context_raw(&self, typeid TypeID) -> Option<&dyn Any> ` - For extracting
85
+ arbitrary members from a context based on their type.
7
86
8
- This library provides [ ` anyhow::Error ` ] [ Error ] , a trait object based error type
9
- for easy idiomatic error handling in Rust applications.
87
+ This method is like a flexible version of the ` fn backtrace(&self) ` method on
88
+ the ` Error ` trait. In the future we will likely support extracting ` Backtrace ` s
89
+ and ` SpanTrace ` s by default by relying on the implementation of ` context_raw `
90
+ provided by the user.
10
91
11
- [ Error ] : https://docs.rs/anyhow/1.0/anyhow/struct.Error.html
92
+
93
+ Here is how the ` eyre::DefaultContext ` type uses this to return ` Backtrace ` s.
94
+
95
+ ``` rust
96
+ fn context_raw (& self , typeid : TypeId ) -> Option <& dyn Any > {
97
+ if typeid == TypeId :: of :: <Backtrace >() {
98
+ self . backtrace. as_ref (). map (| b | b as & dyn Any )
99
+ } else {
100
+ None
101
+ }
102
+ }
103
+ ```
104
+
105
+ * ` fn debug(&self, error: &(dyn Error + 'static), f: &mut fmt::Formatter<'_>) -> fmt Result `
106
+ it's companion ` display ` version. - For formatting the entire error chain and
107
+ the user provided context.
108
+
109
+ When overriding the context it no longer makes sense for ` eyre::ErrReport ` to
110
+ provide the ` Display ` and ` Debug ` implementations for the user, becase we
111
+ cannot predict what forms of context you will need to display along side your
112
+ chain of errors. Instead we forward the implementations of ` Display ` and
113
+ ` Debug ` to these methods on the inner ` EyreContext ` type.
114
+
115
+ This crate does provide a few helpers to assist in writing display
116
+ implementations, specifically the ` Chain ` type, for treating an error and its
117
+ sources like an iterator, and the ` Indented ` type, for indenting multi line
118
+ errors consistently without using heap allocations.
119
+
120
+ ** Note** : best practices for printing errors suggest that ` {} ` should only
121
+ print the current error and none of its sources, and that the primary method of
122
+ displaying an error, its sources, and its context should be handled by the
123
+ ` Debug ` implementation, which is what is used to print errors that are returned
124
+ from ` main ` . For examples on how to implement this please refer to the
125
+ implementations of ` display ` and ` debug ` on ` eyre::DefaultContext `
126
+
127
+ Once you've defined a custom Context type you can use it throughout your
128
+ application by defining a type alias.
129
+
130
+ ``` rust
131
+ type ErrReport = eyre :: ErrReport <MyContext >;
132
+
133
+ // And optionally...
134
+ type Result <T , E = eyre :: ErrReport <MyContext >> = core :: result :: Result <T , E >;
135
+ ```
12
136
13
137
``` toml
14
138
[dependencies ]
15
- anyhow = " 1.0 "
139
+ eyre = " 0.2 "
16
140
```
17
141
18
142
* Compiler support: requires rustc 1.34+*
@@ -21,14 +145,14 @@ anyhow = "1.0"
21
145
22
146
## Details
23
147
24
- - Use ` Result<T, anyhow::Error > ` , or equivalently ` anyhow ::Result<T>` , as the
148
+ - Use ` Result<T, eyre::ErrReport > ` , or equivalently ` eyre ::Result<T>` , as the
25
149
return type of any fallible function.
26
150
27
151
Within the function, use ` ? ` to easily propagate any error that implements the
28
152
` std::error::Error ` trait.
29
153
30
154
``` rust
31
- use anyhow :: Result ;
155
+ use eyre :: Result ;
32
156
33
157
fn get_cluster_info () -> Result <ClusterMap > {
34
158
let config = std :: fs :: read_to_string (" cluster.json" )? ;
@@ -43,7 +167,7 @@ anyhow = "1.0"
43
167
application was in the middle of.
44
168
45
169
``` rust
46
- use anyhow :: {Context , Result };
170
+ use eyre :: {WrapErr , Result };
47
171
48
172
fn main () -> Result <()> {
49
173
...
@@ -78,7 +202,7 @@ anyhow = "1.0"
78
202
type does not already provide its own. In order to see backtraces, the
79
203
` RUST_LIB_BACKTRACE=1 ` environment variable must be defined.
80
204
81
- - Anyhow works with any error type that has an impl of ` std::error::Error ` ,
205
+ - Eyre works with any error type that has an impl of ` std::error::Error ` ,
82
206
including ones defined in your crate. We do not bundle a ` derive(Error) ` macro
83
207
but you can write the impls yourself or use a standalone macro like
84
208
[ thiserror] .
@@ -98,36 +222,40 @@ anyhow = "1.0"
98
222
}
99
223
```
100
224
101
- - One-off error messages can be constructed using the ` anyhow !` macro, which
102
- supports string interpolation and produces an ` anyhow::Error ` .
225
+ - One-off error messages can be constructed using the ` eyre !` macro, which
226
+ supports string interpolation and produces an ` eyre::ErrReport ` .
103
227
104
228
``` rust
105
- return Err (anyhow ! (" Missing attribute: {}" , missing ));
229
+ return Err (eyre ! (" Missing attribute: {}" , missing ));
106
230
```
107
231
108
232
<br >
109
233
110
234
## No-std support
111
235
236
+ ** NOTE** : tests are currently broken for ` no_std ` so I cannot guaruntee that
237
+ everything works still. I'm waiting for upstream fixes to be merged rather than
238
+ fixing them myself, so bear with me.
239
+
112
240
In no_std mode, the same API is almost all available and works the same way. To
113
- depend on Anyhow in no_std mode, disable our default enabled "std" feature in
241
+ depend on Eyre in no_std mode, disable our default enabled "std" feature in
114
242
Cargo.toml. A global allocator is required.
115
243
116
244
``` toml
117
245
[dependencies ]
118
- anyhow = { version = " 1.0 " , default-features = false }
246
+ eyre = { version = " 0.2 " , default-features = false }
119
247
```
120
248
121
249
Since the ` ? ` -based error conversions would normally rely on the
122
250
` std::error::Error ` trait which is only available through std, no_std mode will
123
- require an explicit ` .map_err(Error ::msg) ` when working with a non-Anyhow error
124
- type inside a function that returns Anyhow 's error type.
251
+ require an explicit ` .map_err(ErrReport ::msg) ` when working with a non-Eyre error
252
+ type inside a function that returns Eyre 's error type.
125
253
126
254
<br >
127
255
128
256
## Comparison to failure
129
257
130
- The ` anyhow::Error ` type works something like ` failure::Error ` , but unlike
258
+ The ` eyre::ErrReport ` type works something like ` failure::Error ` , but unlike
131
259
failure ours is built around the standard library's ` std::error::Error ` trait
132
260
rather than a separate trait ` failure::Fail ` . The standard library has adopted
133
261
the necessary improvements for this to be possible as part of [ RFC 2504] .
@@ -138,7 +266,7 @@ the necessary improvements for this to be possible as part of [RFC 2504].
138
266
139
267
## Comparison to thiserror
140
268
141
- Use Anyhow if you don't care what error type your functions return, you just
269
+ Use Eyre if you don't care what error type your functions return, you just
142
270
want it to be easy. This is common in application code. Use [ thiserror] if you
143
271
are a library that wants to design your own dedicated error type(s) so that on
144
272
failures the caller gets exactly the information that you choose.
0 commit comments