1use backtrace;
2use std::{fmt, path};
3
4#[derive(Debug)]
9pub struct Backtrace(backtrace::Backtrace);
10
11impl crate::GenerateImplicitData for Backtrace {
12 #[inline(always)]
14 fn generate() -> Self {
15 Backtrace(backtrace::Backtrace::new())
16 }
17}
18
19impl crate::AsBacktrace for Backtrace {
20 fn as_backtrace(&self) -> Option<&Backtrace> {
21 Some(self)
22 }
23}
24
25impl fmt::Display for Backtrace {
26 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
27 let frames = self.0.frames();
28 let width = (frames.len() as f32).log10().floor() as usize + 1;
29
30 for (index, frame) in frames.iter().enumerate() {
31 let mut symbols = frame.symbols().iter().map(SymbolDisplay);
32
33 if let Some(symbol) = symbols.next() {
34 writeln!(
35 f,
36 "{index:width$} {name}",
37 index = index,
38 width = width,
39 name = symbol.name()
40 )?;
41 if let Some(location) = symbol.location() {
42 writeln!(
43 f,
44 "{index:width$} {location}",
45 index = "",
46 width = width,
47 location = location
48 )?;
49 }
50
51 for symbol in symbols {
52 writeln!(
53 f,
54 "{index:width$} {name}",
55 index = "",
56 width = width,
57 name = symbol.name()
58 )?;
59 if let Some(location) = symbol.location() {
60 writeln!(
61 f,
62 "{index:width$} {location}",
63 index = "",
64 width = width,
65 location = location
66 )?;
67 }
68 }
69 }
70 }
71
72 Ok(())
73 }
74}
75
76struct SymbolDisplay<'a>(&'a backtrace::BacktraceSymbol);
77
78impl<'a> SymbolDisplay<'a> {
79 fn name(&self) -> SymbolNameDisplay<'a> {
80 SymbolNameDisplay(self.0)
81 }
82
83 fn location(&self) -> Option<SymbolLocationDisplay<'a>> {
84 self.0.filename().map(|f| SymbolLocationDisplay(self.0, f))
85 }
86}
87
88struct SymbolNameDisplay<'a>(&'a backtrace::BacktraceSymbol);
89
90impl<'a> fmt::Display for SymbolNameDisplay<'a> {
91 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
92 match self.0.name() {
93 Some(n) => write!(f, "{}", n)?,
94 None => write!(f, "<unknown>")?,
95 }
96
97 Ok(())
98 }
99}
100
101struct SymbolLocationDisplay<'a>(&'a backtrace::BacktraceSymbol, &'a path::Path);
102
103impl<'a> fmt::Display for SymbolLocationDisplay<'a> {
104 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
105 write!(f, "{}", self.1.display())?;
106 if let Some(l) = self.0.lineno() {
107 write!(f, ":{}", l)?;
108 }
109
110 Ok(())
111 }
112}