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`] as well as a bunch of other related traits.
19//! With these you can inspect the type of function pointers at compile time:
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 { unwind: false });
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//! use fn_ptr::{with_abi, Abi};
73//!
74//! type F = extern "C" fn(i32) -> i32;
75//!
76//! type G = with_abi!("sysv64", F);
77//! type H = with_abi!("C", extern "system" fn());
78//! ```
79//!
80//! Or at the instance level:
81//!
82//! ```rust
83//! use fn_ptr::{FnPtr, abi};
84//! let rust_add: fn(i32, i32) -> i32 = |a, b| {a + b};
85//! // Safety: not actually safe!
86//! let c_add: extern "C" fn(i32, i32) -> i32 = unsafe { rust_add.with_abi::<abi!("C")>() };
87//! # assert_eq!(rust_add.addr(), c_add.addr());
88//! ```
89//!
90//! Note that this does not change the underlying ABI and should be used with caution.
91//!
92//! ## How It Works
93//!
94//! 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).
95//! For the conversion macros the crate relies on two traits: [`WithAbi`] and [`WithSafety`] that can also be used directly:
96//!
97//! ```rust
98//! use fn_ptr::{FnPtr, WithAbi, WithSafety, marker::{SysV64, Unsafe}};
99//!
100//! type F = extern "C" fn(i32);
101//! type G = <F as WithAbi<SysV64>>::F;
102//! type U = <F as WithSafety<Unsafe>>::F;
103//! ```
104//!
105//! ## License
106//!
107//! Licensed under the MIT license, see [LICENSE](https://github.com/OpenByteDev/fn-ptr/blob/master/LICENSE) for details.
108
109/// Module containing the Abi abstraction.
110pub mod abi;
111pub use abi::Abi;
112
113mod r#impl;
114
115/// Module containing all marker types and traits.
116pub mod marker;
117
118/// Prelude for this crate.
119pub mod prelude;
120
121mod base;
122pub use base::*;
123
124mod conversion;
125pub use conversion::*;
126
127/// Returns the number of arguments of a function pointer type.
128#[must_use]
129pub const fn arity<F: FnPtr>() -> usize {
130    F::ARITY
131}
132
133/// Returns `true` for safe function pointers (`fn`).
134#[must_use]
135pub const fn is_safe<F: FnPtr>() -> bool {
136    F::IS_SAFE
137}
138
139/// Returns `true` for unsafe function pointers (`unsafe fn`).
140#[must_use]
141pub const fn is_unsafe<F: FnPtr>() -> bool {
142    !is_safe::<F>()
143}
144
145/// Returns `true` if the function pointer uses an extern ABI.
146#[must_use]
147pub const fn is_extern<F: FnPtr>() -> bool {
148    F::IS_EXTERN
149}
150
151/// Returns the ABI of the function pointer.
152#[must_use]
153pub const fn abi<F: FnPtr>() -> Abi {
154    F::ABI
155}