• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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             use alloc::string::ToString;
47 
48             let backtrace = unsafe { Self::backtrace(this) };
49             if let BacktraceStatus::Captured = backtrace.status() {
50                 let mut backtrace = backtrace.to_string();
51                 write!(f, "\n\n")?;
52                 if backtrace.starts_with("stack backtrace:") {
53                     // Capitalize to match "Caused by:"
54                     backtrace.replace_range(0..1, "S");
55                 } else {
56                     // "stack backtrace:" prefix was removed in
57                     // https://github.com/rust-lang/backtrace-rs/pull/286
58                     writeln!(f, "Stack backtrace:")?;
59                 }
60                 backtrace.truncate(backtrace.trim_end().len());
61                 write!(f, "{}", backtrace)?;
62             }
63         }
64 
65         Ok(())
66     }
67 }
68 
69 struct Indented<'a, D> {
70     inner: &'a mut D,
71     number: Option<usize>,
72     started: bool,
73 }
74 
75 impl<T> Write for Indented<'_, T>
76 where
77     T: Write,
78 {
write_str(&mut self, s: &str) -> fmt::Result79     fn write_str(&mut self, s: &str) -> fmt::Result {
80         for (i, line) in s.split('\n').enumerate() {
81             if !self.started {
82                 self.started = true;
83                 match self.number {
84                     Some(number) => write!(self.inner, "{: >5}: ", number)?,
85                     None => self.inner.write_str("    ")?,
86                 }
87             } else if i > 0 {
88                 self.inner.write_char('\n')?;
89                 if self.number.is_some() {
90                     self.inner.write_str("       ")?;
91                 } else {
92                     self.inner.write_str("    ")?;
93                 }
94             }
95 
96             self.inner.write_str(line)?;
97         }
98 
99         Ok(())
100     }
101 }
102 
103 #[cfg(test)]
104 mod tests {
105     use super::*;
106     use alloc::string::String;
107 
108     #[test]
one_digit()109     fn one_digit() {
110         let input = "verify\nthis";
111         let expected = "    2: verify\n       this";
112         let mut output = String::new();
113 
114         Indented {
115             inner: &mut output,
116             number: Some(2),
117             started: false,
118         }
119         .write_str(input)
120         .unwrap();
121 
122         assert_eq!(expected, output);
123     }
124 
125     #[test]
two_digits()126     fn two_digits() {
127         let input = "verify\nthis";
128         let expected = "   12: verify\n       this";
129         let mut output = String::new();
130 
131         Indented {
132             inner: &mut output,
133             number: Some(12),
134             started: false,
135         }
136         .write_str(input)
137         .unwrap();
138 
139         assert_eq!(expected, output);
140     }
141 
142     #[test]
no_digits()143     fn no_digits() {
144         let input = "verify\nthis";
145         let expected = "    verify\n    this";
146         let mut output = String::new();
147 
148         Indented {
149             inner: &mut output,
150             number: None,
151             started: false,
152         }
153         .write_str(input)
154         .unwrap();
155 
156         assert_eq!(expected, output);
157     }
158 }
159