use std::ffi::c_void;
mod sealed {
pub trait Sealed {}
}
pub unsafe trait SymbolType: Copy + sealed::Sealed {
#[doc(hidden)]
fn from_address(addr: *mut c_void) -> Option<Self>;
#[doc(hidden)]
fn to_address(self) -> *mut c_void;
}
pub trait FnPtr: SymbolType {
type Args;
type Output;
unsafe fn call(self, args: Self::Args) -> Self::Output;
}
unsafe impl<T> SymbolType for *const T {
fn from_address(addr: *mut c_void) -> Option<Self> {
Some(addr.cast_const().cast())
}
fn to_address(self) -> *mut c_void {
self.cast_mut().cast()
}
}
impl<T> sealed::Sealed for *const T {}
unsafe impl<T> SymbolType for *mut T {
fn from_address(addr: *mut c_void) -> Option<Self> {
Some(addr.cast())
}
fn to_address(self) -> *mut c_void {
self.cast()
}
}
impl<T> sealed::Sealed for *mut T {}
macro_rules! impl_fn {
($abi:literal; $($ty:ident $val:ident),*) => {
impl<R, $($ty),*> sealed::Sealed for unsafe extern $abi fn($($ty),*) -> R {}
unsafe impl<R, $($ty),*> SymbolType for unsafe extern $abi fn($($ty),*) -> R {
#[allow(clippy::not_unsafe_ptr_arg_deref)]
fn from_address(addr: *mut c_void) -> Option<Self> {
if addr.is_null() {
return None;
}
Some(unsafe { std::mem::transmute::<*mut c_void, Self>(addr) })
}
fn to_address(self) -> *mut c_void {
self as *mut c_void
}
}
impl<R, $($ty),*> FnPtr for unsafe extern $abi fn($($ty),*) -> R {
type Args = ($($ty,)*);
type Output = R;
unsafe fn call(self, ($($val,)*): Self::Args) -> R {
unsafe { self($($val),*) }
}
}
};
}
macro_rules! impl_fn_all_abis {
($($ty:ident $val:ident),*) => {
impl_fn!("C"; $($ty $val),*);
impl_fn!("C-unwind"; $($ty $val),*);
impl_fn!("system"; $($ty $val),*);
impl_fn!("system-unwind"; $($ty $val),*);
};
}
impl_fn_all_abis!();
impl_fn_all_abis!(A a);
impl_fn_all_abis!(A a, B b);
impl_fn_all_abis!(A a, B b, C c);
impl_fn_all_abis!(A a, B b, C c, D d);
impl_fn_all_abis!(A a, B b, C c, D d, E e);
impl_fn_all_abis!(A a, B b, C c, D d, E e, F f);
impl_fn_all_abis!(A a, B b, C c, D d, E e, F f, G g);
impl_fn_all_abis!(A a, B b, C c, D d, E e, F f, G g, H h);
impl_fn_all_abis!(A a, B b, C c, D d, E e, F f, G g, H h, I i);
impl_fn_all_abis!(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j);
impl_fn_all_abis!(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k);
impl_fn_all_abis!(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l);