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, "{}", 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
19 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
67struct Indented<'a, D> {
68 inner: &'a mut D,
69 number: Option<usize>,
70 started: bool,
71}
72
73impl<T> Write for Indented<'_, T>
74where
75 T: Write,
76{
77 fn write_str(&mut self, s: &str) -> fmt::Result {
78 for (i: usize, line: &str) in s.split('\n').enumerate() {
79 if !self.started {
80 self.started = true;
81 match self.number {
82 Some(number: usize) => 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)]
102mod tests {
103 use super::*;
104
105 #[test]
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]
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]
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