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