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