1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
// ////////////////////////////////////////////////////////////////////////////////////////////////
// All code in this file was extracted from:
// * https://github.com/dtolnay/anyhow/blob/0ba6408b5ef508c3dfc95797d21cfbdca9dd64ee/src/fmt.rs
// * https://github.com/dtolnay/anyhow/blob/fa9bcc0457a2e51593b874cc2f8bcb5608ad43fe/src/chain.rs
//
// Author: David Tolnay <dtolnay@gmail.com> and contributors to the `anyhow` project.
// ////////////////////////////////////////////////////////////////////////////////////////////////
use std::error::Error;
use std::fmt::{self, Write};
/// Write out the [`Error`] message and chain.
///
/// Please see the [`crate`] documentation for a more complete example.
///
/// ```rust
/// use std::fmt::{self, Write};
///
/// pub enum MyError {
/// Variant1(/* … */),
/// Variant2(/* … */),
/// // …
/// }
///
/// impl fmt::Debug for MyError {
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// # /*
/// pretty_error_debug::pretty_error_debug(self, f)
/// # */ Ok(())
/// }
/// }
///
/// // TODO: implement `std::fmt::Display` and `std::error::Error`.
/// ```
///
/// # Errors
///
/// Fails if writing to the `f` argument failed.
///
pub fn pretty_error_debug(error: &dyn Error, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", error)?;
if let Some(cause) = error.source() {
write!(f, "\n\nCaused by:")?;
let multiple = cause.source().is_some();
for (n, error) in Chain(Some(cause)).enumerate() {
writeln!(f)?;
let mut indented = Indented {
inner: f,
number: if multiple { Some(n + 1) } else { None },
started: false,
};
write!(indented, "{}", error)?;
}
}
Ok(())
}
struct Chain<'a>(Option<&'a dyn Error>);
impl<'a> Iterator for Chain<'a> {
type Item = &'a dyn Error;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let error = self.0?;
self.0 = error.source();
Some(error)
}
}
struct Indented<'a, 'b: 'a> {
inner: &'a mut fmt::Formatter<'b>,
number: Option<usize>,
started: bool,
}
impl<'a, 'b: 'a> fmt::Write for Indented<'a, 'b> {
fn write_str(&mut self, s: &str) -> fmt::Result {
for (i, line) in s.split('\n').enumerate() {
if !self.started {
self.started = true;
match self.number {
Some(number) => write!(self.inner, "{: >5}: ", number)?,
None => self.inner.write_str(" ")?,
}
} else if i > 0 {
self.inner.write_char('\n')?;
if self.number.is_some() {
self.inner.write_str(" ")?;
} else {
self.inner.write_str(" ")?;
}
}
self.inner.write_str(line)?;
}
Ok(())
}
}