fn_ptr/
base.rs

1use core::{
2    fmt::{Debug, Pointer},
3    hash::Hash,
4    panic::{RefUnwindSafe, UnwindSafe},
5};
6
7use crate::{
8    WithAbi, WithSafety, abi,
9    abi::{Abi, AbiKey},
10    make_safe, make_unsafe,
11};
12
13ffi_opaque::opaque! {
14    /// A struct representing an opaque function.
15    pub struct OpaqueFn;
16}
17
18/// Type alias for a raw untyped function pointer.
19pub type UntypedFnPtr = *const OpaqueFn;
20
21cfg_tt::cfg_tt! {
22/// Marker trait for all function pointers.
23pub trait FnPtr:
24    PartialEq
25    + Eq
26    + PartialOrd
27    + Ord
28    + Hash
29    + Pointer
30    + Debug
31    + Clone
32    + Copy
33    + Send
34    + Sync
35    + Unpin
36    + UnwindSafe
37    + RefUnwindSafe
38    + Sized
39    #[cfg(nightly_build)]
40    (+ core::marker::FnPtr)
41    + WithSafety<true>
42    + WithSafety<false>
43    + WithAbi<{ abi!("Rust") }>
44    + WithAbi<{ abi!("C") }>
45    + WithAbi<{ abi!("system") }>
46{
47    /// The argument types as a tuple.
48    type Args;
49
50    /// The return type.
51    type Output;
52
53    /// The function's arity (number of arguments).
54    const ARITY: usize;
55
56    /// Whether the function pointer is safe (fn) or unsafe (unsafe fn).
57    const IS_SAFE: bool;
58
59    /// Whether the function pointer uses an extern calling convention.
60    const IS_EXTERN: bool;
61
62    /// The ABI associated with this function pointer.
63    const ABI: Abi;
64
65    /// Returns the address of this function.
66    #[must_use]
67    fn addr(&self) -> usize {
68        self.as_ptr() as usize
69    }
70    /// Constructs an instance from an address.
71    ///
72    /// # Safety
73    /// The given pointer has to point to a function of the correct type.
74    #[must_use]
75    unsafe fn from_addr(addr: usize) -> Self {
76        unsafe { Self::from_ptr(addr as UntypedFnPtr) }
77    }
78    /// Returns a untyped function pointer for this function.
79    #[must_use]
80    fn as_ptr(&self) -> UntypedFnPtr;
81    /// Constructs an instance from an untyped function pointer.
82    ///
83    /// # Safety
84    /// The given pointer has to point to a function of the correct type.
85    #[must_use]
86    #[allow(clippy::missing_safety_doc)] // false positive?
87    unsafe fn from_ptr(ptr: UntypedFnPtr) -> Self;
88
89    /// Produces an unsafe version of this function pointer.
90    #[must_use]
91    fn as_unsafe(&self) -> make_unsafe!(Self) {
92        unsafe { FnPtr::from_ptr(self.as_ptr()) }
93    }
94
95    /// Produces a safe version of this function pointer.
96    ///
97    /// # Safety
98    /// Caller must ensure the underlying function is actually safe to call.
99    #[must_use]
100    unsafe fn as_safe(&self) -> make_safe!(Self) {
101        unsafe { FnPtr::from_ptr(self.as_ptr()) }
102    }
103
104    /// Produces a version of this function pointer with the given ABI.
105    ///
106    /// # Safety
107    /// Caller must ensure that the resulting ABI transformation is sound.
108    #[must_use]
109    unsafe fn with_abi<const ABI: AbiKey>(&self) -> <Self as WithAbi<ABI>>::F
110    where
111        Self: WithAbi<ABI>,
112    {
113        unsafe { FnPtr::from_ptr(self.as_ptr()) }
114    }
115}
116}
117
118/// Marker trait for all *safe* function pointer types (`fn` / `extern fn`).
119pub trait SafeFnPtr: FnPtr {
120    /// Invokes the function pointed to with the given args.
121    ///
122    /// # Examples
123    ///
124    /// ```
125    /// # use fn_ptr::SafeFnPtr;
126    /// fn add(a: i32, b: i32) -> i32 { a + b }
127    ///
128    /// let f: fn(i32, i32) -> i32 = add;
129    /// let result = f.invoke((2, 3));
130    /// assert_eq!(result, 5);
131    /// ```
132    // NOTE: Can't use "call" due to fn_traits feature
133    fn invoke(&self, args: Self::Args) -> Self::Output;
134}
135
136/// Marker trait for all *unsafe* function pointer types (`unsafe fn` / `unsafe extern fn`).
137pub trait UnsafeFnPtr: FnPtr {
138    /// Invokes the function pointed to with the given args.
139    ///
140    /// # Safety
141    /// Calling this function pointer is unsafe because the function may have
142    /// invariants that must be manually upheld by the caller.
143    ///
144    /// # Examples
145    ///
146    /// ```
147    /// # use fn_ptr::UnsafeFnPtr;
148    /// unsafe fn add(a: *const i32, b: *const i32) -> i32 { *a + *b }
149    ///
150    /// let f: unsafe fn(*const i32, *const i32) -> i32 = add;
151    /// let result = unsafe { f.invoke((&2, &3)) };
152    /// assert_eq!(result, 5);
153    /// ```
154    // NOTE: Can't use "call" due to fn_traits feature
155    unsafe fn invoke(&self, args: Self::Args) -> Self::Output;
156}
157
158/// Marker trait for all *static* function pointer types.
159/// The return type and all parameter types have to be `'static`.
160pub trait StaticFnPtr: FnPtr + 'static {}
161
162/// Marker trait implemented for function pointers of a specific ABI.
163///
164/// For example:
165/// - `HasAbi<Abi::C>` for `extern "C" fn(...)`
166/// - `HasAbi<Abi::Sysv64>` for `extern "sysv64" fn(...)`
167pub trait HasAbi<const ABI: AbiKey>: FnPtr {}
168
169/// Marker trait denoting the safety of a function pointer type.
170///
171/// For example:
172/// - `HasSafety<true>` for `extern "C" fn(...)`
173/// - `HasSafety<false>` for `unsafe fn(...)`
174pub trait HasSafety<const B: bool> {}
175impl<T: SafeFnPtr> HasSafety<true> for T {}
176impl<T: UnsafeFnPtr> HasSafety<false> for T {}