Source code
Revision control
Copy as Markdown
Other Tools
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<Self>, 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<Self>, 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
writeln!(f, "Stack backtrace:")?;
}
backtrace.truncate(backtrace.trim_end().len());
write!(f, "{}", backtrace)?;
}
}
Ok(())
}
}
struct Indented<'a, D> {
inner: &'a mut D,
number: Option<usize>,
started: bool,
}
impl<T> 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);
}
}