extension_eyre/
lib.rs

1//! # About this crate
2//!
3//! Re-export of [`color-eyre`] crate that introduces `Extensions`.
4//!
5//! See [extensions](extensions) module documentation to learn how to use [`Extension`](extensions::Extension) and [`ExtensionExt`](extensions::ExtensionExt), .
6//!
7//! Rest of the doc here is the same as in [`color-eyre`].
8//!
9//! # extension-eyre
10//!
11//! An error report handler for panics and the [`eyre`] crate for colorful, consistent, and well
12//! formatted error reports for all kinds of errors.
13//!
14//! ## TLDR
15//!
16//! `extension_eyre` helps you build error reports that look like this:
17//!
18//! <pre><span style="color: #06989A"><b>extension-eyre</b></span> on <span style="color: #75507B"><b> hooked</b></span> <span style="color: #CC0000"><b>[$!] </b></span>is <span style="color: #FF8700"><b>📦 v0.5.0</b></span> via <span style="color: #CC0000"><b>🦀 v1.44.0</b></span>
19//! <span style="color: #4E9A06"><b>❯</b></span> cargo run --example custom_section
20//! <span style="color: #4E9A06"><b>    Finished</b></span> dev [unoptimized + debuginfo] target(s) in 0.04s
21//! <span style="color: #4E9A06"><b>     Running</b></span> `target/debug/examples/custom_section`
22//! Error:
23//!    0: <span style="color: #F15D22">Unable to read config</span>
24//!    1: <span style="color: #F15D22">cmd exited with non-zero status code</span>
25//!
26//! Stderr:
27//!    cat: fake_file: No such file or directory
28//!
29//!   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SPANTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
30//!
31//!    0: <span style="color: #F15D22">custom_section::output2</span> with <span style="color: #34E2E2">self=&quot;cat&quot; &quot;fake_file&quot;</span>
32//!       at <span style="color: #75507B">examples/custom_section.rs</span>:<span style="color: #75507B">14</span>
33//!    1: <span style="color: #F15D22">custom_section::read_file</span> with <span style="color: #34E2E2">path=&quot;fake_file&quot;</span>
34//!       at <span style="color: #75507B">examples/custom_section.rs</span>:<span style="color: #75507B">58</span>
35//!    2: <span style="color: #F15D22">custom_section::read_config</span>
36//!       at <span style="color: #75507B">examples/custom_section.rs</span>:<span style="color: #75507B">63</span>
37//!
38//! <span style="color: #34E2E2">Suggestion</span>: try using a file that exists next time</pre>
39//!
40//! ## Setup
41//!
42//! Add the following to your toml file:
43//!
44//! ```toml
45//! [dependencies]
46//! extension-eyre = "0.6"
47//! ```
48//!
49//! And install the panic and error report handlers:
50//!
51//! ```rust
52//! use extension_eyre::eyre::Result;
53//!
54//! fn main() -> Result<()> {
55//!     extension_eyre::install()?;
56//!
57//!     // ...
58//!     # Ok(())
59//! }
60//! ```
61//!
62//! ### Disabling tracing support
63//!
64//! If you don't plan on using `tracing_error` and `SpanTrace` you can disable the
65//! tracing integration to cut down on unused dependencies:
66//!
67//! ```toml
68//! [dependencies]
69//! extension-eyre = { version = "0.6", default-features = false }
70//! ```
71//!
72//! ### Disabling SpanTrace capture by default
73//!
74//! extension-eyre defaults to capturing span traces. This is because `SpanTrace`
75//! capture is significantly cheaper than `Backtrace` capture. However, like
76//! backtraces, span traces are most useful for debugging applications, and it's
77//! not uncommon to want to disable span trace capture by default to keep noise out
78//! developer.
79//!
80//! To disable span trace capture you must explicitly set one of the env variables
81//! that regulate `SpanTrace` capture to `"0"`:
82//!
83//! ```rust
84//! if std::env::var("RUST_SPANTRACE").is_err() {
85//!     std::env::set_var("RUST_SPANTRACE", "0");
86//! }
87//! ```
88//!
89//! ### Improving perf on debug builds
90//!
91//! In debug mode `extension-eyre` behaves noticably worse than `eyre`. This is caused
92//! by the fact that `eyre` uses `std::backtrace::Backtrace` instead of
93//! `backtrace::Backtrace`. The std version of backtrace is precompiled with
94//! optimizations, this means that whether or not you're in debug mode doesn't
95//! matter much for how expensive backtrace capture is, it will always be in the
96//! 10s of milliseconds to capture. A debug version of `backtrace::Backtrace`
97//! however isn't so lucky, and can take an order of magnitude more time to capture
98//! a backtrace compared to its std counterpart.
99//!
100//! Cargo [profile
101//! overrides](https://doc.rust-lang.org/cargo/reference/profiles.html#overrides)
102//! can be used to mitigate this problem. By configuring your project to always
103//! build `backtrace` with optimizations you should get the same performance from
104//! `extension-eyre` that you're used to with `eyre`. To do so add the following to
105//! your Cargo.toml:
106//!
107//! ```toml
108//! [profile.dev.package.backtrace]
109//! opt-level = 3
110//! ```
111//!
112//! ## Features
113//!
114//! ### Multiple report format verbosity levels
115//!
116//! `extension-eyre` provides 3 different report formats for how it formats the captured `SpanTrace`
117//! and `Backtrace`, minimal, short, and full. Take the below snippets of the output produced by [`examples/usage.rs`]:
118//!
119//! ---
120//!
121//! Running `cargo run --example usage` without `RUST_LIB_BACKTRACE` set will produce a minimal
122//! report like this:
123//!
124//! <pre><span style="color: #06989A"><b>extension-eyre</b></span> on <span style="color: #75507B"><b> hooked</b></span> <span style="color: #CC0000"><b>[$!] </b></span>is <span style="color: #FF8700"><b>📦 v0.5.0</b></span> via <span style="color: #CC0000"><b>🦀 v1.44.0</b></span> took <span style="color: #C4A000"><b>2s</b></span>
125//! <span style="color: #CC0000"><b>❯</b></span> cargo run --example usage
126//! <span style="color: #4E9A06"><b>    Finished</b></span> dev [unoptimized + debuginfo] target(s) in 0.04s
127//! <span style="color: #4E9A06"><b>     Running</b></span> `target/debug/examples/usage`
128//! <span style="color: #A1A1A1">Jul 05 19:15:58.026 </span><span style="color: #4E9A06"> INFO</span> <b>read_config</b>:<b>read_file{</b>path=&quot;fake_file&quot;<b>}</b>: Reading file
129//! Error:
130//!    0: <span style="color: #F15D22">Unable to read config</span>
131//!    1: <span style="color: #F15D22">No such file or directory (os error 2)</span>
132//!
133//!   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SPANTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
134//!
135//!    0: <span style="color: #F15D22">usage::read_file</span> with <span style="color: #34E2E2">path=&quot;fake_file&quot;</span>
136//!       at <span style="color: #75507B">examples/usage.rs</span>:<span style="color: #75507B">32</span>
137//!    1: <span style="color: #F15D22">usage::read_config</span>
138//!       at <span style="color: #75507B">examples/usage.rs</span>:<span style="color: #75507B">38</span>
139//!
140//! <span style="color: #34E2E2">Suggestion</span>: try using a file that exists next time</pre>
141//!
142//! <br>
143//!
144//! Running `RUST_LIB_BACKTRACE=1 cargo run --example usage` tells `extension-eyre` to use the short
145//! format, which additionally capture a [`backtrace::Backtrace`]:
146//!
147//! <pre><span style="color: #06989A"><b>extension-eyre</b></span> on <span style="color: #75507B"><b> hooked</b></span> <span style="color: #CC0000"><b>[$!] </b></span>is <span style="color: #FF8700"><b>📦 v0.5.0</b></span> via <span style="color: #CC0000"><b>🦀 v1.44.0</b></span>
148//! <span style="color: #CC0000"><b>❯</b></span> RUST_LIB_BACKTRACE=1 cargo run --example usage
149//! <span style="color: #4E9A06"><b>    Finished</b></span> dev [unoptimized + debuginfo] target(s) in 0.04s
150//! <span style="color: #4E9A06"><b>     Running</b></span> `target/debug/examples/usage`
151//! <span style="color: #A1A1A1">Jul 05 19:16:02.853 </span><span style="color: #4E9A06"> INFO</span> <b>read_config</b>:<b>read_file{</b>path=&quot;fake_file&quot;<b>}</b>: Reading file
152//! Error:
153//!    0: <span style="color: #F15D22">Unable to read config</span>
154//!    1: <span style="color: #F15D22">No such file or directory (os error 2)</span>
155//!
156//!   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SPANTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
157//!
158//!    0: <span style="color: #F15D22">usage::read_file</span> with <span style="color: #34E2E2">path=&quot;fake_file&quot;</span>
159//!       at <span style="color: #75507B">examples/usage.rs</span>:<span style="color: #75507B">32</span>
160//!    1: <span style="color: #F15D22">usage::read_config</span>
161//!       at <span style="color: #75507B">examples/usage.rs</span>:<span style="color: #75507B">38</span>
162//!
163//!   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ BACKTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
164//!   <span style="color: #34E2E2">                              ⋮ 5 frames hidden ⋮                               </span>
165//!    6: <span style="color: #F15D22">usage::read_file</span><span style="color: #88807C">::haee210cb22460af3</span>
166//!       at <span style="color: #75507B">/home/jlusby/git/yaahc/extension-eyre/examples/usage.rs</span>:<span style="color: #75507B">35</span>
167//!    7: <span style="color: #F15D22">usage::read_config</span><span style="color: #88807C">::ha649ef4ec333524d</span>
168//!       at <span style="color: #75507B">/home/jlusby/git/yaahc/extension-eyre/examples/usage.rs</span>:<span style="color: #75507B">40</span>
169//!    8: <span style="color: #F15D22">usage::main</span><span style="color: #88807C">::hbe443b50eac38236</span>
170//!       at <span style="color: #75507B">/home/jlusby/git/yaahc/extension-eyre/examples/usage.rs</span>:<span style="color: #75507B">11</span>
171//!   <span style="color: #34E2E2">                              ⋮ 10 frames hidden ⋮                              </span>
172//!
173//! <span style="color: #34E2E2">Suggestion</span>: try using a file that exists next time</pre>
174//!
175//! <br>
176//!
177//! Finally, running `RUST_LIB_BACKTRACE=full cargo run --example usage` tells `extension-eyre` to use
178//! the full format, which in addition to the above will attempt to include source lines where the
179//! error originated from, assuming it can find them on the disk.
180//!
181//! <pre><span style="color: #06989A"><b>extension-eyre</b></span> on <span style="color: #75507B"><b> hooked</b></span> <span style="color: #CC0000"><b>[$!] </b></span>is <span style="color: #FF8700"><b>📦 v0.5.0</b></span> via <span style="color: #CC0000"><b>🦀 v1.44.0</b></span>
182//! <span style="color: #CC0000"><b>❯</b></span> RUST_LIB_BACKTRACE=full cargo run --example usage
183//! <span style="color: #4E9A06"><b>    Finished</b></span> dev [unoptimized + debuginfo] target(s) in 0.05s
184//! <span style="color: #4E9A06"><b>     Running</b></span> `target/debug/examples/usage`
185//! <span style="color: #A1A1A1">Jul 05 19:16:06.335 </span><span style="color: #4E9A06"> INFO</span> <b>read_config</b>:<b>read_file{</b>path=&quot;fake_file&quot;<b>}</b>: Reading file
186//! Error:
187//!    0: <span style="color: #F15D22">Unable to read config</span>
188//!    1: <span style="color: #F15D22">No such file or directory (os error 2)</span>
189//!
190//!   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SPANTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
191//!
192//!    0: <span style="color: #F15D22">usage::read_file</span> with <span style="color: #34E2E2">path=&quot;fake_file&quot;</span>
193//!       at <span style="color: #75507B">examples/usage.rs</span>:<span style="color: #75507B">32</span>
194//!         30 │ }
195//!         31 │
196//!   <b>      32 &gt; #[instrument]</b>
197//!         33 │ fn read_file(path: &amp;str) -&gt; Result&lt;(), Report&gt; {
198//!         34 │     info!(&quot;Reading file&quot;);
199//!    1: <span style="color: #F15D22">usage::read_config</span>
200//!       at <span style="color: #75507B">examples/usage.rs</span>:<span style="color: #75507B">38</span>
201//!         36 │ }
202//!         37 │
203//!   <b>      38 &gt; #[instrument]</b>
204//!         39 │ fn read_config() -&gt; Result&lt;(), Report&gt; {
205//!         40 │     read_file(&quot;fake_file&quot;)
206//!
207//!   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ BACKTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
208//!   <span style="color: #34E2E2">                              ⋮ 5 frames hidden ⋮                               </span>
209//!    6: <span style="color: #F15D22">usage::read_file</span><span style="color: #88807C">::haee210cb22460af3</span>
210//!       at <span style="color: #75507B">/home/jlusby/git/yaahc/extension-eyre/examples/usage.rs</span>:<span style="color: #75507B">35</span>
211//!         33 │ fn read_file(path: &amp;str) -&gt; Result&lt;(), Report&gt; {
212//!         34 │     info!(&quot;Reading file&quot;);
213//!   <span style="color: #D3D7CF"><b>      35 &gt;     Ok(std::fs::read_to_string(path).map(drop)?)</b></span>
214//!         36 │ }
215//!         37 │
216//!    7: <span style="color: #F15D22">usage::read_config</span><span style="color: #88807C">::ha649ef4ec333524d</span>
217//!       at <span style="color: #75507B">/home/jlusby/git/yaahc/extension-eyre/examples/usage.rs</span>:<span style="color: #75507B">40</span>
218//!         38 │ #[instrument]
219//!         39 │ fn read_config() -&gt; Result&lt;(), Report&gt; {
220//!   <span style="color: #D3D7CF"><b>      40 &gt;     read_file(&quot;fake_file&quot;)</b></span>
221//!         41 │         .wrap_err(&quot;Unable to read config&quot;)
222//!         42 │         .suggestion(&quot;try using a file that exists next time&quot;)
223//!    8: <span style="color: #F15D22">usage::main</span><span style="color: #88807C">::hbe443b50eac38236</span>
224//!       at <span style="color: #75507B">/home/jlusby/git/yaahc/extension-eyre/examples/usage.rs</span>:<span style="color: #75507B">11</span>
225//!          9 │     extension_eyre::install()?;
226//!         10 │
227//!   <span style="color: #D3D7CF"><b>      11 &gt;     Ok(read_config()?)</b></span>
228//!         12 │ }
229//!         13 │
230//!   <span style="color: #34E2E2">                              ⋮ 10 frames hidden ⋮                              </span>
231//!
232//! <span style="color: #34E2E2">Suggestion</span>: try using a file that exists next time</pre>
233//!
234//! ### Custom `Section`s for error reports via [`Section`] trait
235//!
236//! The `section` module provides helpers for adding extra sections to error
237//! reports. Sections are disinct from error messages and are displayed
238//! independently from the chain of errors. Take this example of adding sections
239//! to contain `stderr` and `stdout` from a failed command, taken from
240//! [`examples/custom_section.rs`]:
241//!
242//! ```rust
243//! use extension_eyre::{eyre::eyre, SectionExt, Section, eyre::Report};
244//! use std::process::Command;
245//! use tracing::instrument;
246//!
247//! trait Output {
248//!     fn output2(&mut self) -> Result<String, Report>;
249//! }
250//!
251//! impl Output for Command {
252//!     #[instrument]
253//!     fn output2(&mut self) -> Result<String, Report> {
254//!         let output = self.output()?;
255//!
256//!         let stdout = String::from_utf8_lossy(&output.stdout);
257//!
258//!         if !output.status.success() {
259//!             let stderr = String::from_utf8_lossy(&output.stderr);
260//!             Err(eyre!("cmd exited with non-zero status code"))
261//!                 .with_section(move || stdout.trim().to_string().header("Stdout:"))
262//!                 .with_section(move || stderr.trim().to_string().header("Stderr:"))
263//!         } else {
264//!             Ok(stdout.into())
265//!         }
266//!     }
267//! }
268//! ```
269//!
270//! ---
271//!
272//! Here we have an function that, if the command exits unsuccessfully, creates a
273//! report indicating the failure and attaches two sections, one for `stdout` and
274//! one for `stderr`.
275//!
276//! Running `cargo run --example custom_section` shows us how these sections are
277//! included in the output:
278//!
279//! <pre><span style="color: #06989A"><b>extension-eyre</b></span> on <span style="color: #75507B"><b> hooked</b></span> <span style="color: #CC0000"><b>[$!] </b></span>is <span style="color: #FF8700"><b>📦 v0.5.0</b></span> via <span style="color: #CC0000"><b>🦀 v1.44.0</b></span> took <span style="color: #C4A000"><b>2s</b></span>
280//! <span style="color: #CC0000"><b>❯</b></span> cargo run --example custom_section
281//! <span style="color: #4E9A06"><b>    Finished</b></span> dev [unoptimized + debuginfo] target(s) in 0.04s
282//! <span style="color: #4E9A06"><b>     Running</b></span> `target/debug/examples/custom_section`
283//! Error:
284//!    0: <span style="color: #F15D22">Unable to read config</span>
285//!    1: <span style="color: #F15D22">cmd exited with non-zero status code</span>
286//!
287//! Stderr:
288//!    cat: fake_file: No such file or directory
289//!
290//!   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SPANTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
291//!
292//!    0: <span style="color: #F15D22">custom_section::output2</span> with <span style="color: #34E2E2">self=&quot;cat&quot; &quot;fake_file&quot;</span>
293//!       at <span style="color: #75507B">examples/custom_section.rs</span>:<span style="color: #75507B">14</span>
294//!    1: <span style="color: #F15D22">custom_section::read_file</span> with <span style="color: #34E2E2">path=&quot;fake_file&quot;</span>
295//!       at <span style="color: #75507B">examples/custom_section.rs</span>:<span style="color: #75507B">58</span>
296//!    2: <span style="color: #F15D22">custom_section::read_config</span>
297//!       at <span style="color: #75507B">examples/custom_section.rs</span>:<span style="color: #75507B">63</span>
298//!
299//! <span style="color: #34E2E2">Suggestion</span>: try using a file that exists next time</pre>
300//!
301//! Only the `Stderr:` section actually gets included. The `cat` command fails,
302//! so stdout ends up being empty and is skipped in the final report. This gives
303//! us a short and concise error report indicating exactly what was attempted and
304//! how it failed.
305//!
306//! ### Aggregating multiple errors into one report
307//!
308//! It's not uncommon for programs like batched task runners or parsers to want
309//! to return an error with multiple sources. The current version of the error
310//! trait does not support this use case very well, though there is [work being
311//! done](https://github.com/rust-lang/rfcs/pull/2895) to improve this.
312//!
313//! For now however one way to work around this is to compose errors outside the
314//! error trait. `extension-eyre` supports such composition in its error reports via
315//! the `Section` trait.
316//!
317//! For an example of how to aggregate errors check out [`examples/multiple_errors.rs`].
318//!
319//! ### Custom configuration for `color-backtrace` for setting custom filters and more
320//!
321//! The pretty printing for backtraces and span traces isn't actually provided by
322//! `extension-eyre`, but instead comes from its dependencies [`color-backtrace`] and
323//! [`color-spantrace`]. `color-backtrace` in particular has many more features
324//! than are exported by `extension-eyre`, such as customized color schemes, panic
325//! hooks, and custom frame filters. The custom frame filters are particularly
326//! useful when combined with `extension-eyre`, so to enable their usage we provide
327//! the `install` fn for setting up a custom `BacktracePrinter` with custom
328//! filters installed.
329//!
330//! For an example of how to setup custom filters, check out [`examples/custom_filter.rs`].
331//!
332//! [`eyre`]: https://docs.rs/eyre
333//! [`color-eyre`]: https://docs.rs/color-eyre
334//! [`tracing-error`]: https://docs.rs/tracing-error
335//! [`color-backtrace`]: https://docs.rs/color-backtrace
336//! [`eyre::EyreHandler`]: https://docs.rs/eyre/*/eyre/trait.EyreHandler.html
337//! [`backtrace::Backtrace`]: https://docs.rs/backtrace/*/backtrace/struct.Backtrace.html
338//! [`tracing_error::SpanTrace`]: https://docs.rs/tracing-error/*/tracing_error/struct.SpanTrace.html
339//! [`color-spantrace`]: https://github.com/yaahc/color-spantrace
340//! [`Section`]: https://docs.rs/color-eyre/*/extension_eyre/trait.Section.html
341//! [`eyre::Report`]: https://docs.rs/eyre/*/eyre/struct.Report.html
342//! [`eyre::Result`]: https://docs.rs/eyre/*/eyre/type.Result.html
343//! [`Handler`]: https://docs.rs/color-eyre/*/extension_eyre/struct.Handler.html
344//! [`examples/usage.rs`]: https://github.com/yaahc/color-eyre/blob/master/examples/usage.rs
345//! [`examples/custom_filter.rs`]: https://github.com/yaahc/color-eyre/blob/master/examples/custom_filter.rs
346//! [`examples/custom_section.rs`]: https://github.com/yaahc/color-eyre/blob/master/examples/custom_section.rs
347//! [`examples/multiple_errors.rs`]: https://github.com/yaahc/color-eyre/blob/master/examples/multiple_errors.rs
348#![doc(html_root_url = "https://docs.rs/color-eyre/0.6.2")]
349#![cfg_attr(docsrs, feature(doc_cfg))]
350#![warn(
351    missing_docs,
352    rustdoc::missing_doc_code_examples,
353    rust_2018_idioms,
354    unreachable_pub,
355    bad_style,
356    const_err,
357    dead_code,
358    improper_ctypes,
359    non_shorthand_field_patterns,
360    no_mangle_generic_items,
361    overflowing_literals,
362    path_statements,
363    patterns_in_fns_without_body,
364    private_in_public,
365    unconditional_recursion,
366    unused,
367    unused_allocation,
368    unused_comparisons,
369    unused_parens,
370    while_true
371)]
372#![allow(clippy::try_err)]
373
374use std::ops::Deref;
375use std::ops::DerefMut;
376
377pub use color_eyre::owo_colors;
378pub use eyre;
379#[doc(hidden)]
380pub use eyre::Report;
381#[doc(hidden)]
382pub use eyre::Result;
383#[cfg(feature = "capture-spantrace")]
384#[doc(hidden)]
385pub use Handler as Context;
386
387pub mod config;
388pub mod extensions;
389mod handler;
390pub(crate) mod private;
391
392pub use color_eyre::IndentedSection;
393pub use extensions::{Extension, ExtensionExt};
394#[doc(hidden)]
395pub use color_eyre::section::Section as Help;
396pub use color_eyre::section::{Section, SectionExt};
397
398/// A custom handler type for [`eyre::Report`] which provides colorful error
399/// reports and [`tracing-error`] support.
400///
401/// # Details
402///
403/// This type is not intended to be used directly, prefer using it via the
404/// [`extension_eyre::Report`] and [`extension_eyre::Result`] type aliases.
405///
406/// [`eyre::Report`]: https://docs.rs/eyre/*/eyre/struct.Report.html
407/// [`tracing-error`]: https://docs.rs/tracing-error
408/// [`extension_eyre::Report`]: type.Report.html
409/// [`extension_eyre::Result`]: type.Result.html
410pub struct Handler {
411    extensions: extensions::Extensions,
412    inner: Box<dyn eyre::EyreHandler>,
413}
414
415impl Deref for Handler {
416    type Target = Box<dyn eyre::EyreHandler>;
417
418    fn deref(&self) -> &Self::Target {
419        &self.inner
420    }
421}
422
423impl DerefMut for Handler {
424    fn deref_mut(&mut self) -> &mut Self::Target {
425        &mut self.inner
426    }
427}
428
429/// The kind of type erased error being reported
430#[cfg(feature = "issue-url")]
431#[cfg_attr(docsrs, doc(cfg(feature = "issue-url")))]
432pub enum ErrorKind<'a> {
433    /// A non recoverable error aka `panic!`
434    NonRecoverable(&'a dyn std::any::Any),
435    /// A recoverable error aka `impl std::error::Error`
436    Recoverable(&'a (dyn std::error::Error + 'static)),
437}
438
439/// Install the default panic and error report hooks
440///
441/// # Details
442///
443/// This function must be called to enable the customization of `eyre::Report`
444/// provided by `color-eyre`. This function should be called early, ideally
445/// before any errors could be encountered.
446///
447/// Only the first install will succeed. Calling this function after another
448/// report handler has been installed will cause an error. **Note**: This
449/// function _must_ be called before any `eyre::Report`s are constructed to
450/// prevent the default handler from being installed.
451///
452/// Installing a global theme in `color_spantrace` manually (by calling
453/// `color_spantrace::set_theme` or `color_spantrace::colorize` before
454/// `install` is called) will result in an error if this function is called.
455///
456/// # Examples
457///
458/// ```rust
459/// use extension_eyre::eyre::Result;
460///
461/// fn main() -> Result<()> {
462///     extension_eyre::install()?;
463///
464///     // ...
465///     # Ok(())
466/// }
467/// ```
468pub fn install() -> Result<(), crate::eyre::Report> {
469    config::HookBuilder::default().install()
470}