fn_ptr/lib.rs
1#![cfg_attr(nightly_build, fn_ptr_trait)]
2#![cfg_attr(has_abi_vectorcall, feature(abi_vectorcall))]
3#![warn(clippy::pedantic, missing_docs)]
4#![no_std]
5
6//! `fn-ptr` is a small utility crate that provides a [`FnPtr`] trait, implemented for all function pointer types:
7//! - `fn(T) -> U`
8//! - `unsafe fn(T) -> U`
9//! - `extern "C" fn(T)`
10//! - `unsafe extern "sysv64" fn() -> i32`
11//!
12//! The trait provides associated types and constants to introspect function pointer types at compile time.
13//!
14//! ## Features
15//!
16//! ### 1. Function Pointer Metadata
17//!
18//! Every function pointer automatically implements [`FnPtr`].
19//! Depending on the type, they also implement [`SafeFnPtr`], [`UnsafeFnPtr`], and [`HasAbi<Abi>`].
20//! With it you can inspect the type of function:
21//!
22//! ```rust
23//! use fn_ptr::{FnPtr, Abi};
24//!
25//! type F = extern "C" fn(i32, i32) -> i32;
26//!
27//! assert_eq!(<F as FnPtr>::ARITY, 2);
28//! assert_eq!(<F as FnPtr>::IS_SAFE, true);
29//! assert_eq!(<F as FnPtr>::IS_EXTERN, true);
30//! assert_eq!(<F as FnPtr>::ABI, Abi::C { unwind: false });
31//! ```
32//!
33//! There are also some const helper functons to do so ergonomically.
34//!
35//! ```rust
36//! # type F = extern "C" fn(i32, i32) -> i32;
37//! # use fn_ptr::{FnPtr, Abi};
38//! const A: usize = fn_ptr::arity::<F>(); // 2
39//! const SAFE: bool = fn_ptr::is_safe::<F>(); // true
40//! const EXT: bool = fn_ptr::is_extern::<F>(); // true
41//! const ABI: Abi = fn_ptr::abi::<F>(); // Abi::C
42//! ```
43//!
44//! ### 2. Toggle Function Pointer Safety
45//!
46//! You can toggle the safety of a function pointer at the type level:
47//!
48//! ```rust
49//! use fn_ptr::{make_safe, make_unsafe};
50//!
51//! type U = unsafe extern "C" fn(i32);
52//! type S = make_safe!(U); // extern "C" fn(i32)
53//!
54//! type S2 = extern "C" fn(i32);
55//! type U2 = make_unsafe!(S2); // unsafe extern "C" fn(i32)
56//! ```
57//!
58//! Or at the instance level:
59//!
60//! ```rust
61//! # use fn_ptr::FnPtr;
62//! let safe_add: fn(i32, i32) -> i32 = |a, b| {a + b};
63//! let unsafe_add: unsafe fn(i32, i32) -> i32 = safe_add.as_unsafe();
64//! let safe_add2: fn(i32, i32) -> i32 = unsafe { unsafe_add.as_safe() };
65//! # assert_eq!(safe_add.addr(), safe_add2.addr());
66//! ```
67//!
68//! ### 3. Changing ABIs
69//!
70//! You can also change the ABI of a function pointer at the type level:
71//!
72//! ```rust
73//! # #[cfg(nightly_build)] {
74//! use fn_ptr::{with_abi, Abi};
75//!
76//! type F = extern "C" fn(i32) -> i32;
77//!
78//! type G = with_abi!(Abi::Sysv64, F);
79//! type H = with_abi!("C", extern "system" fn());
80//! # }
81//! ```
82//!
83//! Or at the instance level:
84//!
85//! ```rust
86//! use fn_ptr::{FnPtr, markers};
87//! let rust_add: fn(i32, i32) -> i32 = |a, b| {a + b};
88//! // Safety: not actually safe!
89//! let c_add: extern "C" fn(i32, i32) -> i32 = unsafe { rust_add.with_abi::<markers::abi!("C")>() };
90//! # assert_eq!(rust_add.addr(), c_add.addr());
91//! ```
92//!
93//! Note that this does not change the underlying ABI and should be used with caution.
94//!
95//! ## How It Works
96//!
97//! To implement the traits for all function pointer types, there is a large [macro](https://github.com/OpenByteDev/fn-ptr/blob/master/src/impl.rs).
98//! For the conversion macros the crate relies on two traits: [`WithAbi`] and [`WithSafety`] that can also be used directly:
99//!
100//! ```rust
101//! # #[cfg(nightly_build)] {
102//! use fn_ptr::{FnPtr, WithAbi, WithSafety, Abi};
103//!
104//! type F = extern "C" fn(i32);
105//! type G = <F as WithAbi<{Abi::Sysv64}>>::F;
106//! type U = <F as WithSafety<{false}>>::F;
107//! # }
108//! ```
109//!
110//! ## License
111//!
112//! Licensed under the MIT license, see [LICENSE](https://github.com/OpenByteDev/fn-ptr/blob/master/LICENSE) for details.
113
114/// Module containing the Abi abstraction.
115pub mod abi;
116pub use abi::Abi;
117
118mod r#impl;
119
120/// Module containing all marker types and traits.
121pub mod markers;
122
123/// Prelude for this crate.
124pub mod prelude;
125
126mod base;
127pub use base::*;
128
129mod conversion;
130pub use conversion::*;
131
132/// Returns the number of arguments of a function pointer type.
133#[must_use]
134pub const fn arity<F: FnPtr>() -> usize {
135 F::ARITY
136}
137
138/// Returns `true` for safe function pointers (`fn`).
139#[must_use]
140pub const fn is_safe<F: FnPtr>() -> bool {
141 F::IS_SAFE
142}
143
144/// Returns `true` for unsafe function pointers (`unsafe fn`).
145#[must_use]
146pub const fn is_unsafe<F: FnPtr>() -> bool {
147 !is_safe::<F>()
148}
149
150/// Returns `true` if the function pointer uses an extern ABI.
151#[must_use]
152pub const fn is_extern<F: FnPtr>() -> bool {
153 F::IS_EXTERN
154}
155
156/// Returns the ABI of the function pointer.
157#[must_use]
158pub const fn abi<F: FnPtr>() -> Abi {
159 F::ABI
160}