error.rs - source
Description: Source of the Rust file `library/std/src/error.rs`.

#
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}