From d3a2b21a8c34c7b7eea0a001a1412992e3ed2cb7 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 29 Sep 2020 20:08:27 +0200 Subject: Add panic_context module for better panic messages --- crates/stdx/src/lib.rs | 1 + crates/stdx/src/panic_context.rs | 49 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 crates/stdx/src/panic_context.rs (limited to 'crates/stdx') diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs index 273b0f55b..011935cad 100644 --- a/crates/stdx/src/lib.rs +++ b/crates/stdx/src/lib.rs @@ -5,6 +5,7 @@ use std::{ }; mod macros; +pub mod panic_context; #[inline(always)] pub fn is_ci() -> bool { diff --git a/crates/stdx/src/panic_context.rs b/crates/stdx/src/panic_context.rs new file mode 100644 index 000000000..fd232e0cc --- /dev/null +++ b/crates/stdx/src/panic_context.rs @@ -0,0 +1,49 @@ +//! A micro-crate to enhance panic messages with context info. +//! +//! FIXME: upstream to https://github.com/kriomant/panic-context ? + +use std::{cell::RefCell, panic, sync::Once}; + +pub fn enter(context: String) -> impl Drop { + static ONCE: Once = Once::new(); + ONCE.call_once(PanicContext::init); + + with_ctx(|ctx| ctx.push(context)); + PanicContext { _priv: () } +} + +#[must_use] +struct PanicContext { + _priv: (), +} + +impl PanicContext { + fn init() { + let default_hook = panic::take_hook(); + let hook = move |panic_info: &panic::PanicInfo<'_>| { + with_ctx(|ctx| { + if !ctx.is_empty() { + eprintln!("Panic context:"); + for frame in ctx.iter() { + eprintln!("> {}\n", frame) + } + } + default_hook(panic_info) + }) + }; + panic::set_hook(Box::new(hook)) + } +} + +impl Drop for PanicContext { + fn drop(&mut self) { + with_ctx(|ctx| assert!(ctx.pop().is_some())) + } +} + +fn with_ctx(f: impl FnOnce(&mut Vec)) { + thread_local! { + static CTX: RefCell> = RefCell::new(Vec::new()); + } + CTX.with(|ctx| f(&mut *ctx.borrow_mut())) +} -- cgit v1.2.3