Documentation
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)
    }};
}