fn_ptr/conversion.rs
1use crate::{FnPtr, HasAbi, HasSafety, abi::AbiKey};
2
3/// Computes the function pointer type obtained by changing the ABI
4/// while preserving arity, arguments, return type, and safety.
5pub trait WithAbi<const ABI: AbiKey> {
6 /// The function pointer type with the requested ABI (preserving safety and signature).
7 type F: FnPtr + HasAbi<ABI>;
8}
9
10/// Computes the function pointer type obtained by switching between safe/unsafe
11/// while preserving arity, ABI, and signature.
12pub trait WithSafety<const SAFE: bool> {
13 /// The function pointer type with the requested safety (preserving ABI and signature).
14 type F: FnPtr + HasSafety<SAFE>;
15}
16
17/// Construct a function-pointer type identical to the given one but using
18/// the specified ABI.
19///
20/// Accepts either:
21/// - an `Abi` value (e.g., `Abi::C`, `Abi::Sysv64`), or
22/// - a string literal (e.g., `"C"`, `"system"`, `"stdcall"`).
23///
24/// # Examples
25///
26/// ```rust
27/// # use fn_ptr::{with_abi, Abi};
28/// type F = extern "C" fn(i32) -> i32;
29///
30/// type G = with_abi!(Abi::Sysv64, F);
31/// // `G` is `extern "sysv64" fn(i32) -> i32`
32///
33/// type H = with_abi!("C", extern "system" fn());
34/// // `H` is `extern "C" fn()`
35/// ```
36#[macro_export]
37macro_rules! with_abi {
38 // ABI given as a path (Abi::C, Abi::Sysv64, ...)
39 ( $abi:path, $ty:ty ) => {
40 <$ty as $crate::WithAbi<{ $crate::abi::key($abi) }>>::F
41 };
42
43 // ABI given as a string literal
44 ( $abi_lit:literal, $ty:ty ) => {
45 <$ty as $crate::WithAbi<{ $crate::abi!($abi_lit) }>>::F
46 };
47}
48
49/// Convert a function-pointer type to the *safe* variant of the same
50/// signature. Arguments, return type, and ABI are preserved.
51///
52/// # Example
53///
54/// ```rust
55/// # use fn_ptr::make_safe;
56/// type U = unsafe extern "C" fn(i32);
57/// type S = make_safe!(U);
58/// // `S` is `extern "C" fn(i32)`
59/// ```
60#[macro_export]
61macro_rules! make_safe {
62 ( $ty:ty ) => {
63 <$ty as $crate::WithSafety<{ true }>>::F
64 };
65}
66
67/// Convert a function-pointer type to the *unsafe* variant of the same
68/// signature. Arguments, return type, and ABI are preserved.
69///
70/// # Example
71///
72/// ```rust
73/// # use fn_ptr::make_unsafe;
74/// type S = extern "C" fn(i32);
75/// type U = make_unsafe!(S);
76/// // `U` is `unsafe extern "C" fn(i32)`
77/// ```
78#[macro_export]
79macro_rules! make_unsafe {
80 ( $ty:ty ) => {
81 <$ty as $crate::WithSafety<{ false }>>::F
82 };
83}
84
85/// Convert a function-pointer type to an `extern` function that uses
86/// the specified ABI. Arguments, return type, and safety are preserved.
87///
88/// # Example
89///
90/// ```rust
91/// # use fn_ptr::{make_extern, Abi};
92/// type F = fn(i32) -> i32;
93/// type C = make_extern!(Abi::C, F);
94/// // `C` is `extern "C" fn(i32) -> i32`
95/// ```
96///
97/// Equivalent to:
98/// ```rust
99/// # use fn_ptr::{Abi, with_abi};
100/// # type F = fn(i32) -> i32;
101/// # type G =
102/// with_abi!(Abi::C, F)
103/// # ;
104/// ```
105#[macro_export]
106macro_rules! make_extern {
107 ( $abi:path, $ty:ty ) => {
108 $crate::with_abi!($abi, $ty)
109 };
110}
111
112/// Convert a function-pointer type to a Rust-ABI (`fn`) function while
113/// preserving its arguments, return type, and safety.
114///
115/// # Example
116///
117/// ```rust
118/// # use fn_ptr::make_non_extern;
119/// type F = extern "C" fn(i32) -> i32;
120/// type R = make_non_extern!(F);
121/// // `R` is `fn(i32) -> i32`
122/// ```
123///
124/// Equivalent to:
125/// ```rust
126/// # use fn_ptr::{Abi, with_abi};
127/// # type F = extern "C" fn(i32) -> i32;
128/// # type G =
129/// with_abi!(Abi::Rust, F)
130/// # ;
131/// ```
132#[macro_export]
133macro_rules! make_non_extern {
134 ( $ty:ty ) => {
135 $crate::with_abi!($crate::Abi::Rust, $ty)
136 };
137}