1 macro_rules! ffi_fn {
2     ($(#[$doc:meta])* fn $name:ident($($arg:ident: $arg_ty:ty),*) -> $ret:ty $body:block ?= $default:expr) => {
3         $(#[$doc])*
4         #[no_mangle]
5         pub extern fn $name($($arg: $arg_ty),*) -> $ret {
6             use std::panic::{self, AssertUnwindSafe};
7 
8             match panic::catch_unwind(AssertUnwindSafe(move || $body)) {
9                 Ok(v) => v,
10                 Err(_) => {
11                     $default
12                 }
13             }
14         }
15     };
16 
17     ($(#[$doc:meta])* fn $name:ident($($arg:ident: $arg_ty:ty),*) -> $ret:ty $body:block) => {
18         ffi_fn!($(#[$doc])* fn $name($($arg: $arg_ty),*) -> $ret $body ?= {
19             eprintln!("panic unwind caught, aborting");
20             std::process::abort()
21         });
22     };
23 
24     ($(#[$doc:meta])* fn $name:ident($($arg:ident: $arg_ty:ty),*) $body:block ?= $default:expr) => {
25         ffi_fn!($(#[$doc])* fn $name($($arg: $arg_ty),*) -> () $body ?= $default);
26     };
27 
28     ($(#[$doc:meta])* fn $name:ident($($arg:ident: $arg_ty:ty),*) $body:block) => {
29         ffi_fn!($(#[$doc])* fn $name($($arg: $arg_ty),*) -> () $body);
30     };
31 }
32 
33 macro_rules! non_null {
34     ($ptr:ident, $eval:expr, $err:expr) => {{
35         debug_assert!(!$ptr.is_null(), "{:?} must not be null", stringify!($ptr));
36         if $ptr.is_null() {
37             return $err;
38         }
39         unsafe { $eval }
40     }};
41     (&*$ptr:ident ?= $err:expr) => {{
42         non_null!($ptr, &*$ptr, $err)
43     }};
44     (&mut *$ptr:ident ?= $err:expr) => {{
45         non_null!($ptr, &mut *$ptr, $err)
46     }};
47     (Box::from_raw($ptr:ident) ?= $err:expr) => {{
48         non_null!($ptr, Box::from_raw($ptr), $err)
49     }};
50     (Arc::from_raw($ptr:ident) ?= $err:expr) => {{
51         non_null!($ptr, Arc::from_raw($ptr), $err)
52     }};
53 }
54