PkmnLib_rs/src/ffi/mod.rs

247 lines
7.1 KiB
Rust

/// The foreign function interfaces for the dynamic data
mod dynamic_data;
/// The foreign function interfaces for that static data
mod static_data;
/// Helper type for clearer functions.
type OwnedPtr<T> = *mut T;
/// Helper type for clearer functions.
type BorrowedPtr<T> = *const T;
/// Generates a basic getter foreign function interface.
macro_rules! ffi_arc_getter {
(
$type:ty, $func:ident, $returns: ty
) => {
paste::paste! {
#[no_mangle]
extern "C" fn [< $type:snake _ $func >](ptr: ExternPointer<Arc<$type>>) -> $returns {
ptr.as_ref().$func()
}
}
};
}
/// Generates a basic getter foreign function interface.
macro_rules! ffi_arc_dyn_getter {
(
$type:ty, $func:ident, $returns: ty
) => {
paste::paste! {
#[no_mangle]
extern "C" fn [< $type:snake _ $func >](ptr: ExternPointer<Arc<dyn $type>>) -> $returns {
ptr.as_ref().$func()
}
}
};
}
/// Generates a basic getter foreign function interface where the return type is a [`crate::StringKey`].
macro_rules! ffi_arc_stringkey_getter {
(
$type:ty, $func:ident
) => {
paste::paste! {
#[no_mangle]
extern "C" fn [< $type:lower _ $func >](ptr: ExternPointer<Arc<dyn $type>>) -> OwnedPtr<c_char> {
std::ffi::CString::new(ptr.as_ref().$func().str()).unwrap().into_raw()
}
}
};
}
/// Generates a foreign function interface for a vec. This generates a length function, and a getter.
macro_rules! ffi_vec_value_getters {
(
$name:ident, $type:ty, $func:ident, $returns: ty
) => {
paste::paste! {
#[no_mangle]
extern "C" fn [< $name:lower _ $func _length>](ptr: ExternPointer<Arc<$type>>) -> usize {
ptr.as_ref().$func().len()
}
#[no_mangle]
extern "C" fn [< $name:lower _ $func _get>](ptr: ExternPointer<Arc<$type>>, index: usize) -> $returns {
*ptr.as_ref().$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_vec_stringkey_getters {
(
$type:ty, $func:ident
) => {
paste::paste! {
#[no_mangle]
extern "C" fn [< $type:lower _ $func _length>](ptr: ExternPointer<Arc<dyn $type>>) -> usize {
ptr.as_ref().$func().len()
}
#[no_mangle]
extern "C" fn [< $type:lower _ $func _get>](ptr: ExternPointer<Arc<dyn $type>>, index: usize) -> OwnedPtr<c_char> {
CString::new(ptr.as_ref().$func().get(index).unwrap().str()).unwrap().into_raw()
}
}
};
}
use crate::{ValueIdentifiable, ValueIdentifier};
pub(self) use ffi_arc_dyn_getter;
pub(self) use ffi_arc_getter;
pub(self) use ffi_arc_stringkey_getter;
pub(self) use ffi_vec_stringkey_getters;
pub(self) use ffi_vec_value_getters;
use std::mem::transmute;
use std::sync::Arc;
/// Helper utility class to wrap a pointer for extern functions.
#[repr(C)]
pub(self) struct ExternPointer<T: ?Sized> {
/// The wrapped pointer.
ptr: *mut T,
}
impl<T: ?Sized> ExternPointer<T> {
/// Get the internal pointer as reference.
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::<T>()))
}
}
/// Get the internal pointer as mutable reference.
pub(self) fn as_mut(&mut self) -> &mut T {
unsafe {
self.ptr
.as_mut()
.unwrap_or_else(|| panic!("Given pointer of type '{}' was null", std::any::type_name::<T>()))
}
}
}
/// Helper utility class to give both the pointer and identifier to a FFI.
#[repr(C)]
pub(self) struct IdentifiablePointer<T> {
/// The wrapped pointer.
pub ptr: *const T,
/// The identifier of the pointer.
pub id: usize,
}
impl<T> IdentifiablePointer<T> {
/// Creates a new IdentifiablePointer.
pub(self) fn new(ptr: *const T, id: ValueIdentifier) -> Self {
unsafe { Self { ptr, id: transmute(id) } }
}
}
impl<T> From<*mut T> for ExternPointer<T> {
fn from(ptr: *mut T) -> Self {
ExternPointer { ptr }
}
}
impl<T: ValueIdentifiable + ?Sized> From<Arc<T>> for IdentifiablePointer<Arc<T>> {
fn from(v: Arc<T>) -> Self {
let id = v.value_identifier().value();
Self {
ptr: Box::into_raw(Box::new(v)),
id,
}
}
}
impl<T: ValueIdentifiable + ?Sized> From<Option<Arc<T>>> for IdentifiablePointer<Arc<T>> {
fn from(v: Option<Arc<T>>) -> Self {
if let Some(v) = v {
let id = unsafe { transmute(v.value_identifier()) };
Self {
ptr: Box::into_raw(Box::new(v)),
id,
}
} else {
IdentifiablePointer::none()
}
}
}
impl<T: ValueIdentifiable + ?Sized> From<Box<T>> for IdentifiablePointer<Box<T>> {
fn from(v: Box<T>) -> Self {
let id = unsafe { transmute(v.value_identifier()) };
Self {
ptr: Box::into_raw(Box::new(v)),
id,
}
}
}
impl<T: ValueIdentifiable + ?Sized> From<&Box<T>> for IdentifiablePointer<Box<T>> {
fn from(v: &Box<T>) -> Self {
let id = unsafe { transmute(v.value_identifier()) };
Self {
ptr: v as *const Box<T>,
id,
}
}
}
impl<T: ValueIdentifiable + ?Sized> From<Option<Box<T>>> for IdentifiablePointer<Box<T>> {
fn from(v: Option<Box<T>>) -> Self {
if let Some(v) = v {
let id = unsafe { transmute(v.value_identifier()) };
Self {
ptr: Box::into_raw(Box::new(v)),
id,
}
} else {
IdentifiablePointer::none()
}
}
}
impl<T: ValueIdentifiable + ?Sized> From<&Option<Box<T>>> for IdentifiablePointer<Box<T>> {
fn from(v: &Option<Box<T>>) -> Self {
if let Some(v) = v {
let id = unsafe { transmute(v.value_identifier()) };
unsafe {
Self {
ptr: *Box::into_raw(Box::new(v as *const Box<T>)),
id,
}
}
} else {
IdentifiablePointer::none()
}
}
}
impl<T: ValueIdentifiable> From<Box<T>> for IdentifiablePointer<T> {
fn from(v: Box<T>) -> Self {
let id = unsafe { transmute(v.value_identifier()) };
Self {
ptr: Box::into_raw(v),
id,
}
}
}
impl<T: ValueIdentifiable> From<*const T> for IdentifiablePointer<T> {
fn from(v: *const T) -> Self {
let id = unsafe { transmute(v.as_ref().unwrap().value_identifier()) };
Self { ptr: v, id }
}
}
impl<T> IdentifiablePointer<T> {
/// Returns an identifiable pointer with null as pointer, and 0 as identifier.
pub fn none() -> Self {
Self {
ptr: std::ptr::null(),
id: Default::default(),
}
}
}