diff --git a/crates/stdx/src/panic_context.rs b/crates/stdx/src/panic_context.rs index 4ec74c0742..a35d50b78d 100644 --- a/crates/stdx/src/panic_context.rs +++ b/crates/stdx/src/panic_context.rs @@ -1,48 +1,44 @@ //! A micro-crate to enhance panic messages with context info. -//! -//! FIXME: upstream to ? use std::{cell::RefCell, panic, sync::Once}; -pub fn enter(context: String) -> PanicContext { - static ONCE: Once = Once::new(); - ONCE.call_once(PanicContext::init); - - with_ctx(|ctx| ctx.push(context)); - PanicContext { _priv: () } -} - +/// Dummy for leveraging RAII cleanup to pop frames. #[must_use] pub struct PanicContext { + // prevent arbitrary construction _priv: (), } -impl PanicContext { - #[allow(clippy::print_stderr)] - fn init() { - let default_hook = panic::take_hook(); - #[allow(deprecated)] - let hook = move |panic_info: &panic::PanicInfo<'_>| { - with_ctx(|ctx| { - if !ctx.is_empty() { - eprintln!("Panic context:"); - for frame in ctx.iter() { - eprintln!("> {frame}\n"); - } - } - 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())); } } +pub fn enter(frame: String) -> PanicContext { + #[allow(clippy::print_stderr)] + fn set_hook() { + let default_hook = panic::take_hook(); + panic::set_hook(Box::new(move |panic_info| { + with_ctx(|ctx| { + if !ctx.is_empty() { + eprintln!("Panic context:"); + for frame in ctx.iter() { + eprintln!("> {frame}\n"); + } + } + }); + default_hook(panic_info); + })); + } + + static SET_HOOK: Once = Once::new(); + SET_HOOK.call_once(set_hook); + + with_ctx(|ctx| ctx.push(frame)); + PanicContext { _priv: () } +} + fn with_ctx(f: impl FnOnce(&mut Vec)) { thread_local! { static CTX: RefCell> = const { RefCell::new(Vec::new()) };