use std::cell::RefCell;
thread_local! {
static LAST_UNCAUGHT_EXCEPTION: RefCell<Option<String>> = const { RefCell::new(None) };
}
pub fn clear() {
LAST_UNCAUGHT_EXCEPTION.with(|c| {
c.borrow_mut().take();
});
}
#[must_use]
pub fn take() -> Option<String> {
LAST_UNCAUGHT_EXCEPTION.with(|c| c.borrow_mut().take())
}
pub fn set(msg: String) {
LAST_UNCAUGHT_EXCEPTION.with(|c| *c.borrow_mut() = Some(msg));
}
pub fn panic_on_uncaught() {
if let Some(msg) = take() {
panic!("uncaught exception in plugin call: {msg}");
}
}
pub unsafe extern "C" fn uncaught_exception_callback(_ctx: *const u8, message: *const u8, len: i32) {
if message.is_null() || len <= 0 {
return;
}
let bytes = unsafe { std::slice::from_raw_parts(message, len.unsigned_abs() as usize) };
let msg = String::from_utf8_lossy(bytes).into_owned();
set(msg);
}
#[must_use]
#[allow(clippy::fn_to_numeric_cast_any)]
pub fn callback_ptr() -> *const u8 {
uncaught_exception_callback as *const u8
}