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 {}