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