fn_ptr/lib.rs
1#![cfg_attr(feature = "nightly", feature(adt_const_params))]
2//! # fn-ptr
3//!
4//! `fn-ptr` is a small utility crate that provides a [`FnPtr`] trait, implemented for all function pointer types:
5//! - `fn(T) -> U`
6//! - `unsafe fn(T) -> U`
7//! - `extern "C" fn(T)`
8//! - `unsafe extern "sysv64" fn() -> i32`
9//!
10//! The trait provides associated types and constants to introspect function pointer types at compile time.
11//!
12//! ```rust
13//! # use fn_ptr::Abi;
14//! #
15//! pub trait FnPtr {
16//! /// The argument types as a tuple.
17//! type Args;
18//!
19//! /// The return type.
20//! type Output;
21//!
22//! /// The function's arity (number of arguments).
23//! const ARITY: usize;
24//!
25//! /// Whether the function pointer is safe (`fn`) or unsafe (`unsafe fn`).
26//! const IS_SAFE: bool;
27//!
28//! /// Whether the function pointer uses an extern calling convention.
29//! const IS_EXTERN: bool;
30//!
31//! /// The ABI associated with this function pointer.
32//! const ABI: Abi;
33//! }
34//! ```
35//!
36//! ## Features
37//!
38//! ### 1. Function Pointer Metadata
39//!
40//! Every function pointer automatically implements [`FnPtr`]. Depending on the type, it may also implement [`SafeFnPtr`], [`UnsafeFnPtr`], and [`HasAbi<Abi>`].
41//!
42//! ```rust
43//! use fn_ptr::{FnPtr, Abi};
44//!
45//! type F = extern "C" fn(i32, i32) -> i32;
46//!
47//! assert_eq!(<F as FnPtr>::ARITY, 2);
48//! assert_eq!(<F as FnPtr>::IS_SAFE, true);
49//! assert_eq!(<F as FnPtr>::IS_EXTERN, true);
50//! assert_eq!(<F as FnPtr>::ABI, Abi::C);
51//! ```
52//!
53//! Const helper functions are also provided:
54//!
55//! ```rust
56//! # use fn_ptr::{FnPtr, Abi};
57//! # type F = extern "C" fn(i32, i32) -> i32;
58//! const A: usize = fn_ptr::arity::<F>(); // 2
59//! const SAFE: bool = fn_ptr::is_safe::<F>(); // true
60//! const EXT: bool = fn_ptr::is_extern::<F>(); // true
61//! const ABI: Abi = fn_ptr::abi::<F>(); // Abi::C
62//! ```
63//!
64//! ### 2. Changing ABIs at the Type Level
65//!
66//! You can change the ABI of a function pointer type using macros:
67//!
68//! ```rust
69//! # #[cfg(feature = "nightly")] {
70//! use fn_ptr::{with_abi, Abi};
71//!
72//! type F = extern "C" fn(i32) -> i32;
73//!
74//! type G = with_abi!(Abi::Sysv64, F);
75//! type H = with_abi!("C", extern "system" fn());
76//! }
77//! ```
78//!
79//! ### 3. Toggle Function Pointer Safety
80//!
81//! Macros are provided to make function pointers safe or unsafe:
82//!
83//! ```rust
84//! use fn_ptr::{make_safe, make_unsafe};
85//!
86//! type U = unsafe extern "C" fn(i32);
87//! type S = make_safe!(U); // extern "C" fn(i32)
88//!
89//! type S2 = extern "C" fn(i32);
90//! type U2 = make_unsafe!(S2); // unsafe extern "C" fn(i32)
91//! ```
92//!
93//! ## How It Works
94//!
95//! All macros rely on type-level traits [`WithAbi`] and [`WithSafety`]. Each trait exposes an associated type representing the transformed function pointer. You can use these traits directly for const generics or explicit type transformations:
96//!
97//! ```rust
98//! # #[cfg(feature = "nightly")] {
99//! use fn_ptr::{FnPtr, WithAbi, WithSafety, Abi};
100//!
101//! type F = extern "C" fn(i32);
102//! type G = <F as WithAbi<{Abi::Sysv64}, F>>::F;
103//! type U = <F as WithSafety<{false}, F>>::F;
104//! }
105//! ```
106//!
107//! ## License
108//!
109//! Licensed under the MIT license, see [LICENSE](https://github.com/OpenByteDev/fn-ptr/blob/master/LICENSE) for details.
110
111use core::{
112 fmt::{Debug, Pointer},
113 hash::Hash,
114 panic::{RefUnwindSafe, UnwindSafe},
115};
116
117/// Module containing the Abi abstraction.
118pub mod abi;
119pub use abi::Abi;
120
121mod r#impl;
122
123/// Marker trait for all function pointers.
124// list of implemented traits from https://rust.docs.kernel.org/core/primitive.fn.html#trait-implementations-1
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 + 'static
141{
142 /// The argument types as a tuple.
143 type Args;
144
145 /// The return type.
146 type Output;
147
148 /// The function's arity (number of arguments).
149 const ARITY: usize;
150
151 /// Whether the function pointer is safe (`fn`) or unsafe (`unsafe fn`).
152 const IS_SAFE: bool;
153
154 /// Whether the function pointer uses an extern calling convention.
155 const IS_EXTERN: bool;
156
157 /// The ABI associated with this function pointer.
158 const ABI: Abi;
159}
160
161/// Marker trait for all *safe* function pointer types (`fn` / `extern fn`).
162pub trait SafeFnPtr: FnPtr {}
163
164/// Marker trait for all *unsafe* function pointer types (`unsafe fn` / `unsafe extern fn`).
165pub trait UnsafeFnPtr: FnPtr {}
166
167/// Marker trait implemented for extern function pointers of a specific ABI.
168///
169/// For example:
170/// - `HasAbi<Abi::C>` for `extern "C" fn(...)`
171/// - `HasAbi<Abi::Sysv64>` for `extern "sysv64" fn(...)`
172#[cfg(feature = "nightly")]
173pub trait HasAbi<const ABI: Abi>: FnPtr {}
174
175/// Computes the function pointer type obtained by changing the ABI
176/// while preserving arity, arguments, return type, and safety.
177#[cfg(feature = "nightly")]
178pub trait WithAbi<const ABI: Abi, F: FnPtr> {
179 /// The function pointer type with the requested ABI (preserving safety and signature).
180 type F: FnPtr;
181}
182
183/// Computes the function pointer type obtained by switching between safe/unsafe
184/// while preserving arity, ABI, and signature.
185pub trait WithSafety<const SAFE: bool, F: FnPtr> {
186 /// The function pointer type with the requested safety (preserving ABI and signature).
187 type F: FnPtr;
188}
189
190/// Returns the number of arguments of a function pointer type.
191pub const fn arity<F: FnPtr>() -> usize {
192 F::ARITY
193}
194
195/// Returns `true` for safe function pointers (`fn`).
196pub const fn is_safe<F: FnPtr>() -> bool {
197 F::IS_SAFE
198}
199
200/// Returns `true` for unsafe function pointers (`unsafe fn`).
201pub const fn is_unsafe<F: FnPtr>() -> bool {
202 !is_safe::<F>()
203}
204
205/// Returns `true` if the function pointer uses an extern ABI.
206pub const fn is_extern<F: FnPtr>() -> bool {
207 F::IS_EXTERN
208}
209
210/// Returns the ABI of the function pointer.
211pub const fn abi<F: FnPtr>() -> Abi {
212 F::ABI
213}
214
215/// Construct a function-pointer type identical to the given one but using
216/// the specified ABI.
217///
218/// Accepts either:
219/// - an `Abi` value (e.g., `Abi::C`, `Abi::Sysv64`), or
220/// - a string literal (e.g., `"C"`, `"system"`, `"stdcall"`).
221///
222/// # Examples
223///
224/// ```rust
225/// # use fn_ptr::{with_abi, Abi};
226/// type F = extern "C" fn(i32) -> i32;
227///
228/// type G = with_abi!(Abi::Sysv64, F);
229/// // `G` is `extern "sysv64" fn(i32) -> i32`
230///
231/// type H = with_abi!("C", extern "system" fn());
232/// // `H` is `extern "C" fn()`
233/// ```
234#[cfg(feature = "nightly")]
235#[cfg_attr(feature = "nightly", macro_export)]
236macro_rules! with_abi {
237 // ABI given as a path (Abi::C, Abi::Sysv64, ...)
238 ( $abi:path, $ty:ty ) => {
239 <$ty as $crate::WithAbi<{ $abi }, $ty>>::F
240 };
241
242 // ABI given as a string literal
243 ( $abi_lit:literal, $ty:ty ) => {
244 <$ty as $crate::WithAbi<{ $crate::abi::parse_or_fail($abi_lit) }, $ty>>::F
245 };
246}
247
248/// Convert a function-pointer type to the *safe* variant of the same
249/// signature. Arguments, return type, and ABI are preserved.
250///
251/// # Example
252///
253/// ```rust
254/// # use fn_ptr::make_safe;
255/// type U = unsafe extern "C" fn(i32);
256/// type S = make_safe!(U);
257/// // `S` is `extern "C" fn(i32)`
258/// ```
259#[macro_export]
260macro_rules! make_safe {
261 ( $ty:ty ) => {
262 <$ty as $crate::WithSafety<{ true }, $ty>>::F
263 };
264}
265
266/// Convert a function-pointer type to the *unsafe* variant of the same
267/// signature. Arguments, return type, and ABI are preserved.
268///
269/// # Example
270///
271/// ```rust
272/// # use fn_ptr::make_unsafe;
273/// type S = extern "C" fn(i32);
274/// type U = make_unsafe!(S);
275/// // `U` is `unsafe extern "C" fn(i32)`
276/// ```
277#[macro_export]
278macro_rules! make_unsafe {
279 ( $ty:ty ) => {
280 <$ty as $crate::WithSafety<{ false }, $ty>>::F
281 };
282}
283
284/// Convert a function-pointer type to an `extern` function that uses
285/// the specified ABI. Arguments, return type, and safety are preserved.
286///
287/// # Example
288///
289/// ```rust
290/// # use fn_ptr::{make_extern, Abi};
291/// type F = fn(i32) -> i32;
292/// type C = make_extern!(Abi::C, F);
293/// // `C` is `extern "C" fn(i32) -> i32`
294/// ```
295///
296/// Equivalent to:
297/// ```rust
298/// # use fn_ptr::{Abi, with_abi};
299/// # type F = fn(i32) -> i32;
300/// # type G =
301/// with_abi!(Abi::C, F)
302/// # ;
303/// ```
304#[cfg(feature = "nightly")]
305#[cfg_attr(feature = "nightly", macro_export)]
306macro_rules! make_extern {
307 ( $abi:path, $ty:ty ) => {
308 $crate::with_abi!($abi, $ty)
309 };
310}
311
312/// Convert a function-pointer type to a Rust-ABI (`fn`) function while
313/// preserving its arguments, return type, and safety.
314///
315/// # Example
316///
317/// ```rust
318/// # use fn_ptr::make_non_extern;
319/// type F = extern "C" fn(i32) -> i32;
320/// type R = make_non_extern!(F);
321/// // `R` is `fn(i32) -> i32`
322/// ```
323///
324/// Equivalent to:
325/// ```rust
326/// # use fn_ptr::{Abi, with_abi};
327/// # type F = extern "C" fn(i32) -> i32;
328/// # type G =
329/// with_abi!(Abi::Rust, F)
330/// # ;
331/// ```
332#[cfg(feature = "nightly")]
333#[cfg_attr(feature = "nightly", macro_export)]
334macro_rules! make_non_extern {
335 ( $ty:ty ) => {
336 $crate::with_abi!($crate::Abi::Rust, $ty)
337 };
338}