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}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy