use std::any::Any; use std::cell::RefCell; use std::panic::{self, AssertUnwindSafe}; thread_local!(static LAST_ERROR: RefCell>> = { RefCell::new(None) }); pub fn catch T>(f: F) -> Option { match LAST_ERROR.try_with(|slot| slot.borrow().is_some()) { Ok(true) => return None, Ok(false) => {} // we're in thread shutdown, so we're for sure not panicking and // panicking again will abort, so no need to worry! Err(_) => {} } // Note that `AssertUnwindSafe` is used here as we prevent reentering // arbitrary code due to the `LAST_ERROR` check above plus propagation of a // panic after we return back to user code from C. match panic::catch_unwind(AssertUnwindSafe(f)) { Ok(ret) => Some(ret), Err(e) => { LAST_ERROR.with(|slot| *slot.borrow_mut() = Some(e)); None } } } pub fn propagate() { if let Ok(Some(t)) = LAST_ERROR.try_with(|slot| slot.borrow_mut().take()) { panic::resume_unwind(t) } }