std/
error.rs

1#![doc = include_str!("../../core/src/error.md")]
2#![stable(feature = "rust1", since = "1.0.0")]
3
4#[stable(feature = "rust1", since = "1.0.0")]
5pub use core::error::Error;
6#[unstable(feature = "error_generic_member_access", issue = "99301")]
7pub use core::error::{Request, request_ref, request_value};
8
9use crate::backtrace::Backtrace;
10use crate::fmt::{self, Write};
11
12/// An error reporter that prints an error and its sources.
13///
14/// Report also exposes configuration options for formatting the error sources, either entirely on a
15/// single line, or in multi-line format with each source on a new line.
16///
17/// `Report` only requires that the wrapped error implement `Error`. It doesn't require that the
18/// wrapped error be `Send`, `Sync`, or `'static`.
19///
20/// # Examples
21///
22/// ```rust
23/// #![feature(error_reporter)]
24/// use std::error::{Error, Report};
25/// use std::fmt;
26///
27/// #[derive(Debug)]
28/// struct SuperError {
29///     source: SuperErrorSideKick,
30/// }
31///
32/// impl fmt::Display for SuperError {
33///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34///         write!(f, "SuperError is here!")
35///     }
36/// }
37///
38/// impl Error for SuperError {
39///     fn source(&self) -> Option<&(dyn Error + 'static)> {
40///         Some(&self.source)
41///     }
42/// }
43///
44/// #[derive(Debug)]
45/// struct SuperErrorSideKick;
46///
47/// impl fmt::Display for SuperErrorSideKick {
48///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49///         write!(f, "SuperErrorSideKick is here!")
50///     }
51/// }
52///
53/// impl Error for SuperErrorSideKick {}
54///
55/// fn get_super_error() -> Result<(), SuperError> {
56///     Err(SuperError { source: SuperErrorSideKick })
57/// }
58///
59/// fn main() {
60///     match get_super_error() {
61///         Err(e) => println!("Error: {}", Report::new(e)),
62///         _ => println!("No error"),
63///     }
64/// }
65/// ```
66///
67/// This example produces the following output:
68///
69/// ```console
70/// Error: SuperError is here!: SuperErrorSideKick is here!
71/// ```
72///
73/// ## Output consistency
74///
75/// Report prints the same output via `Display` and `Debug`, so it works well with
76/// [`Result::unwrap`]/[`Result::expect`] which print their `Err` variant via `Debug`:
77///
78/// ```should_panic
79/// #![feature(error_reporter)]
80/// use std::error::Report;
81/// # use std::error::Error;
82/// # use std::fmt;
83/// # #[derive(Debug)]
84/// # struct SuperError {
85/// #     source: SuperErrorSideKick,
86/// # }
87/// # impl fmt::Display for SuperError {
88/// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89/// #         write!(f, "SuperError is here!")
90/// #     }
91/// # }
92/// # impl Error for SuperError {
93/// #     fn source(&self) -> Option<&(dyn Error + 'static)> {
94/// #         Some(&self.source)
95/// #     }
96/// # }
97/// # #[derive(Debug)]
98/// # struct SuperErrorSideKick;
99/// # impl fmt::Display for SuperErrorSideKick {
100/// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101/// #         write!(f, "SuperErrorSideKick is here!")
102/// #     }
103/// # }
104/// # impl Error for SuperErrorSideKick {}
105/// # fn get_super_error() -> Result<(), SuperError> {
106/// #     Err(SuperError { source: SuperErrorSideKick })
107/// # }
108///
109/// get_super_error().map_err(Report::new).unwrap();
110/// ```
111///
112/// This example produces the following output:
113///
114/// ```console
115/// thread 'main' panicked at src/error.rs:34:40:
116/// called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!
117/// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
118/// ```
119///
120/// ## Return from `main`
121///
122/// `Report` also implements `From` for all types that implement [`Error`]; this when combined with
123/// the `Debug` output means `Report` is an ideal starting place for formatting errors returned
124/// from `main`.
125///
126/// ```should_panic
127/// #![feature(error_reporter)]
128/// use std::error::Report;
129/// # use std::error::Error;
130/// # use std::fmt;
131/// # #[derive(Debug)]
132/// # struct SuperError {
133/// #     source: SuperErrorSideKick,
134/// # }
135/// # impl fmt::Display for SuperError {
136/// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137/// #         write!(f, "SuperError is here!")
138/// #     }
139/// # }
140/// # impl Error for SuperError {
141/// #     fn source(&self) -> Option<&(dyn Error + 'static)> {
142/// #         Some(&self.source)
143/// #     }
144/// # }
145/// # #[derive(Debug)]
146/// # struct SuperErrorSideKick;
147/// # impl fmt::Display for SuperErrorSideKick {
148/// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149/// #         write!(f, "SuperErrorSideKick is here!")
150/// #     }
151/// # }
152/// # impl Error for SuperErrorSideKick {}
153/// # fn get_super_error() -> Result<(), SuperError> {
154/// #     Err(SuperError { source: SuperErrorSideKick })
155/// # }
156///
157/// fn main() -> Result<(), Report<SuperError>> {
158///     get_super_error()?;
159///     Ok(())
160/// }
161/// ```
162///
163/// This example produces the following output:
164///
165/// ```console
166/// Error: SuperError is here!: SuperErrorSideKick is here!
167/// ```
168///
169/// **Note**: `Report`s constructed via `?` and `From` will be configured to use the single line
170/// output format. If you want to make sure your `Report`s are pretty printed and include backtrace
171/// you will need to manually convert and enable those flags.
172///
173/// ```should_panic
174/// #![feature(error_reporter)]
175/// use std::error::Report;
176/// # use std::error::Error;
177/// # use std::fmt;
178/// # #[derive(Debug)]
179/// # struct SuperError {
180/// #     source: SuperErrorSideKick,
181/// # }
182/// # impl fmt::Display for SuperError {
183/// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184/// #         write!(f, "SuperError is here!")
185/// #     }
186/// # }
187/// # impl Error for SuperError {
188/// #     fn source(&self) -> Option<&(dyn Error + 'static)> {
189/// #         Some(&self.source)
190/// #     }
191/// # }
192/// # #[derive(Debug)]
193/// # struct SuperErrorSideKick;
194/// # impl fmt::Display for SuperErrorSideKick {
195/// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196/// #         write!(f, "SuperErrorSideKick is here!")
197/// #     }
198/// # }
199/// # impl Error for SuperErrorSideKick {}
200/// # fn get_super_error() -> Result<(), SuperError> {
201/// #     Err(SuperError { source: SuperErrorSideKick })
202/// # }
203///
204/// fn main() -> Result<(), Report<SuperError>> {
205///     get_super_error()
206///         .map_err(Report::from)
207///         .map_err(|r| r.pretty(true).show_backtrace(true))?;
208///     Ok(())
209/// }
210/// ```
211///
212/// This example produces the following output:
213///
214/// ```console
215/// Error: SuperError is here!
216///
217/// Caused by:
218///       SuperErrorSideKick is here!
219/// ```
220#[unstable(feature = "error_reporter", issue = "90172")]
221pub struct Report<E = Box<dyn Error>> {
222    /// The error being reported.
223    error: E,
224    /// Whether a backtrace should be included as part of the report.
225    show_backtrace: bool,
226    /// Whether the report should be pretty-printed.
227    pretty: bool,
228}
229
230impl<E> Report<E>
231where
232    Report<E>: From<E>,
233{
234    /// Creates a new `Report` from an input error.
235    #[unstable(feature = "error_reporter", issue = "90172")]
236    pub fn new(error: E) -> Report<E> {
237        Self::from(error)
238    }
239}
240
241impl<E> Report<E> {
242    /// Enable pretty-printing the report across multiple lines.
243    ///
244    /// # Examples
245    ///
246    /// ```rust
247    /// #![feature(error_reporter)]
248    /// use std::error::Report;
249    /// # use std::error::Error;
250    /// # use std::fmt;
251    /// # #[derive(Debug)]
252    /// # struct SuperError {
253    /// #     source: SuperErrorSideKick,
254    /// # }
255    /// # impl fmt::Display for SuperError {
256    /// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
257    /// #         write!(f, "SuperError is here!")
258    /// #     }
259    /// # }
260    /// # impl Error for SuperError {
261    /// #     fn source(&self) -> Option<&(dyn Error + 'static)> {
262    /// #         Some(&self.source)
263    /// #     }
264    /// # }
265    /// # #[derive(Debug)]
266    /// # struct SuperErrorSideKick;
267    /// # impl fmt::Display for SuperErrorSideKick {
268    /// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
269    /// #         write!(f, "SuperErrorSideKick is here!")
270    /// #     }
271    /// # }
272    /// # impl Error for SuperErrorSideKick {}
273    ///
274    /// let error = SuperError { source: SuperErrorSideKick };
275    /// let report = Report::new(error).pretty(true);
276    /// eprintln!("Error: {report:?}");
277    /// ```
278    ///
279    /// This example produces the following output:
280    ///
281    /// ```console
282    /// Error: SuperError is here!
283    ///
284    /// Caused by:
285    ///       SuperErrorSideKick is here!
286    /// ```
287    ///
288    /// When there are multiple source errors the causes will be numbered in order of iteration
289    /// starting from the outermost error.
290    ///
291    /// ```rust
292    /// #![feature(error_reporter)]
293    /// use std::error::Report;
294    /// # use std::error::Error;
295    /// # use std::fmt;
296    /// # #[derive(Debug)]
297    /// # struct SuperError {
298    /// #     source: SuperErrorSideKick,
299    /// # }
300    /// # impl fmt::Display for SuperError {
301    /// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
302    /// #         write!(f, "SuperError is here!")
303    /// #     }
304    /// # }
305    /// # impl Error for SuperError {
306    /// #     fn source(&self) -> Option<&(dyn Error + 'static)> {
307    /// #         Some(&self.source)
308    /// #     }
309    /// # }
310    /// # #[derive(Debug)]
311    /// # struct SuperErrorSideKick {
312    /// #     source: SuperErrorSideKickSideKick,
313    /// # }
314    /// # impl fmt::Display for SuperErrorSideKick {
315    /// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
316    /// #         write!(f, "SuperErrorSideKick is here!")
317    /// #     }
318    /// # }
319    /// # impl Error for SuperErrorSideKick {
320    /// #     fn source(&self) -> Option<&(dyn Error + 'static)> {
321    /// #         Some(&self.source)
322    /// #     }
323    /// # }
324    /// # #[derive(Debug)]
325    /// # struct SuperErrorSideKickSideKick;
326    /// # impl fmt::Display for SuperErrorSideKickSideKick {
327    /// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
328    /// #         write!(f, "SuperErrorSideKickSideKick is here!")
329    /// #     }
330    /// # }
331    /// # impl Error for SuperErrorSideKickSideKick { }
332    ///
333    /// let source = SuperErrorSideKickSideKick;
334    /// let source = SuperErrorSideKick { source };
335    /// let error = SuperError { source };
336    /// let report = Report::new(error).pretty(true);
337    /// eprintln!("Error: {report:?}");
338    /// ```
339    ///
340    /// This example produces the following output:
341    ///
342    /// ```console
343    /// Error: SuperError is here!
344    ///
345    /// Caused by:
346    ///    0: SuperErrorSideKick is here!
347    ///    1: SuperErrorSideKickSideKick is here!
348    /// ```
349    #[unstable(feature = "error_reporter", issue = "90172")]
350    pub fn pretty(mut self, pretty: bool) -> Self {
351        self.pretty = pretty;
352        self
353    }
354
355    /// Display backtrace if available when using pretty output format.
356    ///
357    /// # Examples
358    ///
359    /// **Note**: Report will search for the first `Backtrace` it can find starting from the
360    /// outermost error. In this example it will display the backtrace from the second error in the
361    /// sources, `SuperErrorSideKick`.
362    ///
363    /// ```rust
364    /// #![feature(error_reporter)]
365    /// #![feature(error_generic_member_access)]
366    /// # use std::error::Error;
367    /// # use std::fmt;
368    /// use std::error::Request;
369    /// use std::error::Report;
370    /// use std::backtrace::Backtrace;
371    ///
372    /// # #[derive(Debug)]
373    /// # struct SuperError {
374    /// #     source: SuperErrorSideKick,
375    /// # }
376    /// # impl fmt::Display for SuperError {
377    /// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
378    /// #         write!(f, "SuperError is here!")
379    /// #     }
380    /// # }
381    /// # impl Error for SuperError {
382    /// #     fn source(&self) -> Option<&(dyn Error + 'static)> {
383    /// #         Some(&self.source)
384    /// #     }
385    /// # }
386    /// #[derive(Debug)]
387    /// struct SuperErrorSideKick {
388    ///     backtrace: Backtrace,
389    /// }
390    ///
391    /// impl SuperErrorSideKick {
392    ///     fn new() -> SuperErrorSideKick {
393    ///         SuperErrorSideKick { backtrace: Backtrace::force_capture() }
394    ///     }
395    /// }
396    ///
397    /// impl Error for SuperErrorSideKick {
398    ///     fn provide<'a>(&'a self, request: &mut Request<'a>) {
399    ///         request.provide_ref::<Backtrace>(&self.backtrace);
400    ///     }
401    /// }
402    ///
403    /// // The rest of the example is unchanged ...
404    /// # impl fmt::Display for SuperErrorSideKick {
405    /// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
406    /// #         write!(f, "SuperErrorSideKick is here!")
407    /// #     }
408    /// # }
409    ///
410    /// let source = SuperErrorSideKick::new();
411    /// let error = SuperError { source };
412    /// let report = Report::new(error).pretty(true).show_backtrace(true);
413    /// eprintln!("Error: {report:?}");
414    /// ```
415    ///
416    /// This example produces something similar to the following output:
417    ///
418    /// ```console
419    /// Error: SuperError is here!
420    ///
421    /// Caused by:
422    ///       SuperErrorSideKick is here!
423    ///
424    /// Stack backtrace:
425    ///    0: rust_out::main::_doctest_main_src_error_rs_1158_0::SuperErrorSideKick::new
426    ///    1: rust_out::main::_doctest_main_src_error_rs_1158_0
427    ///    2: rust_out::main
428    ///    3: core::ops::function::FnOnce::call_once
429    ///    4: std::sys::backtrace::__rust_begin_short_backtrace
430    ///    5: std::rt::lang_start::{{closure}}
431    ///    6: std::panicking::try
432    ///    7: std::rt::lang_start_internal
433    ///    8: std::rt::lang_start
434    ///    9: main
435    ///   10: __libc_start_main
436    ///   11: _start
437    /// ```
438    #[unstable(feature = "error_reporter", issue = "90172")]
439    pub fn show_backtrace(mut self, show_backtrace: bool) -> Self {
440        self.show_backtrace = show_backtrace;
441        self
442    }
443}
444
445impl<E> Report<E>
446where
447    E: Error,
448{
449    fn backtrace(&self) -> Option<&Backtrace> {
450        // have to grab the backtrace on the first error directly since that error may not be
451        // 'static
452        let backtrace = request_ref(&self.error);
453        let backtrace = backtrace.or_else(|| {
454            self.error
455                .source()
456                .map(|source| source.sources().find_map(|source| request_ref(source)))
457                .flatten()
458        });
459        backtrace
460    }
461
462    /// Format the report as a single line.
463    #[unstable(feature = "error_reporter", issue = "90172")]
464    fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
465        write!(f, "{}", self.error)?;
466
467        let sources = self.error.source().into_iter().flat_map(<dyn Error>::sources);
468
469        for cause in sources {
470            write!(f, ": {cause}")?;
471        }
472
473        Ok(())
474    }
475
476    /// Format the report as multiple lines, with each error cause on its own line.
477    #[unstable(feature = "error_reporter", issue = "90172")]
478    fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
479        let error = &self.error;
480
481        write!(f, "{error}")?;
482
483        if let Some(cause) = error.source() {
484            write!(f, "\n\nCaused by:")?;
485
486            let multiple = cause.source().is_some();
487
488            for (ind, error) in cause.sources().enumerate() {
489                writeln!(f)?;
490                let mut indented = Indented { inner: f };
491                if multiple {
492                    write!(indented, "{ind: >4}: {error}")?;
493                } else {
494                    write!(indented, "      {error}")?;
495                }
496            }
497        }
498
499        if self.show_backtrace {
500            if let Some(backtrace) = self.backtrace() {
501                write!(f, "\n\nStack backtrace:\n{}", backtrace.to_string().trim_end())?;
502            }
503        }
504
505        Ok(())
506    }
507}
508
509#[unstable(feature = "error_reporter", issue = "90172")]
510impl<E> From<E> for Report<E>
511where
512    E: Error,
513{
514    fn from(error: E) -> Self {
515        Report { error, show_backtrace: false, pretty: false }
516    }
517}
518
519#[unstable(feature = "error_reporter", issue = "90172")]
520impl<E> fmt::Display for Report<E>
521where
522    E: Error,
523{
524    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
525        if self.pretty { self.fmt_multiline(f) } else { self.fmt_singleline(f) }
526    }
527}
528
529// This type intentionally outputs the same format for `Display` and `Debug`for
530// situations where you unwrap a `Report` or return it from main.
531#[unstable(feature = "error_reporter", issue = "90172")]
532impl<E> fmt::Debug for Report<E>
533where
534    Report<E>: fmt::Display,
535{
536    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
537        fmt::Display::fmt(self, f)
538    }
539}
540
541/// Wrapper type for indenting the inner source.
542struct Indented<'a, D> {
543    inner: &'a mut D,
544}
545
546impl<T> Write for Indented<'_, T>
547where
548    T: Write,
549{
550    fn write_str(&mut self, s: &str) -> fmt::Result {
551        for (i, line) in s.split('\n').enumerate() {
552            if i > 0 {
553                self.inner.write_char('\n')?;
554                self.inner.write_str("      ")?;
555            }
556
557            self.inner.write_str(line)?;
558        }
559
560        Ok(())
561    }
562}