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,
9    abi::Abi,
10    make_safe, make_unsafe,
11    markers::{self, Safe, Unsafe},
12    with_abi,
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: markers::Arity;
52    /// Marker type denoting safety
53    type SafetyMarker: markers::Safety;
54    /// Marker type denoting abi
55    type AbiMarker: markers::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: markers::Abi>(&self) -> with_abi!(Abi, Self)
114    where
115        Self: WithAbi<Abi>,
116    {
117        unsafe { FnPtr::from_ptr(self.as_ptr()) }
118    }
119}
120}
121
122/// Marker trait for all callable *safe* function pointer types (`fn` / `extern fn`).
123pub trait SafeFnPtr: FnPtr<SafetyMarker = Safe> {
124    /// Invokes the function pointed to with the given args.
125    ///
126    /// # Examples
127    ///
128    /// ```
129    /// # use fn_ptr::SafeFnPtr;
130    /// fn add(a: i32, b: i32) -> i32 { a + b }
131    ///
132    /// let f: fn(i32, i32) -> i32 = add;
133    /// let result = f.invoke((2, 3));
134    /// assert_eq!(result, 5);
135    /// ```
136    // NOTE: Can't use "call" due to fn_traits feature
137    fn invoke(&self, args: Self::Args) -> Self::Output;
138}
139
140/// Marker trait for all callable *unsafe* function pointer types (`unsafe fn` / `unsafe extern fn`).
141pub trait UnsafeFnPtr: FnPtr<SafetyMarker = Unsafe> {
142    /// Invokes the function pointed to with the given args.
143    ///
144    /// # Safety
145    /// Calling this function pointer is unsafe because the function may have
146    /// invariants that must be manually upheld by the caller.
147    ///
148    /// # Examples
149    ///
150    /// ```
151    /// # use fn_ptr::UnsafeFnPtr;
152    /// unsafe fn add(a: *const i32, b: *const i32) -> i32 { *a + *b }
153    ///
154    /// let f: unsafe fn(*const i32, *const i32) -> i32 = add;
155    /// let result = unsafe { f.invoke((&2, &3)) };
156    /// assert_eq!(result, 5);
157    /// ```
158    // NOTE: Can't use "call" due to fn_traits feature
159    unsafe fn invoke(&self, args: Self::Args) -> Self::Output;
160}
161
162/// Marker trait for all *static* function pointer types.
163/// The return type and all parameter types have to be `'static`.
164pub trait StaticFnPtr: FnPtr + 'static {}
165
166/// Marker trait implemented for function pointers of a specific ABI.
167///
168/// For example:
169/// - `HasAbi<markers::C>` for `extern "C" fn(...)`
170/// - `HasAbi<markers::Sysv64>` for `extern "sysv64" fn(...)`
171pub trait HasAbi<Abi: markers::Abi>: FnPtr {}
172
173/// Marker trait denoting the safety of a function pointer type.
174///
175/// For example:
176/// - `HasSafety<Safe>` for `extern "C" fn(...)`
177/// - `HasSafety<Unsafe>` for `unsafe fn(...)`
178pub trait HasSafety<Safety: markers::Safety> {}
179impl<F: FnPtr> HasSafety<F::SafetyMarker> for F {}