use core::{
fmt::{Debug, Pointer},
hash::Hash,
panic::{RefUnwindSafe, UnwindSafe},
};
use crate::{
WithAbi, WithAbiImpl, WithArgs, WithArgsImpl, WithOutput, WithOutputImpl, WithSafety,
WithSafetyImpl, abi,
abi_value::AbiValue,
safety::{self, Safe, Unsafe},
tuple::Tuple,
};
ffi_opaque::opaque! {
pub struct OpaqueFn;
}
pub type UntypedFnPtr = *const OpaqueFn;
cfg_tt::cfg_tt! {
pub trait FnPtr:
PartialEq
+ Eq
+ PartialOrd
+ Ord
+ Hash
+ Pointer
+ Debug
+ Clone
+ Copy
+ Send
+ Sync
+ Unpin
+ UnwindSafe
+ RefUnwindSafe
+ Sized
+ WithOutputImpl
+ WithArgsImpl
+ WithSafetyImpl<safety::Safe>
+ WithSafetyImpl<safety::Unsafe>
+ WithAbiImpl<abi::Rust>
+ WithAbiImpl<abi::C>
+ WithAbiImpl<abi::CUnwind>
+ WithAbiImpl<abi::System>
+ WithAbiImpl<abi::SystemUnwind>
#[cfg(nightly_build)](+ core::marker::FnPtr)
#[cfg(has_abi_aapcs)](+ WithAbiImpl<abi::Aapcs>)
#[cfg(has_abi_aapcs)](+ WithAbiImpl<abi::AapcsUnwind>)
#[cfg(has_abi_cdecl)](+ WithAbiImpl<abi::Cdecl>)
#[cfg(has_abi_cdecl)](+ WithAbiImpl<abi::CdeclUnwind>)
#[cfg(has_abi_cdecl)](+ WithAbiImpl<abi::Stdcall>)
#[cfg(has_abi_cdecl)](+ WithAbiImpl<abi::StdcallUnwind>)
#[cfg(has_abi_cdecl)](+ WithAbiImpl<abi::Fastcall>)
#[cfg(has_abi_cdecl)](+ WithAbiImpl<abi::FastcallUnwind>)
#[cfg(has_abi_cdecl)](+ WithAbiImpl<abi::Thiscall>)
#[cfg(has_abi_cdecl)](+ WithAbiImpl<abi::ThiscallUnwind>)
#[cfg(has_abi_vectorcall)](+ WithAbiImpl<abi::Vectorcall>)
#[cfg(has_abi_vectorcall)](+ WithAbiImpl<abi::VectorcallUnwind>)
#[cfg(has_abi_sysv64)](+ WithAbiImpl<abi::SysV64>)
#[cfg(has_abi_sysv64)](+ WithAbiImpl<abi::SysV64Unwind>)
#[cfg(has_abi_win64)](+ WithAbiImpl<abi::Win64>)
#[cfg(has_abi_win64)](+ WithAbiImpl<abi::Win64Unwind>)
#[cfg(has_abi_efiapi)](+ WithAbiImpl<abi::EfiApi>)
{
type Args: Tuple;
type Output;
type Safety: safety::Safety;
type Abi: abi::Abi;
const ARITY: usize;
const IS_SAFE: bool;
const IS_EXTERN: bool;
const ABI: AbiValue;
#[must_use]
fn addr(&self) -> usize {
self.as_ptr() as usize
}
#[must_use]
unsafe fn from_addr(addr: usize) -> Self {
unsafe { Self::from_ptr(addr as UntypedFnPtr) }
}
#[must_use]
fn as_ptr(&self) -> UntypedFnPtr;
#[must_use]
#[allow(clippy::missing_safety_doc)] unsafe fn from_ptr(ptr: UntypedFnPtr) -> Self;
#[must_use]
unsafe fn cast<F: FnPtr>(&self) -> F {
unsafe { FnPtr::from_ptr(self.as_ptr()) }
}
#[must_use]
fn as_unsafe(&self) -> <Self as WithSafety<Unsafe>>::F {
unsafe { FnPtr::from_ptr(self.as_ptr()) }
}
#[must_use]
unsafe fn as_safe(&self) -> <Self as WithSafety<Safe>>::F {
self.cast()
}
#[must_use]
unsafe fn with_safety<Safety: safety::Safety>(&self) -> <Self as WithSafety<Safety>>::F
where
Self: WithSafety<Safety>,
{
self.cast()
}
#[must_use]
unsafe fn with_abi<Abi: abi::Abi>(&self) -> <Self as WithAbi<Abi>>::F
where
Self: WithAbi<Abi>,
{
self.cast()
}
#[must_use]
unsafe fn with_output<Output>(&self) -> <Self as WithOutput<Output>>::F
where
Self: WithOutput<Output>,
{
self.cast()
}
#[must_use]
unsafe fn with_args<Args: Tuple>(&self) -> <Self as WithArgs<Args>>::F
where
Self: WithArgs<Args>,
{
self.cast()
}
}
}
pub trait SafeFnPtr: FnPtr<Safety = Safe> {
fn invoke(&self, args: Self::Args) -> Self::Output;
}
pub trait UnsafeFnPtr: FnPtr<Safety = Unsafe> {
unsafe fn invoke(&self, args: Self::Args) -> Self::Output;
}
pub trait StaticFnPtr: FnPtr + 'static {}
impl<F: FnPtr + 'static> StaticFnPtr for F {}
#[cfg(test)]
#[allow(unused)]
mod test {
use super::*;
fn h<F: FnPtr>(f: F) -> crate::with_abi!("system", F) {
unsafe { f.cast() }
}
fn f<F: FnPtr>(f: F) -> crate::with_safety!(unsafe, F) {
unsafe { f.cast() }
}
fn j<F: FnPtr>(f: F) -> crate::with_output!(i32, F) {
unsafe { f.cast() }
}
fn k<F: FnPtr>(f: F) -> crate::with_args!((i32,), F) {
unsafe { f.cast() }
}
}