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}