fn_ptr/
conversion.rs

1use crate::{
2    FnPtr, HasAbi, HasSafety,
3    marker::{self, Safe, Unsafe},
4};
5
6/// Helper trait to change the ABI of a function pointer type while preserving arity, safety, and signature.
7pub trait WithAbi<Abi>: FnPtr
8where
9    Abi: marker::Abi,
10{
11    /// The function pointer type with the requested ABI (preserving safety and signature).
12    type F: FnPtr<
13            Args = Self::Args,
14            Output = Self::Output,
15            ArityMarker = Self::ArityMarker,
16            SafetyMarker = Self::SafetyMarker,
17            AbiMarker = Abi,
18        > + HasAbi<Abi>;
19}
20
21/// Helper trait to change the safety of a function pointer type while preserving arity, ABI, and signature.
22pub trait WithSafety<Safety>: FnPtr
23where
24    Safety: marker::Safety,
25{
26    /// The function pointer type with the requested safety (preserving ABI and signature).
27    type F: FnPtr<
28            Args = Self::Args,
29            Output = Self::Output,
30            ArityMarker = Self::ArityMarker,
31            SafetyMarker = Safety,
32            AbiMarker = Self::AbiMarker,
33        > + HasSafety<Safety>;
34}
35
36/// Helper trait to compute the safe version of a function pointer type while preserving arity, ABI, and signature.
37pub trait AsSafe: WithSafety<Safe> {}
38impl<F: WithSafety<Safe>> AsSafe for F {}
39
40/// Helper trait to compute the unsafe version of a function pointer type while preserving arity, ABI, and signature.
41pub trait AsUnsafe: WithSafety<Unsafe> {}
42impl<F: WithSafety<Unsafe>> AsUnsafe for F {}
43
44cfg_tt::cfg_tt! {
45/// Helper trait that simplifies generic bounds when converting between funciton pointer types.
46// using has_abi_cdecl instead of stdcall, fastcall, thiscall is to reduce compile times
47pub trait Convertible:
48    FnPtr
49    + WithAbi<marker::Rust>
50    + WithAbi<marker::C>
51    + WithAbi<marker::CUnwind>
52    + WithAbi<marker::System>
53    + WithAbi<marker::SystemUnwind>
54    + WithSafety<marker::Safe>
55    + WithSafety<marker::Unsafe>
56    + AsSafe
57    + AsUnsafe
58    #[cfg(has_abi_aapcs)](+ WithAbi<marker::Aapcs>)
59    #[cfg(has_abi_aapcs)](+ WithAbi<marker::AapcsUnwind>)
60    #[cfg(has_abi_cdecl)](+ WithAbi<marker::Cdecl>)
61    #[cfg(has_abi_cdecl)](+ WithAbi<marker::CdeclUnwind>)
62    #[cfg(has_abi_cdecl)](+ WithAbi<marker::Stdcall>)
63    #[cfg(has_abi_cdecl)](+ WithAbi<marker::StdcallUnwind>)
64    #[cfg(has_abi_cdecl)](+ WithAbi<marker::Fastcall>)
65    #[cfg(has_abi_cdecl)](+ WithAbi<marker::FastcallUnwind>)
66    #[cfg(has_abi_cdecl)](+ WithAbi<marker::Thiscall>)
67    #[cfg(has_abi_cdecl)](+ WithAbi<marker::ThiscallUnwind>)
68    #[cfg(has_abi_vectorcall)](+ WithAbi<marker::Vectorcall>)
69    #[cfg(has_abi_vectorcall)](+ WithAbi<marker::VectorcallUnwind>)
70    #[cfg(has_abi_sysv64)](+ WithAbi<marker::SysV64>)
71    #[cfg(has_abi_sysv64)](+ WithAbi<marker::SysV64Unwind>)
72    #[cfg(has_abi_win64)](+ WithAbi<marker::Win64>)
73    #[cfg(has_abi_win64)](+ WithAbi<marker::Win64Unwind>)
74{
75}
76impl<T> Convertible for T
77where
78    T: FnPtr
79        + WithAbi<marker::Rust>
80        + WithAbi<marker::C>
81        + WithAbi<marker::CUnwind>
82        + WithAbi<marker::System>
83        + WithAbi<marker::SystemUnwind>
84        + WithSafety<marker::Safe>
85        + WithSafety<marker::Unsafe>
86        + AsSafe
87        + AsUnsafe
88        #[cfg(has_abi_aapcs)](+ WithAbi<marker::Aapcs>)
89        #[cfg(has_abi_aapcs)](+ WithAbi<marker::AapcsUnwind>)
90        #[cfg(has_abi_cdecl)](+ WithAbi<marker::Cdecl>)
91        #[cfg(has_abi_cdecl)](+ WithAbi<marker::CdeclUnwind>)
92        #[cfg(has_abi_cdecl)](+ WithAbi<marker::Stdcall>)
93        #[cfg(has_abi_cdecl)](+ WithAbi<marker::StdcallUnwind>)
94        #[cfg(has_abi_cdecl)](+ WithAbi<marker::Fastcall>)
95        #[cfg(has_abi_cdecl)](+ WithAbi<marker::FastcallUnwind>)
96        #[cfg(has_abi_cdecl)](+ WithAbi<marker::Thiscall>)
97        #[cfg(has_abi_cdecl)](+ WithAbi<marker::ThiscallUnwind>)
98        #[cfg(has_abi_vectorcall)](+ WithAbi<marker::Vectorcall>)
99        #[cfg(has_abi_vectorcall)](+ WithAbi<marker::VectorcallUnwind>)
100        #[cfg(has_abi_sysv64)](+ WithAbi<marker::SysV64>)
101        #[cfg(has_abi_sysv64)](+ WithAbi<marker::SysV64Unwind>)
102        #[cfg(has_abi_win64)](+ WithAbi<marker::Win64>)
103        #[cfg(has_abi_win64)](+ WithAbi<marker::Win64Unwind>)
104{}
105}
106
107/// Construct a function-pointer type identical to the given one but using
108/// the specified ABI.
109///
110/// Accepts either:
111/// - an [`Abi`](crate::marker::Abi) marker type (e.g., [`C`](crate::marker::C), [`SysV64`](crate::marker::SysV64)), or
112/// - a string literal (e.g., `"C"`, `"system"`, `"stdcall"`).
113///
114/// # Examples
115///
116/// ```rust
117/// # use fn_ptr::{with_abi, marker};
118/// type F = with_abi!(marker::SysV64, extern "C" fn(i32) -> i32);
119/// // `F` is `extern "sysv64" fn(i32) -> i32`
120///
121/// type G = with_abi!("C", extern "system" fn());
122/// // `G` is `extern "C" fn()`
123/// ```
124#[macro_export]
125macro_rules! with_abi {
126    ( $abi:path, $ty:ty ) => {
127        <$ty as $crate::WithAbi<$abi>>::F
128    };
129
130    ( $lit:tt, $ty:ty ) => {
131        <$ty as $crate::WithAbi<$crate::abi!($lit)>>::F
132    };
133}
134
135/// Construct a function-pointer type identical to the given one but using
136/// the specified safety.
137///
138/// Accepts either:
139/// - an [`Safety`](crate::marker::Safety) marker type ([`Safe`](crate::marker::Safe) or [`Unsafe`](crate::marker::Unsafe))
140/// - safety keyword (`safe` or `unsafe`).
141/// - a boolean literal.
142///
143/// # Examples
144///
145/// ```rust
146/// # use fn_ptr::{with_safety, marker};
147/// type F = with_safety!(marker::Safe, unsafe extern "C" fn(i32) -> i32);
148/// // `F` is `extern "C" fn(i32) -> i32`
149///
150/// type G = with_safety!(unsafe, fn());
151/// // `G` is `unsafe fn()`
152/// ```
153#[macro_export]
154macro_rules! with_safety {
155    ( safe, $ty:ty ) => {
156        $crate::with_safety!(@inner $crate::marker::Safe, $ty)
157    };
158    ( unsafe, $ty:ty ) => {
159        $crate::with_safety!(@inner $crate::marker::Unsafe, $ty)
160    };
161    ( $safety:path, $ty:ty ) => {
162        $crate::with_safety!(@inner $safety, $ty)
163    };
164    ( $safety:tt, $ty:ty ) => {
165        $crate::with_safety!(@inner $crate::safety!($safety), $ty)
166    };
167
168    ( @inner $safety:ty, $ty:ty ) => {
169        <$ty as $crate::WithSafety<$safety>>::F
170    };
171}
172
173/// Convert a function-pointer type to the *safe* variant of the same
174/// signature. Arguments, return type, and ABI are preserved.
175///
176/// # Example
177///
178/// ```rust
179/// # use fn_ptr::make_safe;
180/// type U = unsafe extern "C" fn(i32);
181/// type S = make_safe!(U);
182/// // `S` is `extern "C" fn(i32)`
183/// ```
184#[macro_export]
185macro_rules! make_safe {
186    ( $ty:ty ) => {
187        <$ty as $crate::WithSafety<$crate::marker::Safe>>::F
188    };
189}
190
191/// Convert a function-pointer type to the *unsafe* variant of the same
192/// signature. Arguments, return type, and ABI are preserved.
193///
194/// # Example
195///
196/// ```rust
197/// # use fn_ptr::make_unsafe;
198/// type S = extern "C" fn(i32);
199/// type U = make_unsafe!(S);
200/// // `U` is `unsafe extern "C" fn(i32)`
201/// ```
202#[macro_export]
203macro_rules! make_unsafe {
204    ( $ty:ty ) => {
205        <$ty as $crate::WithSafety<$crate::marker::Unsafe>>::F
206    };
207}