_assert::<Backtrace>();
}
-struct BacktraceFrame {
+/// A single frame of a backtrace.
+#[unstable(feature = "backtrace_frames", issue = "79676")]
+pub struct BacktraceFrame {
frame: RawFrame,
symbols: Vec<BacktraceSymbol>,
}
+#[derive(Debug)]
enum RawFrame {
Actual(backtrace_rs::Frame),
#[cfg(test)]
}
}
+impl fmt::Debug for BacktraceFrame {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut dbg = fmt.debug_list();
+ dbg.entries(&self.symbols);
+ dbg.finish()
+ }
+}
+
impl fmt::Debug for BacktraceSymbol {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
// FIXME: improve formatting: https://github.com/rust-lang/rust/issues/65280
}
}
+impl<'a> Backtrace {
+ /// Returns an iterator over the backtrace frames.
+ #[unstable(feature = "backtrace_frames", issue = "79676")]
+ pub fn frames(&'a self) -> &'a [BacktraceFrame] {
+ if let Inner::Captured(c) = &self.inner { &c.force().frames } else { &[] }
+ }
+}
+
impl fmt::Display for Backtrace {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let capture = match &self.inner {
use super::*;
+fn generate_fake_frames() -> Vec<BacktraceFrame> {
+ vec![
+ BacktraceFrame {
+ frame: RawFrame::Fake,
+ symbols: vec![BacktraceSymbol {
+ name: Some(b"std::backtrace::Backtrace::create".to_vec()),
+ filename: Some(BytesOrWide::Bytes(b"rust/backtrace.rs".to_vec())),
+ lineno: Some(100),
+ colno: None,
+ }],
+ },
+ BacktraceFrame {
+ frame: RawFrame::Fake,
+ symbols: vec![BacktraceSymbol {
+ name: Some(b"__rust_maybe_catch_panic".to_vec()),
+ filename: None,
+ lineno: None,
+ colno: None,
+ }],
+ },
+ BacktraceFrame {
+ frame: RawFrame::Fake,
+ symbols: vec![
+ BacktraceSymbol {
+ name: Some(b"std::rt::lang_start_internal".to_vec()),
+ filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())),
+ lineno: Some(300),
+ colno: Some(5),
+ },
+ BacktraceSymbol {
+ name: Some(b"std::rt::lang_start".to_vec()),
+ filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())),
+ lineno: Some(400),
+ colno: None,
+ },
+ ],
+ },
+ ]
+}
+
#[test]
fn test_debug() {
let backtrace = Backtrace {
inner: Inner::Captured(LazilyResolvedCapture::new(Capture {
actual_start: 1,
resolved: true,
- frames: vec![
- BacktraceFrame {
- frame: RawFrame::Fake,
- symbols: vec![BacktraceSymbol {
- name: Some(b"std::backtrace::Backtrace::create".to_vec()),
- filename: Some(BytesOrWide::Bytes(b"rust/backtrace.rs".to_vec())),
- lineno: Some(100),
- colno: None,
- }],
- },
- BacktraceFrame {
- frame: RawFrame::Fake,
- symbols: vec![BacktraceSymbol {
- name: Some(b"__rust_maybe_catch_panic".to_vec()),
- filename: None,
- lineno: None,
- colno: None,
- }],
- },
- BacktraceFrame {
- frame: RawFrame::Fake,
- symbols: vec![
- BacktraceSymbol {
- name: Some(b"std::rt::lang_start_internal".to_vec()),
- filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())),
- lineno: Some(300),
- colno: Some(5),
- },
- BacktraceSymbol {
- name: Some(b"std::rt::lang_start".to_vec()),
- filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())),
- lineno: Some(400),
- colno: None,
- },
- ],
- },
- ],
+ frames: generate_fake_frames(),
})),
};
// Format the backtrace a second time, just to make sure lazily resolved state is stable
assert_eq!(format!("{:#?}", backtrace), expected);
}
+
+#[test]
+fn test_frames() {
+ let backtrace = Backtrace {
+ inner: Inner::Captured(LazilyResolvedCapture::new(Capture {
+ actual_start: 1,
+ resolved: true,
+ frames: generate_fake_frames(),
+ })),
+ };
+
+ let frames = backtrace.frames();
+
+ #[rustfmt::skip]
+ let expected = vec![
+ "[
+ { fn: \"std::backtrace::Backtrace::create\", file: \"rust/backtrace.rs\", line: 100 },
+]",
+ "[
+ { fn: \"__rust_maybe_catch_panic\" },
+]",
+ "[
+ { fn: \"std::rt::lang_start_internal\", file: \"rust/rt.rs\", line: 300 },
+ { fn: \"std::rt::lang_start\", file: \"rust/rt.rs\", line: 400 },
+]"
+ ];
+
+ let mut iter = frames.iter().zip(expected.iter());
+
+ assert!(iter.all(|(f, e)| format!("{:#?}", f) == *e));
+}