use std::any::Any;
use std::panic::{self, AssertUnwindSafe};
fn panic_message(payload: &Box<dyn Any + Send>) -> &str {
payload
.downcast_ref::<&str>()
.copied()
.or_else(|| payload.downcast_ref::<String>().map(String::as_str))
.unwrap_or("unknown panic")
}
#[inline]
pub fn catch_mojo_call<T: Default>(f: impl FnOnce() -> T) -> T {
match panic::catch_unwind(AssertUnwindSafe(f)) {
Ok(val) => val,
Err(payload) => {
eprintln!(
"[pyroxide] panic at FFI boundary: {}",
panic_message(&payload)
);
T::default()
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn success_returns_value() {
let result = catch_mojo_call(|| 42i32);
assert_eq!(result, 42);
}
#[test]
fn panic_returns_default() {
let result: f64 = catch_mojo_call(|| {
panic!("test panic");
});
assert_eq!(result, 0.0); }
#[test]
fn panic_returns_false_for_bool() {
let result: bool = catch_mojo_call(|| {
panic!("test");
});
assert!(!result);
}
}