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