fn_ptr/
base.rs

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    /// A struct representing an opaque function.
17    pub struct OpaqueFn;
18}
19
20/// Type alias for a raw untyped function pointer.
21pub type UntypedFnPtr = *const OpaqueFn;
22
23cfg_tt::cfg_tt! {
24/// Marker trait for all function pointers.
25pub 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    /// The argument types as a tuple.
70    type Args: Tuple;
71
72    /// The return type.
73    type Output;
74
75    /// Marker type denoting safety
76    type Safety: safety::Safety;
77
78    /// Marker type denoting abi
79    type Abi: abi::Abi;
80
81    /// The function's arity (number of arguments).
82    const ARITY: usize;
83
84    /// Whether the function pointer is safe (fn) or unsafe (unsafe fn).
85    const IS_SAFE: bool;
86
87    /// Whether the function pointer uses an extern calling convention.
88    const IS_EXTERN: bool;
89
90    /// The abi associated with this function pointer.
91    const ABI: AbiValue;
92
93    /// Returns the address of this function.
94    #[must_use]
95    fn addr(&self) -> usize {
96        self.as_ptr() as usize
97    }
98    /// Constructs an instance from an address.
99    ///
100    /// # Safety
101    /// The given pointer has to point to a function of the correct type.
102    #[must_use]
103    unsafe fn from_addr(addr: usize) -> Self {
104        unsafe { Self::from_ptr(addr as UntypedFnPtr) }
105    }
106    /// Returns a untyped function pointer for this function.
107    #[must_use]
108    fn as_ptr(&self) -> UntypedFnPtr;
109    /// Constructs an instance from an untyped function pointer.
110    ///
111    /// # Safety
112    /// The given pointer has to point to a function of the correct type.
113    #[must_use]
114    #[allow(clippy::missing_safety_doc)] // false positive?
115    unsafe fn from_ptr(ptr: UntypedFnPtr) -> Self;
116
117    /// Casts this function pointer to a different function pointer type.
118    ///
119    /// # Safety
120    /// Caller must ensure that the resulting transformation is sound.
121    #[must_use]
122    unsafe fn cast<F: FnPtr>(&self) -> F {
123        unsafe { FnPtr::from_ptr(self.as_ptr()) }
124    }
125
126    /// Produces an unsafe version of this function pointer.
127    #[must_use]
128    fn as_unsafe(&self) -> <Self as WithSafety<Unsafe>>::F {
129        unsafe { FnPtr::from_ptr(self.as_ptr()) }
130    }
131
132    /// Produces a safe version of this function pointer.
133    ///
134    /// # Safety
135    /// Caller must ensure the underlying function is actually safe to call.
136    #[must_use]
137    unsafe fn as_safe(&self) ->  <Self as WithSafety<Safe>>::F {
138        self.cast()
139    }
140
141    /// Produces a version of this function pointer with the given safety.
142    ///
143    /// # Safety
144    /// Caller must ensure that this function pointer is safe when casting to a safe function.
145    #[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    /// Produces a version of this function pointer with the given abi.
154    ///
155    /// # Safety
156    /// Caller must ensure that the resulting abi transformation is sound.
157    #[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    /// Produces a version of this function pointer with the given return type.
166    ///
167    /// # Safety
168    /// Caller must ensure that the resulting transformation is sound.
169    #[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    /// Produces a version of this function pointer with the given return type.
178    ///
179    /// # Safety
180    /// Caller must ensure that the resulting transformation is sound.
181    #[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
191/// Marker trait for all callable *safe* function pointer types (`fn` / `extern fn`).
192pub trait SafeFnPtr: FnPtr<Safety = Safe> {
193    /// Invokes the function pointed to with the given args.
194    ///
195    /// # Examples
196    ///
197    /// ```
198    /// # use fn_ptr::SafeFnPtr;
199    /// fn add(a: i32, b: i32) -> i32 { a + b }
200    ///
201    /// let f: fn(i32, i32) -> i32 = add;
202    /// let result = f.invoke((2, 3));
203    /// assert_eq!(result, 5);
204    /// ```
205    // NOTE: Can't use "call" due to fn_traits feature
206    fn invoke(&self, args: Self::Args) -> Self::Output;
207}
208
209/// Marker trait for all callable *unsafe* function pointer types (`unsafe fn` / `unsafe extern fn`).
210pub trait UnsafeFnPtr: FnPtr<Safety = Unsafe> {
211    /// Invokes the function pointed to with the given args.
212    ///
213    /// # Safety
214    /// Calling this function pointer is unsafe because the function may have
215    /// invariants that must be manually upheld by the caller.
216    ///
217    /// # Examples
218    ///
219    /// ```
220    /// # use fn_ptr::UnsafeFnPtr;
221    /// unsafe fn add(a: *const i32, b: *const i32) -> i32 { *a + *b }
222    ///
223    /// let f: unsafe fn(*const i32, *const i32) -> i32 = add;
224    /// let result = unsafe { f.invoke((&2, &3)) };
225    /// assert_eq!(result, 5);
226    /// ```
227    // NOTE: Can't use "call" due to fn_traits feature
228    unsafe fn invoke(&self, args: Self::Args) -> Self::Output;
229}
230
231/// Marker trait for all *static* function pointer types.
232/// The return type and all parameter types have to be `'static`.
233pub 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}