use std::sync::Arc;
use egui::mutex::Mutex;
use wasm_bindgen::prelude::*;
#[derive(Clone)]
pub struct PanicHandler(Arc<Mutex<PanicHandlerInner>>);
impl PanicHandler {
pub fn install() -> Self {
let handler = Self(Arc::new(Mutex::new(Default::default())));
let handler_clone = handler.clone();
let previous_hook = std::panic::take_hook();
std::panic::set_hook(Box::new(move |panic_info| {
let summary = PanicSummary::new(panic_info);
error(format!(
"{}\n\nStack:\n\n{}",
summary.message(),
summary.callstack()
));
handler_clone.0.lock().summary = Some(summary);
previous_hook(panic_info);
}));
handler
}
pub fn has_panicked(&self) -> bool {
self.0.lock().summary.is_some()
}
pub fn panic_summary(&self) -> Option<PanicSummary> {
self.0.lock().summary.clone()
}
}
#[derive(Clone, Default)]
struct PanicHandlerInner {
summary: Option<PanicSummary>,
}
#[derive(Clone, Debug)]
pub struct PanicSummary {
message: String,
callstack: String,
}
impl PanicSummary {
pub fn new(info: &std::panic::PanicHookInfo<'_>) -> Self {
let message = info.to_string();
let callstack = Error::new().stack();
Self { message, callstack }
}
pub fn message(&self) -> String {
self.message.clone()
}
pub fn callstack(&self) -> String {
self.callstack.clone()
}
}
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
fn error(msg: String);
type Error;
#[wasm_bindgen(constructor)]
fn new() -> Error;
#[wasm_bindgen(structural, method, getter)]
fn stack(error: &Error) -> String;
}