| macro_rules! ffi_fn { |
| ($(#[$doc:meta])* fn $name:ident($($arg:ident: $arg_ty:ty),*) -> $ret:ty $body:block ?= $default:expr) => { |
| $(#[$doc])* |
| #[no_mangle] |
| pub extern fn $name($($arg: $arg_ty),*) -> $ret { |
| use std::panic::{self, AssertUnwindSafe}; |
| |
| match panic::catch_unwind(AssertUnwindSafe(move || $body)) { |
| Ok(v) => v, |
| Err(_) => { |
| $default |
| } |
| } |
| } |
| }; |
| |
| ($(#[$doc:meta])* fn $name:ident($($arg:ident: $arg_ty:ty),*) -> $ret:ty $body:block) => { |
| ffi_fn!($(#[$doc])* fn $name($($arg: $arg_ty),*) -> $ret $body ?= { |
| eprintln!("panic unwind caught, aborting"); |
| std::process::abort() |
| }); |
| }; |
| |
| ($(#[$doc:meta])* fn $name:ident($($arg:ident: $arg_ty:ty),*) $body:block ?= $default:expr) => { |
| ffi_fn!($(#[$doc])* fn $name($($arg: $arg_ty),*) -> () $body ?= $default); |
| }; |
| |
| ($(#[$doc:meta])* fn $name:ident($($arg:ident: $arg_ty:ty),*) $body:block) => { |
| ffi_fn!($(#[$doc])* fn $name($($arg: $arg_ty),*) -> () $body); |
| }; |
| } |
| |
| macro_rules! non_null { |
| ($ptr:ident, $eval:expr, $err:expr) => {{ |
| debug_assert!(!$ptr.is_null(), "{:?} must not be null", stringify!($ptr)); |
| if $ptr.is_null() { |
| return $err; |
| } |
| unsafe { $eval } |
| }}; |
| (&*$ptr:ident ?= $err:expr) => {{ |
| non_null!($ptr, &*$ptr, $err) |
| }}; |
| (&mut *$ptr:ident ?= $err:expr) => {{ |
| non_null!($ptr, &mut *$ptr, $err) |
| }}; |
| (Box::from_raw($ptr:ident) ?= $err:expr) => {{ |
| non_null!($ptr, Box::from_raw($ptr), $err) |
| }}; |
| (Arc::from_raw($ptr:ident) ?= $err:expr) => {{ |
| non_null!($ptr, Arc::from_raw($ptr), $err) |
| }}; |
| } |