use super::INJECTED_PANIC_MESSAGE;
type PanicHook = Box<dyn Fn(&std::panic::PanicHookInfo<'_>) + Sync + Send + 'static>;
#[must_use = "the injected panic is only silenced while the guard is alive"]
pub fn silence_injected_panics() -> SilencedInjectedPanics {
let previous: std::sync::Arc<PanicHook> = std::sync::Arc::new(std::panic::take_hook());
let installed = previous.clone();
std::panic::set_hook(Box::new(move |info| {
if is_injected(info) {
return;
}
installed(info);
}));
SilencedInjectedPanics { previous }
}
fn is_injected(info: &std::panic::PanicHookInfo<'_>) -> bool {
let payload = info.payload();
let message = payload
.downcast_ref::<String>()
.map(String::as_str)
.or_else(|| payload.downcast_ref::<&'static str>().copied());
message.is_some_and(|m| m.contains(INJECTED_PANIC_MESSAGE))
}
pub struct SilencedInjectedPanics {
previous: std::sync::Arc<PanicHook>,
}
impl Drop for SilencedInjectedPanics {
fn drop(&mut self) {
if std::thread::panicking() {
return;
}
let previous = self.previous.clone();
std::panic::set_hook(Box::new(move |info| previous(info)));
}
}