1use core::{
2 fmt::{Debug, Pointer},
3 hash::Hash,
4 panic::{RefUnwindSafe, UnwindSafe},
5};
6
7use crate::{
8 WithAbi, WithAbiImpl, WithArgs, WithArgsImpl, WithOutput, WithOutputImpl, WithSafety,
9 WithSafetyImpl, abi,
10 abi_value::AbiValue,
11 safety::{self, Safe, Unsafe},
12 tuple::Tuple,
13};
14
15ffi_opaque::opaque! {
16 pub struct OpaqueFn;
18}
19
20pub type UntypedFnPtr = *const OpaqueFn;
22
23cfg_tt::cfg_tt! {
24pub trait FnPtr:
26 PartialEq
27 + Eq
28 + PartialOrd
29 + Ord
30 + Hash
31 + Pointer
32 + Debug
33 + Clone
34 + Copy
35 + Send
36 + Sync
37 + Unpin
38 + UnwindSafe
39 + RefUnwindSafe
40 + Sized
41 + WithOutputImpl
42 + WithArgsImpl
43 + WithSafetyImpl<safety::Safe>
44 + WithSafetyImpl<safety::Unsafe>
45 + WithAbiImpl<abi::Rust>
46 + WithAbiImpl<abi::C>
47 + WithAbiImpl<abi::CUnwind>
48 + WithAbiImpl<abi::System>
49 + WithAbiImpl<abi::SystemUnwind>
50 #[cfg(nightly_build)](+ core::marker::FnPtr)
51 #[cfg(has_abi_aapcs)](+ WithAbiImpl<abi::Aapcs>)
52 #[cfg(has_abi_aapcs)](+ WithAbiImpl<abi::AapcsUnwind>)
53 #[cfg(has_abi_cdecl)](+ WithAbiImpl<abi::Cdecl>)
54 #[cfg(has_abi_cdecl)](+ WithAbiImpl<abi::CdeclUnwind>)
55 #[cfg(has_abi_cdecl)](+ WithAbiImpl<abi::Stdcall>)
56 #[cfg(has_abi_cdecl)](+ WithAbiImpl<abi::StdcallUnwind>)
57 #[cfg(has_abi_cdecl)](+ WithAbiImpl<abi::Fastcall>)
58 #[cfg(has_abi_cdecl)](+ WithAbiImpl<abi::FastcallUnwind>)
59 #[cfg(has_abi_cdecl)](+ WithAbiImpl<abi::Thiscall>)
60 #[cfg(has_abi_cdecl)](+ WithAbiImpl<abi::ThiscallUnwind>)
61 #[cfg(has_abi_vectorcall)](+ WithAbiImpl<abi::Vectorcall>)
62 #[cfg(has_abi_vectorcall)](+ WithAbiImpl<abi::VectorcallUnwind>)
63 #[cfg(has_abi_sysv64)](+ WithAbiImpl<abi::SysV64>)
64 #[cfg(has_abi_sysv64)](+ WithAbiImpl<abi::SysV64Unwind>)
65 #[cfg(has_abi_win64)](+ WithAbiImpl<abi::Win64>)
66 #[cfg(has_abi_win64)](+ WithAbiImpl<abi::Win64Unwind>)
67 #[cfg(has_abi_efiapi)](+ WithAbiImpl<abi::EfiApi>)
68{
69 type Args: Tuple;
71
72 type Output;
74
75 type Safety: safety::Safety;
77
78 type Abi: abi::Abi;
80
81 const ARITY: usize;
83
84 const IS_SAFE: bool;
86
87 const IS_EXTERN: bool;
89
90 const ABI: AbiValue;
92
93 #[must_use]
95 fn addr(&self) -> usize {
96 self.as_ptr() as usize
97 }
98 #[must_use]
103 unsafe fn from_addr(addr: usize) -> Self {
104 unsafe { Self::from_ptr(addr as UntypedFnPtr) }
105 }
106 #[must_use]
108 fn as_ptr(&self) -> UntypedFnPtr;
109 #[must_use]
114 #[allow(clippy::missing_safety_doc)] unsafe fn from_ptr(ptr: UntypedFnPtr) -> Self;
116
117 #[must_use]
122 unsafe fn cast<F: FnPtr>(&self) -> F {
123 unsafe { FnPtr::from_ptr(self.as_ptr()) }
124 }
125
126 #[must_use]
128 fn as_unsafe(&self) -> <Self as WithSafety<Unsafe>>::F {
129 unsafe { FnPtr::from_ptr(self.as_ptr()) }
130 }
131
132 #[must_use]
137 unsafe fn as_safe(&self) -> <Self as WithSafety<Safe>>::F {
138 self.cast()
139 }
140
141 #[must_use]
146 unsafe fn with_safety<Safety: safety::Safety>(&self) -> <Self as WithSafety<Safety>>::F
147 where
148 Self: WithSafety<Safety>,
149 {
150 self.cast()
151 }
152
153 #[must_use]
158 unsafe fn with_abi<Abi: abi::Abi>(&self) -> <Self as WithAbi<Abi>>::F
159 where
160 Self: WithAbi<Abi>,
161 {
162 self.cast()
163 }
164
165 #[must_use]
170 unsafe fn with_output<Output>(&self) -> <Self as WithOutput<Output>>::F
171 where
172 Self: WithOutput<Output>,
173 {
174 self.cast()
175 }
176
177 #[must_use]
182 unsafe fn with_args<Args: Tuple>(&self) -> <Self as WithArgs<Args>>::F
183 where
184 Self: WithArgs<Args>,
185 {
186 self.cast()
187 }
188}
189}
190
191pub trait SafeFnPtr: FnPtr<Safety = Safe> {
193 fn invoke(&self, args: Self::Args) -> Self::Output;
207}
208
209pub trait UnsafeFnPtr: FnPtr<Safety = Unsafe> {
211 unsafe fn invoke(&self, args: Self::Args) -> Self::Output;
229}
230
231pub trait StaticFnPtr: FnPtr + 'static {}
234impl<F: FnPtr + 'static> StaticFnPtr for F {}
235
236#[cfg(test)]
237#[allow(unused)]
238mod test {
239 use super::*;
240
241 fn h<F: FnPtr>(f: F) -> crate::with_abi!("system", F) {
242 unsafe { f.cast() }
243 }
244 fn f<F: FnPtr>(f: F) -> crate::with_safety!(unsafe, F) {
245 unsafe { f.cast() }
246 }
247 fn j<F: FnPtr>(f: F) -> crate::with_output!(i32, F) {
248 unsafe { f.cast() }
249 }
250 fn k<F: FnPtr>(f: F) -> crate::with_args!((i32,), F) {
251 unsafe { f.cast() }
252 }
253}