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 { |
7 | 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 | |
20 | 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 | { |
79 | fn write_str(&mut self, s: &str) -> fmt::Result { |
80 | for (i: usize, line: &str) in s.split(' \n' ).enumerate() { |
81 | if !self.started { |
82 | self.started = true; |
83 | match self.number { |
84 | Some(number: usize) => 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 ] |
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 ] |
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 ] |
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 | |