1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
use backtrace;
use std::{fmt, path};

/// A backtrace starting from the beginning of the thread.
///
/// Backtrace functionality is currently **enabled**. Please review
/// [the feature flags](crate::guide::feature_flags) to disable it.
#[derive(Debug)]
pub struct Backtrace(backtrace::Backtrace);

impl crate::GenerateBacktrace for Backtrace {
    // Inlining in an attempt to remove this function from the backtrace
    #[inline(always)]
    fn generate() -> Self {
        Backtrace(backtrace::Backtrace::new())
    }

    fn as_backtrace(&self) -> Option<&Backtrace> {
        Some(self)
    }
}

impl fmt::Display for Backtrace {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let frames = self.0.frames();
        let width = (frames.len() as f32).log10().floor() as usize + 1;

        for (index, frame) in frames.iter().enumerate() {
            let mut symbols = frame.symbols().iter().map(SymbolDisplay);

            if let Some(symbol) = symbols.next() {
                writeln!(
                    f,
                    "{index:width$} {name}",
                    index = index,
                    width = width,
                    name = symbol.name()
                )?;
                if let Some(location) = symbol.location() {
                    writeln!(
                        f,
                        "{index:width$} {location}",
                        index = "",
                        width = width,
                        location = location
                    )?;
                }

                for symbol in symbols {
                    writeln!(
                        f,
                        "{index:width$} {name}",
                        index = "",
                        width = width,
                        name = symbol.name()
                    )?;
                    if let Some(location) = symbol.location() {
                        writeln!(
                            f,
                            "{index:width$} {location}",
                            index = "",
                            width = width,
                            location = location
                        )?;
                    }
                }
            }
        }

        Ok(())
    }
}

struct SymbolDisplay<'a>(&'a backtrace::BacktraceSymbol);

impl<'a> SymbolDisplay<'a> {
    fn name(&self) -> SymbolNameDisplay<'a> {
        SymbolNameDisplay(self.0)
    }

    fn location(&self) -> Option<SymbolLocationDisplay<'a>> {
        self.0.filename().map(|f| SymbolLocationDisplay(self.0, f))
    }
}

struct SymbolNameDisplay<'a>(&'a backtrace::BacktraceSymbol);

impl<'a> fmt::Display for SymbolNameDisplay<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.0.name() {
            Some(n) => write!(f, "{}", n)?,
            None => write!(f, "<unknown>")?,
        }

        Ok(())
    }
}

struct SymbolLocationDisplay<'a>(&'a backtrace::BacktraceSymbol, &'a path::Path);

impl<'a> fmt::Display for SymbolLocationDisplay<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.1.display())?;
        if let Some(l) = self.0.lineno() {
            write!(f, ":{}", l)?;
        }

        Ok(())
    }
}