use std::{backtrace::Backtrace, panic::PanicHookInfo, sync::Once};
use crate::{
panic_data::PanicLocation,
thread_local_catch_stack::{CaptureBacktrace, THREAD_LOCAL_CATCH_STACK},
};
type PanicHook = Box<dyn Fn(&PanicHookInfo<'_>) + Send + Sync>;
pub fn install_if_not_installed() -> Result<(), ()> {
static CHILLPILL_HOOK_INSTALLED: Once = Once::new();
if std::thread::panicking() {
return Err(());
}
CHILLPILL_HOOK_INSTALLED.call_once(|| {
let old_hook = std::panic::take_hook();
let new_hook = Box::new(make_chillpill_panic_hook(old_hook));
std::panic::set_hook(new_hook);
});
Ok(())
}
fn make_chillpill_panic_hook(
previous_hook: PanicHook,
) -> impl Fn(&PanicHookInfo<'_>) + Send + Sync {
move |info| {
THREAD_LOCAL_CATCH_STACK.with_borrow_mut(|stack| {
match stack.last_mut() {
Some(top_frame) => {
top_frame.location = info.location().map(|location| PanicLocation {
file: location.file().to_string(),
line: location.line(),
col: location.column(),
});
top_frame.backtrace = match top_frame.capture_backtrace {
CaptureBacktrace::Always => Backtrace::force_capture(),
CaptureBacktrace::Default => Backtrace::capture(),
CaptureBacktrace::Never => Backtrace::disabled(),
};
}
None => previous_hook(info),
}
});
}
}