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 utility crate for **introspecting** and **rewriting** function pointer types at compile time.
7//!
8//! It implements [`FnPtr`] for all function-pointer types:
9//! - `fn(T) -> U`
10//! - `unsafe fn(T) -> U`
11//! - `extern "C-unwind" fn(T)`
12//! - `unsafe extern "sysv64" fn() -> i32`
13//!
14//! ## Function pointer metadata
15//!
16//! [`FnPtr`] exposes metadata as associated types/consts.
17//!
18//! ```rust
19//! use fn_ptr::{FnPtr, AbiValue};
20//!
21//! type F = extern "C" fn(i32, i32) -> i32;
22//! assert_eq!(<F as FnPtr>::ARITY, 2);
23//! assert_eq!(<F as FnPtr>::IS_SAFE, true);
24//! assert_eq!(<F as FnPtr>::IS_EXTERN, true);
25//! assert_eq!(<F as FnPtr>::ABI, AbiValue::C { unwind: false });
26//! ```
27//!
28//! Ergonomic const functions are provided as well:
29//!
30//! ```rust
31//! # type F = extern "C" fn(i32, i32) -> i32;
32//! # use fn_ptr::{FnPtr, AbiValue};
33//! const A: usize = fn_ptr::arity::<F>();
34//! const SAFE: bool = fn_ptr::is_safe::<F>();
35//! const EXT: bool = fn_ptr::is_extern::<F>();
36//! const ABI: AbiValue = fn_ptr::abi::<F>();
37//! ```
38//!
39//! ## Rewriting function-pointer types
40//!
41//! The crate provides type-level rewriting via traits:
42//!
43//! - **abi:** [`WithAbi`] / [`with_abi!`]
44//! - **Safety:** [`WithSafety`] / [`with_safety!`] ([`make_safe!`], [`make_unsafe!`])
45//! - **Output:** [`WithOutput`] / [`with_output!`]
46//! - **Args:** [`WithArgs`] / [`with_args!`]
47//!
48//! ### Type-level transformations
49//!
50//! The macros compute a new function-pointer **type** while preserving everything else.
51//!
52//! ```rust
53//! use fn_ptr::{with_abi, with_safety, with_output, with_args};
54//!
55//! type F = extern "C" fn(i32) -> i32;
56//!
57//! type F1 = with_abi!("sysv64", F);   // extern "sysv64" fn(i32) -> i32
58//! type F2 = with_safety!(unsafe, F);  // unsafe extern "C" fn(i32) -> i32
59//! type F3 = with_output!(u64, F);     // extern "C" fn(i32) -> u64
60//! type F4 = with_args!((u8, u16), F); // extern "C" fn(u8, u16) -> i32
61//! ```
62//!
63//! ### Value-level casts
64//!
65//! The same transformations exist at the value level via methods on [`FnPtr`].
66//! These casts are only [`transmuting`](core::mem::transmute) and do **not** the actual underlying function.
67//!
68//! ```rust
69//! use fn_ptr::{FnPtr, abi};
70//!
71//! let f: fn(i32, i32) -> i32 = |a, b| a + b;
72//!
73//! // safety
74//! let u: unsafe fn(i32, i32) -> i32 = f.as_unsafe();
75//! let f2: fn(i32, i32) -> i32 = unsafe { u.as_safe() };
76//!
77//! // abi
78//! let c: extern "C" fn(i32, i32) -> i32 = unsafe { f.with_abi::<abi!("C")>() };
79//!
80//! // output
81//! let out: fn(i32, i32) -> u64 = unsafe { f.with_output::<u64>() };
82//!
83//! // args
84//! let args: fn(u8, u16) -> i32 = unsafe { f.with_args::<(u8, u16)>() };
85//!
86//! # assert_eq!(f.addr(), f2.addr());
87//! # assert_eq!(f.addr(), c.addr());
88//! # assert_eq!(f.addr(), out.addr());
89//! # assert_eq!(f.addr(), args.addr());
90//! ```
91//! ## How it works
92//!
93//! Implementations are generated by a large [macro](https://github.com/OpenByteDev/fn-ptr/blob/master/src/impl.rs). The rewrite macros are thin wrappers
94//! over the traits [`WithAbi`], [`WithSafety`], [`WithOutput`], [`WithArgs`] (and the corresponding `*Impl` helper traits).
95
96/// Module containing the Abi abstraction.
97mod abi_value;
98pub use abi_value::AbiValue;
99
100mod r#impl;
101
102/// Module containing safety related marker types and traits.
103pub mod safety;
104pub use safety::Safety;
105/// Module containing abi related marker types and traits.
106pub mod abi;
107pub use abi::Abi;
108/// Module containing arity related marker types and traits.
109pub mod arity;
110pub use arity::Arity;
111
112/// Prelude for this crate.
113pub mod prelude;
114
115mod base;
116pub use base::*;
117
118mod build;
119pub use build::*;
120
121mod tuple;
122pub use tuple::*;
123
124mod conv;
125pub use conv::*;
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 external abi.
146#[must_use]
147pub const fn is_extern<F: FnPtr>() -> bool {
148    F::IS_EXTERN
149}
150
151/// Returns a runtime representation of the abi of the function pointer.
152#[must_use]
153pub const fn abi<F: FnPtr>() -> AbiValue {
154    F::ABI
155}