macro_rules! ffi_fn { (fn $name:ident($($arg:ident: $arg_ty:ty),*,) -> $ret:ty $body:block) => { ffi_fn!(fn $name($($arg: $arg_ty),*) -> $ret $body); }; (fn $name:ident($($arg:ident: $arg_ty:ty),*) -> $ret:ty $body:block) => { #[no_mangle] pub extern fn $name($($arg: $arg_ty),*) -> $ret { use ::std::io::{self, Write}; use ::std::panic::{self, AssertUnwindSafe}; use ::libc::abort; match panic::catch_unwind(AssertUnwindSafe(move || $body)) { Ok(v) => v, Err(err) => { let msg = if let Some(&s) = err.downcast_ref::<&str>() { s.to_owned() } else if let Some(s) = err.downcast_ref::() { s.to_owned() } else { "UNABLE TO SHOW RESULT OF PANIC.".to_owned() }; let _ = writeln!( &mut io::stderr(), "panic unwind caught, aborting: {:?}", msg); unsafe { abort() } } } } }; (fn $name:ident($($arg:ident: $arg_ty:ty),*,) $body:block) => { ffi_fn!(fn $name($($arg: $arg_ty),*) -> () $body); }; (fn $name:ident($($arg:ident: $arg_ty:ty),*) $body:block) => { ffi_fn!(fn $name($($arg: $arg_ty),*) -> () $body); }; }