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