use core::fmt::{self, Write};
use crate::Error;
pub fn pretty_error_debug(error: &dyn Error, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(error, f)?;
if let Some(cause) = error.source() {
f.write_str("\n\nCaused by:")?;
let multiple = cause.source().is_some();
for (n, error) in Chain(Some(cause)).enumerate() {
f.write_char('\n')?;
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> {
inner: &'a mut fmt::Formatter<'b>,
number: Option<usize>,
started: bool,
}
impl fmt::Write for Indented<'_, '_> {
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, "{number: >5}: ")?,
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(())
}
}