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