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 f.write_fmt(format_args!("{0}", unsafe { Self::error(this) }))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 f.write_fmt(format_args!(": {0}", cause))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 f.write_fmt(format_args!("{0}", error))write!(f, "{}", error)?;
28 unsafe { Self::fmt_location(this, f) }?;
29
30 if let Some(cause) = error.source() {
31 f.write_fmt(format_args!("\n\nCaused by:"))write!(f, "\n\nCaused by:")?;
32 let multiple = cause.source().is_some();
33 let mut context = unsafe { Self::context(this) };
34 for (n, error) in Chain::new(cause).enumerate() {
35 f.write_fmt(format_args!("\n"))writeln!(f)?;
36 let mut indented = Indented {
37 inner: f,
38 number: if multiple { Some(n) } else { None },
39 started: false,
40 };
41 indented.write_fmt(format_args!("{0}", error))write!(indented, "{}", error)?;
42 if let Some(layer) = context {
43 unsafe { Self::fmt_location(layer, indented.inner) }?;
45 context = unsafe { Self::context(layer) };
46 }
47 }
48 }
49
50 #[cfg(feature = "std")]
51 {
52 use alloc::string::ToString;
53 use std::backtrace::BacktraceStatus;
54
55 let backtrace = unsafe { Self::backtrace(this) };
56 if let BacktraceStatus::Captured = backtrace.status() {
57 let mut backtrace = backtrace.to_string();
58 f.write_fmt(format_args!("\n\n"))write!(f, "\n\n")?;
59 if backtrace.starts_with("stack backtrace:") {
60 backtrace.replace_range(0..1, "S");
62 } else {
63 f.write_fmt(format_args!("Stack backtrace:\n"))writeln!(f, "Stack backtrace:")?;
66 }
67 backtrace.truncate(backtrace.trim_end().len());
68 f.write_fmt(format_args!("{0}", backtrace))write!(f, "{}", backtrace)?;
69 }
70 }
71
72 Ok(())
73 }
74
75 unsafe fn fmt_location(this: Ref<Self>, f: &mut fmt::Formatter) -> fmt::Result {
76 let location = unsafe { Self::location(this) };
77 f.write_fmt(format_args!(" [{0}:{1}]", location.file(), location.line()))write!(f, " [{}:{}]", location.file(), location.line())
78 }
79}
80
81struct Indented<'a, D> {
82 inner: &'a mut D,
83 number: Option<usize>,
84 started: bool,
85}
86
87impl<T> Write for Indented<'_, T>
88where
89 T: Write,
90{
91 fn write_str(&mut self, s: &str) -> fmt::Result {
92 for (i, line) in s.split('\n').enumerate() {
93 if !self.started {
94 self.started = true;
95 match self.number {
96 Some(number) => self.inner.write_fmt(format_args!("{0: >5}: ", number))write!(self.inner, "{: >5}: ", number)?,
97 None => self.inner.write_str(" ")?,
98 }
99 } else if i > 0 {
100 self.inner.write_char('\n')?;
101 if self.number.is_some() {
102 self.inner.write_str(" ")?;
103 } else {
104 self.inner.write_str(" ")?;
105 }
106 }
107
108 self.inner.write_str(line)?;
109 }
110
111 Ok(())
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118 use alloc::string::String;
119
120 #[test]
121 fn one_digit() {
122 let input = "verify\nthis";
123 let expected = " 2: verify\n this";
124 let mut output = String::new();
125
126 Indented {
127 inner: &mut output,
128 number: Some(2),
129 started: false,
130 }
131 .write_str(input)
132 .unwrap();
133
134 assert_eq!(expected, output);
135 }
136
137 #[test]
138 fn two_digits() {
139 let input = "verify\nthis";
140 let expected = " 12: verify\n this";
141 let mut output = String::new();
142
143 Indented {
144 inner: &mut output,
145 number: Some(12),
146 started: false,
147 }
148 .write_str(input)
149 .unwrap();
150
151 assert_eq!(expected, output);
152 }
153
154 #[test]
155 fn no_digits() {
156 let input = "verify\nthis";
157 let expected = " verify\n this";
158 let mut output = String::new();
159
160 Indented {
161 inner: &mut output,
162 number: None,
163 started: false,
164 }
165 .write_str(input)
166 .unwrap();
167
168 assert_eq!(expected, output);
169 }
170}