]> git.lizzy.rs Git - rust.git/commitdiff
Add Frames iterator for Backtrace
authorSean Chen <seanchen11235@gmail.com>
Wed, 13 Jan 2021 23:54:24 +0000 (17:54 -0600)
committerSean Chen <seanchen11235@gmail.com>
Sat, 23 Jan 2021 17:56:33 +0000 (11:56 -0600)
library/std/src/backtrace.rs
library/std/src/backtrace/tests.rs

index 95e18ef2a654343b71f3f96063b956a11c2c94fa..0aae4674b29423c763025113ecf236b8591f4dd4 100644 (file)
@@ -147,11 +147,14 @@ fn _assert<T: Send + Sync>() {}
     _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)]
@@ -196,6 +199,14 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
+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
@@ -353,6 +364,14 @@ pub fn status(&self) -> BacktraceStatus {
     }
 }
 
+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 {
index 31cf0f702185c9ca47e0df66821f302b673d0334..f5da93f93fd932b0e7ed6134e1893c18b6d02d2a 100644 (file)
@@ -1,48 +1,52 @@
 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(),
         })),
     };
 
@@ -58,3 +62,34 @@ fn test_debug() {
     // 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));
+}