1 use crate::chain::Chain; 2 use crate::error::ErrorImpl; 3 use crate::ptr::Ref; 4 use core::fmt::{self, Debug, Write}; 5 6 impl ErrorImpl { display(this: Ref<Self>, f: &mut fmt::Formatter) -> fmt::Result7 pub(crate) unsafe fn display(this: Ref<Self>, f: &mut fmt::Formatter) -> fmt::Result { 8 write!(f, "{}", unsafe { Self::error(this) })?; 9 10 if f.alternate() { 11 let chain = unsafe { Self::chain(this) }; 12 for cause in chain.skip(1) { 13 write!(f, ": {}", cause)?; 14 } 15 } 16 17 Ok(()) 18 } 19 debug(this: Ref<Self>, f: &mut fmt::Formatter) -> fmt::Result20 pub(crate) unsafe fn debug(this: Ref<Self>, f: &mut fmt::Formatter) -> fmt::Result { 21 let error = unsafe { Self::error(this) }; 22 23 if f.alternate() { 24 return Debug::fmt(error, f); 25 } 26 27 write!(f, "{}", error)?; 28 29 if let Some(cause) = error.source() { 30 write!(f, "\n\nCaused by:")?; 31 let multiple = cause.source().is_some(); 32 for (n, error) in Chain::new(cause).enumerate() { 33 writeln!(f)?; 34 let mut indented = Indented { 35 inner: f, 36 number: if multiple { Some(n) } else { None }, 37 started: false, 38 }; 39 write!(indented, "{}", error)?; 40 } 41 } 42 43 #[cfg(any(std_backtrace, feature = "backtrace"))] 44 { 45 use crate::backtrace::BacktraceStatus; 46 47 let backtrace = unsafe { Self::backtrace(this) }; 48 if let BacktraceStatus::Captured = backtrace.status() { 49 let mut backtrace = backtrace.to_string(); 50 write!(f, "\n\n")?; 51 if backtrace.starts_with("stack backtrace:") { 52 // Capitalize to match "Caused by:" 53 backtrace.replace_range(0..1, "S"); 54 } else { 55 // "stack backtrace:" prefix was removed in 56 // https://github.com/rust-lang/backtrace-rs/pull/286 57 writeln!(f, "Stack backtrace:")?; 58 } 59 backtrace.truncate(backtrace.trim_end().len()); 60 write!(f, "{}", backtrace)?; 61 } 62 } 63 64 Ok(()) 65 } 66 } 67 68 struct Indented<'a, D> { 69 inner: &'a mut D, 70 number: Option<usize>, 71 started: bool, 72 } 73 74 impl<T> Write for Indented<'_, T> 75 where 76 T: Write, 77 { write_str(&mut self, s: &str) -> fmt::Result78 fn write_str(&mut self, s: &str) -> fmt::Result { 79 for (i, line) in s.split('\n').enumerate() { 80 if !self.started { 81 self.started = true; 82 match self.number { 83 Some(number) => write!(self.inner, "{: >5}: ", number)?, 84 None => self.inner.write_str(" ")?, 85 } 86 } else if i > 0 { 87 self.inner.write_char('\n')?; 88 if self.number.is_some() { 89 self.inner.write_str(" ")?; 90 } else { 91 self.inner.write_str(" ")?; 92 } 93 } 94 95 self.inner.write_str(line)?; 96 } 97 98 Ok(()) 99 } 100 } 101 102 #[cfg(test)] 103 mod tests { 104 use super::*; 105 106 #[test] one_digit()107 fn one_digit() { 108 let input = "verify\nthis"; 109 let expected = " 2: verify\n this"; 110 let mut output = String::new(); 111 112 Indented { 113 inner: &mut output, 114 number: Some(2), 115 started: false, 116 } 117 .write_str(input) 118 .unwrap(); 119 120 assert_eq!(expected, output); 121 } 122 123 #[test] two_digits()124 fn two_digits() { 125 let input = "verify\nthis"; 126 let expected = " 12: verify\n this"; 127 let mut output = String::new(); 128 129 Indented { 130 inner: &mut output, 131 number: Some(12), 132 started: false, 133 } 134 .write_str(input) 135 .unwrap(); 136 137 assert_eq!(expected, output); 138 } 139 140 #[test] no_digits()141 fn no_digits() { 142 let input = "verify\nthis"; 143 let expected = " verify\n this"; 144 let mut output = String::new(); 145 146 Indented { 147 inner: &mut output, 148 number: None, 149 started: false, 150 } 151 .write_str(input) 152 .unwrap(); 153 154 assert_eq!(expected, output); 155 } 156 } 157