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.
46pub trait Convertible:
47    FnPtr
48    + WithAbi<marker::Rust>
49    + WithAbi<marker::C>
50    + WithAbi<marker::CUnwind>
51    + WithAbi<marker::System>
52    + WithAbi<marker::SystemUnwind>
53    + WithSafety<marker::Safe>
54    + WithSafety<marker::Unsafe>
55    + AsSafe
56    + AsUnsafe
57    #[cfg(has_abi_aapcs)](+ WithAbi<marker::Aapcs>)
58    #[cfg(has_abi_aapcs)](+ WithAbi<marker::AapcsUnwind>)
59    #[cfg(has_abi_cdecl)](+ WithAbi<marker::Cdecl>)
60    #[cfg(has_abi_cdecl)](+ WithAbi<marker::CdeclUnwind>)
61    #[cfg(has_abi_stdcall)](+ WithAbi<marker::Stdcall>)
62    #[cfg(has_abi_stdcall)](+ WithAbi<marker::StdcallUnwind>)
63    #[cfg(has_abi_fastcall)](+ WithAbi<marker::Fastcall>)
64    #[cfg(has_abi_fastcall)](+ WithAbi<marker::FastcallUnwind>)
65    #[cfg(has_abi_thiscall)](+ WithAbi<marker::Thiscall>)
66    #[cfg(has_abi_thiscall)](+ WithAbi<marker::ThiscallUnwind>)
67    #[cfg(has_abi_vectorcall)](+ WithAbi<marker::Vectorcall>)
68    #[cfg(has_abi_vectorcall)](+ WithAbi<marker::VectorcallUnwind>)
69    #[cfg(has_abi_sysv64)](+ WithAbi<marker::SysV64>)
70    #[cfg(has_abi_sysv64)](+ WithAbi<marker::SysV64Unwind>)
71    #[cfg(has_abi_win64)](+ WithAbi<marker::Win64>)
72    #[cfg(has_abi_win64)](+ WithAbi<marker::Win64Unwind>)
73{
74}
75impl<T> Convertible for T
76where
77    T: FnPtr
78        + WithAbi<marker::Rust>
79        + WithAbi<marker::C>
80        + WithAbi<marker::CUnwind>
81        + WithAbi<marker::System>
82        + WithAbi<marker::SystemUnwind>
83        + WithSafety<marker::Safe>
84        + WithSafety<marker::Unsafe>
85        + AsSafe
86        + AsUnsafe
87        #[cfg(has_abi_aapcs)](+ WithAbi<marker::Aapcs>)
88        #[cfg(has_abi_aapcs)](+ WithAbi<marker::AapcsUnwind>)
89        #[cfg(has_abi_cdecl)](+ WithAbi<marker::Cdecl>)
90        #[cfg(has_abi_cdecl)](+ WithAbi<marker::CdeclUnwind>)
91        #[cfg(has_abi_stdcall)](+ WithAbi<marker::Stdcall>)
92        #[cfg(has_abi_stdcall)](+ WithAbi<marker::StdcallUnwind>)
93        #[cfg(has_abi_fastcall)](+ WithAbi<marker::Fastcall>)
94        #[cfg(has_abi_fastcall)](+ WithAbi<marker::FastcallUnwind>)
95        #[cfg(has_abi_thiscall)](+ WithAbi<marker::Thiscall>)
96        #[cfg(has_abi_thiscall)](+ WithAbi<marker::ThiscallUnwind>)
97        #[cfg(has_abi_vectorcall)](+ WithAbi<marker::Vectorcall>)
98        #[cfg(has_abi_vectorcall)](+ WithAbi<marker::VectorcallUnwind>)
99        #[cfg(has_abi_sysv64)](+ WithAbi<marker::SysV64>)
100        #[cfg(has_abi_sysv64)](+ WithAbi<marker::SysV64Unwind>)
101        #[cfg(has_abi_win64)](+ WithAbi<marker::Win64>)
102        #[cfg(has_abi_win64)](+ WithAbi<marker::Win64Unwind>)
103{}
104}
105
106/// Construct a function-pointer type identical to the given one but using
107/// the specified ABI.
108///
109/// Accepts either:
110/// - an `Abi` value (e.g., `Abi::C`, `Abi::SysV64`), or
111/// - a string literal (e.g., `"C"`, `"system"`, `"stdcall"`).
112///
113/// # Examples
114///
115/// ```rust
116/// # use fn_ptr::{with_abi, marker};
117/// type F = extern "C" fn(i32) -> i32;
118///
119/// type G = with_abi!(marker::SysV64, F);
120/// // `G` is `extern "sysv64" fn(i32) -> i32`
121///
122/// type H = with_abi!("C", extern "system" fn());
123/// // `H` is `extern "C" fn()`
124/// ```
125#[macro_export]
126macro_rules! with_abi {
127    // ABI given as a path (Abi::C, Abi::SysV64, ...)
128    ( $abi:path, $ty:ty ) => {
129        <$ty as $crate::WithAbi<$abi>>::F
130    };
131
132    // ABI given as a string literal
133    ( $abi_lit:tt, $ty:ty ) => {
134        <$ty as $crate::WithAbi<$crate::abi!($abi_lit)>>::F
135    };
136}
137
138/// Convert a function-pointer type to the *safe* variant of the same
139/// signature. Arguments, return type, and ABI are preserved.
140///
141/// # Example
142///
143/// ```rust
144/// # use fn_ptr::make_safe;
145/// type U = unsafe extern "C" fn(i32);
146/// type S = make_safe!(U);
147/// // `S` is `extern "C" fn(i32)`
148/// ```
149#[macro_export]
150macro_rules! make_safe {
151    ( $ty:ty ) => {
152        <$ty as $crate::WithSafety<$crate::marker::Safe>>::F
153    };
154}
155
156/// Convert a function-pointer type to the *unsafe* variant of the same
157/// signature. Arguments, return type, and ABI are preserved.
158///
159/// # Example
160///
161/// ```rust
162/// # use fn_ptr::make_unsafe;
163/// type S = extern "C" fn(i32);
164/// type U = make_unsafe!(S);
165/// // `U` is `unsafe extern "C" fn(i32)`
166/// ```
167#[macro_export]
168macro_rules! make_unsafe {
169    ( $ty:ty ) => {
170        <$ty as $crate::WithSafety<$crate::marker::Unsafe>>::F
171    };
172}