7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 1 | use std::cell::RefCell; |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 2 | |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 3 | type Handler = Box<dyn Fn(&str)>; |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 4 | |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 5 | thread_local! { |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 6 | static HANDLER: RefCell<Option<Handler>> = const { RefCell::new(None) }; |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 7 | } |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 8 | |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 9 | /// a panic on wasm32 traps the task that raised it and nothing unwinds, so the engine |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 10 | /// catches nothing. the rest of it keeps running in an undefined state and goes silent, |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 11 | /// no `Failed` and no `Stopped`. `handler` runs from the panic hook with the message, |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 12 | /// after whatever hook was there before, and is the host's one chance to react, say by |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 13 | /// terminating the worker and starting a fresh one. a second call replaces the handler |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 14 | pub fn on_panic(handler: impl Fn(&str) + 'static) { |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 15 | let installed = HANDLER.with(|slot| slot.replace(Some(Box::new(handler))).is_some()); |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 16 | if installed { |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 17 | return; |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 18 | } |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 19 | let previous = std::panic::take_hook(); |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 20 | std::panic::set_hook(Box::new(move |info| { |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 21 | previous(info); |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 22 | let message = info.to_string(); |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 23 | HANDLER.with(|slot| { |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 24 | if let Some(handler) = &*slot.borrow() { |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 25 | handler(&message); |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 26 | } |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 27 | }); |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 28 | })); |
7b376d620a3d | atagen | 2026-09-26 12:53 UTC | 29 | } |