1 | #![doc = include_str!("../../core/src/error.md" )] |
2 | #![stable (feature = "rust1" , since = "1.0.0" )] |
3 | |
4 | #[cfg (test)] |
5 | mod tests; |
6 | |
7 | use crate::backtrace::Backtrace; |
8 | use crate::fmt::{self, Write}; |
9 | |
10 | #[stable (feature = "rust1" , since = "1.0.0" )] |
11 | pub use core::error::Error; |
12 | #[unstable (feature = "error_generic_member_access" , issue = "99301" )] |
13 | pub 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" )] |
224 | pub 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 | |
233 | impl<E> Report<E> |
234 | where |
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 | |
244 | impl<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 | |
448 | impl<E> Report<E> |
449 | where |
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" )] |
518 | impl<E> From<E> for Report<E> |
519 | where |
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" )] |
528 | impl<E> fmt::Display for Report<E> |
529 | where |
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" )] |
540 | impl<E> fmt::Debug for Report<E> |
541 | where |
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. |
550 | struct Indented<'a, D> { |
551 | inner: &'a mut D, |
552 | } |
553 | |
554 | impl<T> Write for Indented<'_, T> |
555 | where |
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 | |