Skip to content

Commit 46644de

Browse files
author
Andrew DeFilippo
committed
Implemented Debug newtypes for BacktraceFrame and BacktraceSymbol
1 parent d153f36 commit 46644de

File tree

3 files changed

+67
-34
lines changed

3 files changed

+67
-34
lines changed

src/capture.rs

+9-33
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
use crate::PrintFmt;
2-
use crate::{resolve, resolve_frame, trace, BacktraceFmt, Symbol, SymbolName};
1+
use crate::{resolve, resolve_frame, trace, DebugBacktraceFrame, Symbol, SymbolName};
32
use std::ffi::c_void;
43
use std::fmt;
54
use std::path::{Path, PathBuf};
@@ -322,41 +321,18 @@ impl BacktraceSymbol {
322321
pub fn lineno(&self) -> Option<u32> {
323322
self.lineno
324323
}
324+
325+
/// Returns whether the BacktraceSymbol has any data associated with it
326+
pub fn is_empty(&self) -> bool {
327+
self.name.is_none() && self.addr.is_none() && self.filename.is_none() && self.lineno.is_none()
328+
}
325329
}
326330

327331
impl fmt::Debug for Backtrace {
328332
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
329-
let full = fmt.alternate();
330-
let (frames, style) = if full {
331-
(&self.frames[..], PrintFmt::Full)
332-
} else {
333-
(&self.frames[self.actual_start_index..], PrintFmt::Short)
334-
};
335-
336-
// When printing paths we try to strip the cwd if it exists, otherwise
337-
// we just print the path as-is. Note that we also only do this for the
338-
// short format, because if it's full we presumably want to print
339-
// everything.
340-
let cwd = std::env::current_dir();
341-
let mut print_path = move |fmt: &mut fmt::Formatter, path: crate::BytesOrWideString| {
342-
let path = path.into_path_buf();
343-
if !full {
344-
if let Ok(cwd) = &cwd {
345-
if let Ok(suffix) = path.strip_prefix(cwd) {
346-
return fmt::Display::fmt(&suffix.display(), fmt);
347-
}
348-
}
349-
}
350-
fmt::Display::fmt(&path.display(), fmt)
351-
};
352-
353-
let mut f = BacktraceFmt::new(fmt, style, &mut print_path);
354-
f.add_context()?;
355-
for frame in frames {
356-
f.frame().backtrace_frame(frame)?;
357-
}
358-
f.finish()?;
359-
Ok(())
333+
fmt.debug_list()
334+
.entries(self.frames().iter().flat_map(|frame| DebugBacktraceFrame::new(frame).symbols_skip_empty()))
335+
.finish()
360336
}
361337
}
362338

src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ mod types;
8787
pub use crate::symbolize::clear_symbol_cache;
8888

8989
mod print;
90-
pub use print::{BacktraceFmt, BacktraceFrameFmt, PrintFmt};
90+
pub use print::{BacktraceFmt, BacktraceFrameFmt, DebugBacktraceFrame, PrintFmt};
9191

9292
cfg_if::cfg_if! {
9393
if #[cfg(feature = "std")] {

src/print.rs

+57
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,63 @@ const HEX_WIDTH: usize = 2 + 2 * core::mem::size_of::<usize>();
77
#[cfg(target_os = "fuchsia")]
88
mod fuchsia;
99

10+
/// A formatter for BacktraceFrames.
11+
pub struct DebugBacktraceFrame<'a>(&'a crate::BacktraceFrame);
12+
13+
impl<'a> DebugBacktraceFrame<'a> {
14+
#[allow(missing_docs)]
15+
pub fn new(frame: &'a crate::BacktraceFrame) -> Self {
16+
Self(frame)
17+
}
18+
19+
/// Iterates over symbols in wrapped BacktraceFrame, and wraps them in DebugBacktraceSymbols.
20+
pub fn symbols(&self) -> std::vec::Vec<DebugBacktraceSymbol<'a>> {
21+
self.0.symbols().iter().map(DebugBacktraceSymbol::new).collect()
22+
}
23+
24+
/// Same as symbols(), but filters out symbols that have no data
25+
pub fn symbols_skip_empty(&self) -> std::vec::Vec<DebugBacktraceSymbol<'a>> {
26+
self.0.symbols().iter().filter(|symbol| !symbol.is_empty()).map(DebugBacktraceSymbol::new).collect()
27+
}
28+
}
29+
30+
impl<'a> fmt::Debug for DebugBacktraceFrame<'a> {
31+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32+
let mut d = f.debug_list();
33+
if !self.0.symbols().is_empty() {
34+
d.entries(self.0.symbols().iter().map(|symbol| DebugBacktraceSymbol::new(symbol)));
35+
}
36+
d.finish()
37+
}
38+
}
39+
40+
/// A formatter for BacktraceSymbols.
41+
pub struct DebugBacktraceSymbol<'a>(&'a crate::BacktraceSymbol);
42+
43+
impl<'a> DebugBacktraceSymbol<'a> {
44+
/// Create a new DebugBacktraceSymbol.
45+
pub fn new(frame: &'a crate::BacktraceSymbol) -> Self {
46+
Self(frame)
47+
}
48+
}
49+
50+
impl<'a> fmt::Debug for DebugBacktraceSymbol<'a> {
51+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
52+
if self.0.name().is_none() { return Ok(()); }
53+
let mut d = f.debug_map();
54+
let name = self.0.name();
55+
let file = self.0
56+
.filename()
57+
.and_then(|p| Some(BytesOrWideString::Bytes(p.to_str()?.as_bytes())));
58+
let line = self.0.lineno();
59+
60+
if let Some(ref name) = name { d.entry(&"function", name); }
61+
if let Some(ref file) = file { d.entry(&"file", file); }
62+
if let Some(ref line) = line { d.entry(&"line", line); }
63+
d.finish()
64+
}
65+
}
66+
1067
/// A formatter for backtraces.
1168
///
1269
/// This type can be used to print a backtrace regardless of where the backtrace

0 commit comments

Comments
 (0)