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