fn_ptr/
base.rs

1use core::{
2    fmt::{Debug, Pointer},
3    hash::Hash,
4    panic::{RefUnwindSafe, UnwindSafe},
5};
6
7use crate::{
8    AsSafe, AsUnsafe, WithAbi, WithSafety,
9    abi::Abi,
10    make_safe, make_unsafe,
11    marker::{self, Safe, Unsafe},
12    with_abi, with_safety,
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    #[cfg(nightly_build)]
42    (+ core::marker::FnPtr)
43{
44    /// The argument types as a tuple.
45    type Args;
46
47    /// The return type.
48    type Output;
49
50    /// Marker type denoting arity
51    type ArityMarker: marker::Arity;
52    /// Marker type denoting safety
53    type SafetyMarker: marker::Safety;
54    /// Marker type denoting abi
55    type AbiMarker: marker::Abi;
56
57    /// The function's arity (number of arguments).
58    const ARITY: usize;
59
60    /// Whether the function pointer is safe (fn) or unsafe (unsafe fn).
61    const IS_SAFE: bool;
62
63    /// Whether the function pointer uses an extern calling convention.
64    const IS_EXTERN: bool;
65
66    /// The ABI associated with this function pointer.
67    const ABI: Abi;
68
69    /// Returns the address of this function.
70    #[must_use]
71    fn addr(&self) -> usize {
72        self.as_ptr() as usize
73    }
74    /// Constructs an instance from an address.
75    ///
76    /// # Safety
77    /// The given pointer has to point to a function of the correct type.
78    #[must_use]
79    unsafe fn from_addr(addr: usize) -> Self {
80        unsafe { Self::from_ptr(addr as UntypedFnPtr) }
81    }
82    /// Returns a untyped function pointer for this function.
83    #[must_use]
84    fn as_ptr(&self) -> UntypedFnPtr;
85    /// Constructs an instance from an untyped function pointer.
86    ///
87    /// # Safety
88    /// The given pointer has to point to a function of the correct type.
89    #[must_use]
90    #[allow(clippy::missing_safety_doc)] // false positive?
91    unsafe fn from_ptr(ptr: UntypedFnPtr) -> Self;
92
93    /// Produces an unsafe version of this function pointer.
94    #[must_use]
95    fn as_unsafe(&self) -> make_unsafe!(Self) where Self: AsUnsafe {
96        unsafe { FnPtr::from_ptr(self.as_ptr()) }
97    }
98
99    /// Produces a safe version of this function pointer.
100    ///
101    /// # Safety
102    /// Caller must ensure the underlying function is actually safe to call.
103    #[must_use]
104    unsafe fn as_safe(&self) -> make_safe!(Self) where Self: AsSafe {
105        unsafe { FnPtr::from_ptr(self.as_ptr()) }
106    }
107
108    /// Produces a version of this function pointer with the given ABI.
109    ///
110    /// # Safety
111    /// Caller must ensure that the resulting ABI transformation is sound.
112    #[must_use]
113    unsafe fn with_abi<Abi: marker::Abi>(&self) -> with_abi!(Abi, Self)
114    where
115        Self: WithAbi<Abi>,
116    {
117        unsafe { FnPtr::from_ptr(self.as_ptr()) }
118    }
119
120    /// Produces a version of this function pointer with the given safety.
121    ///
122    /// # Safety
123    /// Caller must ensure that this function pointer is safe when casting to a safe function.
124    #[must_use]
125    unsafe fn with_safety<Safety: marker::Safety>(&self) -> with_safety!(Safety, Self)
126    where
127        Self: WithSafety<Safety>,
128    {
129        unsafe { FnPtr::from_ptr(self.as_ptr()) }
130    }
131}
132}
133
134/// Marker trait for all callable *safe* function pointer types (`fn` / `extern fn`).
135pub trait SafeFnPtr: FnPtr<SafetyMarker = Safe> {
136    /// Invokes the function pointed to with the given args.
137    ///
138    /// # Examples
139    ///
140    /// ```
141    /// # use fn_ptr::SafeFnPtr;
142    /// fn add(a: i32, b: i32) -> i32 { a + b }
143    ///
144    /// let f: fn(i32, i32) -> i32 = add;
145    /// let result = f.invoke((2, 3));
146    /// assert_eq!(result, 5);
147    /// ```
148    // NOTE: Can't use "call" due to fn_traits feature
149    fn invoke(&self, args: Self::Args) -> Self::Output;
150}
151
152/// Marker trait for all callable *unsafe* function pointer types (`unsafe fn` / `unsafe extern fn`).
153pub trait UnsafeFnPtr: FnPtr<SafetyMarker = Unsafe> {
154    /// Invokes the function pointed to with the given args.
155    ///
156    /// # Safety
157    /// Calling this function pointer is unsafe because the function may have
158    /// invariants that must be manually upheld by the caller.
159    ///
160    /// # Examples
161    ///
162    /// ```
163    /// # use fn_ptr::UnsafeFnPtr;
164    /// unsafe fn add(a: *const i32, b: *const i32) -> i32 { *a + *b }
165    ///
166    /// let f: unsafe fn(*const i32, *const i32) -> i32 = add;
167    /// let result = unsafe { f.invoke((&2, &3)) };
168    /// assert_eq!(result, 5);
169    /// ```
170    // NOTE: Can't use "call" due to fn_traits feature
171    unsafe fn invoke(&self, args: Self::Args) -> Self::Output;
172}
173
174/// Marker trait for all *static* function pointer types.
175/// The return type and all parameter types have to be `'static`.
176pub trait StaticFnPtr: FnPtr + 'static {}
177
178/// Marker trait implemented for function pointers of a specific ABI.
179///
180/// For example:
181/// - `HasAbi<marker::C>` for `extern "C" fn(...)`
182/// - `HasAbi<marker::Sysv64>` for `extern "sysv64" fn(...)`
183pub trait HasAbi<Abi: marker::Abi>: FnPtr {}
184
185/// Marker trait denoting the safety of a function pointer type.
186///
187/// For example:
188/// - `HasSafety<Safe>` for `extern "C" fn(...)`
189/// - `HasSafety<Unsafe>` for `unsafe fn(...)`
190pub trait HasSafety<Safety: marker::Safety> {}
191impl<F: FnPtr> HasSafety<F::SafetyMarker> for F {}