// Common code for sequoia-openpgp-ffi and sequoia-ffi.
use std::collections::hash_map::{DefaultHasher, RandomState};
use std::hash::BuildHasher;
/* Canonical free(). */
/// Transfers ownership from C to Rust, then frees the object.
///
/// NOP if called with NULL.
macro_rules! ffi_free {
($name:ident) => {{
if let Some(ptr) = $name {
unsafe {
drop(Box::from_raw(ptr))
}
}
}};
}
/* Parameter handling. */
/// Transfers ownership from C to Rust.
///
/// # Panics
///
/// Panics if called with NULL.
macro_rules! ffi_param_move {
($name:expr) => {{
if $name.is_null() {
panic!("Parameter {} is NULL", stringify!($name));
}
unsafe {
Box::from_raw($name)
}
}};
}
/// Transfers a reference from C to Rust.
///
/// # Panics
///
/// Panics if called with NULL.
macro_rules! ffi_param_ref {
($name:ident) => {{
if $name.is_null() {
panic!("Parameter {} is NULL", stringify!($name));
}
unsafe {
&*$name
}
}};
}
/// Transfers a mutable reference from C to Rust.
///
/// # Panics
///
/// Panics if called with NULL.
macro_rules! ffi_param_ref_mut {
($name:ident) => {{
if $name.is_null() {
panic!("Parameter {} is NULL", stringify!($name));
}
unsafe {
&mut *$name
}
}};
}
/// Transfers a reference to a string from C to Rust.
///
/// # Panics
///
/// Panics if called with NULL.
macro_rules! ffi_param_cstr {
($name:expr) => {{
if $name.is_null() {
panic!("Parameter {} is NULL", stringify!($name));
}
unsafe {
::std::ffi::CStr::from_ptr($name)
}
}};
}
/* Return value handling. */
/// Duplicates a string similar to strndup(3).
#[allow(dead_code)]
pub(crate) fn strndup(src: &[u8]) -> Option<*mut libc::c_char> {
if src.contains(&0) {
return None;
}
let l = src.len() + 1;
let s = unsafe {
::std::slice::from_raw_parts_mut(libc::malloc(l) as *mut u8, l)
};
&mut s[..l - 1].copy_from_slice(src);
s[l - 1] = 0;
Some(s.as_mut_ptr() as *mut libc::c_char)
}
/// Transfers a string from Rust to C, allocating it using malloc.
///
/// # Panics
///
/// Panics if the given string contains a 0.
macro_rules! ffi_return_string {
($name:expr) => {{
let string = $name;
let bytes: &[u8] = string.as_ref();
::strndup(bytes).expect(
&format!("Returned string {} contains a 0 byte.", stringify!($name))
)
}};
}
/// Transfers a string from Rust to C, allocating it using malloc.
///
/// # Panics
///
/// Does *NOT* panic if the given string contains a 0, but returns
/// `NULL`.
macro_rules! ffi_return_maybe_string {
($name:expr) => {{
let string = $name;
let bytes: &[u8] = string.as_ref();
::strndup(bytes).unwrap_or(::std::ptr::null_mut())
}};
}
/* Error handling with implicit error return argument. */
/// Emits local macros for error handling that use the given context
/// to store complex errors.
macro_rules! ffi_make_fry_from_errp {
($errp:expr) => {
/// Like try! for ffi glue.
///
/// Evaluates the given expression. On success, evaluate to
/// `Status.Success`. On failure, stashes the error in the
/// context and evaluates to the appropriate Status code.
#[allow(unused_macros)]
macro_rules! ffi_try_status {
($expr:expr) => {
match $expr {
Ok(_) => Status::Success,
Err(e) => {
let status = Status::from(&e);
if let Some(errp) = $errp {
*errp = box_raw!(e);
}
status
},
}
};
}
/// Like try! for ffi glue.
///
/// Unwraps the given expression. On failure, stashes the
/// error in the context and returns $or.
#[allow(unused_macros)]
macro_rules! ffi_try_or