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