1macro_rules! ffi_fn {
2    (fn $name:ident($($arg:ident: $arg_ty:ty),*,) -> $ret:ty $body:block) => {
3        ffi_fn!(fn $name($($arg: $arg_ty),*) -> $ret $body);
4    };
5    (fn $name:ident($($arg:ident: $arg_ty:ty),*) -> $ret:ty $body:block) => {
6        #[no_mangle]
7        pub extern fn $name($($arg: $arg_ty),*) -> $ret {
8            use ::std::io::{self, Write};
9            use ::std::panic::{self, AssertUnwindSafe};
10            use ::libc::abort;
11            match panic::catch_unwind(AssertUnwindSafe(move || $body)) {
12                Ok(v) => v,
13                Err(err) => {
14                    let msg = if let Some(&s) = err.downcast_ref::<&str>() {
15                        s.to_owned()
16                    } else if let Some(s) = err.downcast_ref::<String>() {
17                        s.to_owned()
18                    } else {
19                        "UNABLE TO SHOW RESULT OF PANIC.".to_owned()
20                    };
21                    let _ = writeln!(
22                        &mut io::stderr(),
23                        "panic unwind caught, aborting: {:?}",
24                        msg);
25                    unsafe { abort() }
26                }
27            }
28        }
29    };
30    (fn $name:ident($($arg:ident: $arg_ty:ty),*,) $body:block) => {
31        ffi_fn!(fn $name($($arg: $arg_ty),*) -> () $body);
32    };
33    (fn $name:ident($($arg:ident: $arg_ty:ty),*) $body:block) => {
34        ffi_fn!(fn $name($($arg: $arg_ty),*) -> () $body);
35    };
36}
37