/// The foreign function interfaces for the dynamic data mod dynamic_data; /// The handling of handles for the foreign function interfaces mod ffi_handle; /// The foreign function interfaces for that static data mod static_data; pub(self) use ffi_handle::*; /// Helper type for clearer functions. #[repr(C)] #[derive(Debug, Copy, Clone)] struct OwnedPtrString(*mut c_char); /// Helper type for clearer functions. type NonOwnedPtrString = *const c_char; impl Default for OwnedPtrString { fn default() -> Self { OwnedPtrString(std::ptr::null_mut()) } } /// Generates a basic getter foreign function interface. macro_rules! ffi_handle_arc_dyn_getter { ( $type:ty, $func:ident, $returns: ty ) => { paste::paste! { #[no_mangle] extern "C" fn [< $type:snake _ $func >](ptr: FFIHandle>) -> $returns { ptr.from_ffi_handle().$func() } } }; } /// Generates a basic getter foreign function interface where the return type is a [`crate::StringKey`]. macro_rules! ffi_handle_arc_stringkey_getter { ( $type:ty, $func:ident ) => { paste::paste! { #[no_mangle] extern "C" fn [< $type:lower _ $func >](ptr: FFIHandle>) -> NonOwnedPtrString { std::ffi::CString::new(ptr.from_ffi_handle().$func().str()).unwrap().into_raw() } } }; } /// Generates a foreign function interface for a vec. This generates a length function, and a getter. macro_rules! ffi_handle_vec_value_getters { ( $name:ident, $type:ty, $func:ident, $returns: ty ) => { paste::paste! { #[no_mangle] extern "C" fn [< $name:lower _ $func _length>](ptr: FFIHandle>) -> usize { ptr.from_ffi_handle().$func().len() } #[no_mangle] extern "C" fn [< $name:lower _ $func _get>](ptr: FFIHandle>, index: usize) -> $returns { *ptr.from_ffi_handle().$func().get(index).unwrap() } } }; } /// Generates a foreign function interface for a vec of [`crate::StringKey`]. This generates a /// length function, and a getter. macro_rules! ffi_handle_vec_stringkey_getters { ( $type:ty, $func:ident ) => { paste::paste! { #[no_mangle] extern "C" fn [< $type:lower _ $func _length>](ptr: FFIHandle>) -> usize { ptr.from_ffi_handle().$func().len() } #[no_mangle] extern "C" fn [< $type:lower _ $func _get>](ptr: FFIHandle>, index: usize) -> OwnedPtrString { OwnedPtrString(CString::new(ptr.from_ffi_handle().$func().get(index).unwrap().str()).unwrap().into_raw()) } } }; } pub(self) use ffi_handle_arc_dyn_getter; pub(self) use ffi_handle_arc_stringkey_getter; pub(self) use ffi_handle_vec_stringkey_getters; pub(self) use ffi_handle_vec_value_getters; use std::ffi::{c_char, CString}; /// Helper utility class to wrap a pointer for extern functions. #[repr(C)] pub(self) struct ExternPointer { /// The wrapped pointer. ptr: *mut T, } impl ExternPointer { /// Get the internal pointer as reference. #[allow(clippy::panic)] // We currently allow this as these should never be null, but we might want to change this in the future. pub(self) fn as_ref(&self) -> &T { unsafe { self.ptr .as_ref() .unwrap_or_else(|| panic!("Given pointer of type '{}' was null", std::any::type_name::())) } } } /// The result of a FFI call that can either be an error or a value. #[repr(C)] #[repr(packed)] pub struct FFIResult { /// If the result is ok, this is null, otherwise this is a pointer to the error string. err: NonOwnedPtrString, /// The value or error. value: T, } impl FFIResult { /// Creates a new NativeResult with the given value. pub fn ok(value: T) -> Self { Self { err: std::ptr::null(), value, } } /// Creates a new NativeResult with the given error. #[allow(clippy::unwrap_used)] // We know for certain this is not empty. pub fn err(err: anyhow_ext::Error) -> Self { Self { err: CString::new(err.to_string()).unwrap().into_raw(), value: Default::default(), } } /// Creates a new NativeResult with the given error string. #[allow(clippy::unwrap_used)] // We know for certain this is not empty. pub fn err_from_str(err: &str) -> Self { Self { err: CString::new(err).unwrap().into_raw(), value: Default::default(), } } } impl From> for FFIResult { fn from(value: anyhow::Result) -> Self { match value { Ok(v) => Self::ok(v), Err(e) => Self::err(e), } } } impl From for FFIResult { fn from(value: T) -> Self { Self::ok(value) } }