1use crate::chain::Chain;
2use crate::error::ErrorImpl;
3use crate::ptr::Ref;
4use core::fmt::{self, Debug, Write};
5
6impl 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 backtrace.replace_range(0..1, "S");
55 } else {
56 writeln!(f, "Stack backtrace:")?;
59 }
60 backtrace.truncate(backtrace.trim_end().len());
61 write!(f, "{}", backtrace)?;
62 }
63 }
64
65 Ok(())
66 }
67}
68
69struct Indented<'a, D> {
70 inner: &'a mut D,
71 number: Option<usize>,
72 started: bool,
73}
74
75impl<T> Write for Indented<'_, T>
76where
77 T: Write,
78{
79 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)]
104mod 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}