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