snafu/
backtrace_shim.rs

1use backtrace;
2use std::{fmt, path};
3
4/// A backtrace starting from the beginning of the thread.
5///
6/// Backtrace functionality is currently **enabled**. Please review
7/// [the feature flags](crate::guide::feature_flags) to disable it.
8#[derive(Debug)]
9pub struct Backtrace(backtrace::Backtrace);
10
11impl crate::GenerateImplicitData for Backtrace {
12    // Inlining in an attempt to remove this function from the backtrace
13    #[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}