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" )] |
5 | pub use core::error::Error; |
6 | #[unstable (feature = "error_generic_member_access" , issue = "99301" )] |
7 | pub use core::error::{Request, request_ref, request_value}; |
8 | |
9 | use crate::backtrace::Backtrace; |
10 | use 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" )] |
221 | pub 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 | |
230 | impl<E> Report<E> |
231 | where |
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 | |
241 | impl<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 | |
445 | impl<E> Report<E> |
446 | where |
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" )] |
510 | impl<E> From<E> for Report<E> |
511 | where |
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" )] |
520 | impl<E> fmt::Display for Report<E> |
521 | where |
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" )] |
532 | impl<E> fmt::Debug for Report<E> |
533 | where |
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. |
542 | struct Indented<'a, D> { |
543 | inner: &'a mut D, |
544 | } |
545 | |
546 | impl<T> Write for Indented<'_, T> |
547 | where |
548 | T: Write, |
549 | { |
550 | fn write_str(&mut self, s: &str) -> fmt::Result { |
551 | for (i: usize, line: &str) 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 | } |
563 | |