use crate::chain::Chain; use crate::error::ErrorImpl; use crate::ptr::Ref; use core::fmt::{self, Debug, Write}; impl ErrorImpl { pub(crate) unsafe fn display(this: Ref, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", Self::error(this))?; if f.alternate() { for cause in Self::chain(this).skip(1) { write!(f, ": {}", cause)?; } } Ok(()) } pub(crate) unsafe fn debug(this: Ref, f: &mut fmt::Formatter) -> fmt::Result { let error = Self::error(this); if f.alternate() { return Debug::fmt(error, f); } 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::new(cause).enumerate() { writeln!(f)?; let mut indented = Indented { inner: f, number: if multiple { Some(n) } else { None }, started: false, }; write!(indented, "{}", error)?; } } #[cfg(any(backtrace, feature = "backtrace"))] { use crate::backtrace::BacktraceStatus; let backtrace = Self::backtrace(this); if let BacktraceStatus::Captured = backtrace.status() { let mut backtrace = backtrace.to_string(); write!(f, "\n\n")?; if backtrace.starts_with("stack backtrace:") { // Capitalize to match "Caused by:" backtrace.replace_range(0..1, "S"); } else { // "stack backtrace:" prefix was removed in // https://github.com/rust-lang/backtrace-rs/pull/286 writeln!(f, "Stack backtrace:")?; } backtrace.truncate(backtrace.trim_end().len()); write!(f, "{}", backtrace)?; } } Ok(()) } } struct Indented<'a, D> { inner: &'a mut D, number: Option, started: bool, } impl Write for Indented<'_, T> where T: Write, { 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(()) } } #[cfg(test)] mod tests { use super::*; #[test] fn one_digit() { let input = "verify\nthis"; let expected = " 2: verify\n this"; let mut output = String::new(); Indented { inner: &mut output, number: Some(2), started: false, } .write_str(input) .unwrap(); assert_eq!(expected, output); } #[test] fn two_digits() { let input = "verify\nthis"; let expected = " 12: verify\n this"; let mut output = String::new(); Indented { inner: &mut output, number: Some(12), started: false, } .write_str(input) .unwrap(); assert_eq!(expected, output); } #[test] fn no_digits() { let input = "verify\nthis"; let expected = " verify\n this"; let mut output = String::new(); Indented { inner: &mut output, number: None, started: false, } .write_str(input) .unwrap(); assert_eq!(expected, output); } }