fn_ptr/conv.rs
1use crate::{
2 FnPtr, abi,
3 safety::{self, Safe, Unsafe},
4 tuple::Tuple,
5};
6
7/// Helper trait used by [`WithAbi`] (use it instead).
8/// This trait is required to allow [`FnPtr`] to be a subtrait of [`WithAbi`], which eliminates
9/// the need for a type bound when using a fixed abi marker.
10/// Using [`WithAbi`] directly would result in a cyclic supertrait error.
11pub trait WithAbiImpl<Abi: abi::Abi, F: FnPtr = Self> {
12 /// The function pointer type with the requested abi (preserving all other properties).
13 type F: FnPtr<Args = F::Args, Output = F::Output, Safety = F::Safety, Abi = Abi>;
14}
15
16/// Helper trait to change the abi of a function pointer type while preserving its safety, arguments and return type.
17///
18/// This is used by [`with_abi!`](crate::with_abi) under the hood.
19///
20/// # Example
21///
22/// ```rust
23/// # use fn_ptr::{abi, WithAbi};
24/// type F = extern "C" fn(i32) -> i32;
25/// type G = <F as WithAbi<abi::System>>::F;
26/// // `G` is `extern "system" fn(i32) -> i32`
27/// # static_assertions::assert_type_eq_all!(G, extern "system" fn(i32) -> i32);
28/// ```
29pub trait WithAbi<Abi: abi::Abi>: FnPtr {
30 /// The function pointer type with the requested abi (preserving all other properties).
31 type F: FnPtr<Args = Self::Args, Output = Self::Output, Safety = Self::Safety, Abi = Abi>;
32}
33impl<Abi: abi::Abi, F: FnPtr + WithAbiImpl<Abi, Self>> WithAbi<Abi> for F {
34 type F = <Self as WithAbiImpl<Abi, Self>>::F;
35}
36
37/// Helper trait used by [`WithSafety`] (use it instead).
38/// This trait is required to allow [`FnPtr`] to be a subtrait of [`WithSafety`], which eliminates
39/// the need for a type bound when using a fixed safety marker.
40/// Using [`WithSafety`] directly would result in a cyclic supertrait error.
41pub trait WithSafetyImpl<Safety: safety::Safety, F: FnPtr = Self> {
42 /// The function pointer type with the requested safety (preserving all other properties).
43 type F: FnPtr<Args = F::Args, Output = F::Output, Safety = Safety, Abi = F::Abi>;
44}
45
46/// Helper trait to change the safety of a function pointer type while preserving its abi, arguments and return type.
47///
48/// This is used by [`with_safety!`](crate::with_safety) under the hood.
49///
50/// # Example
51///
52/// ```rust
53/// # use fn_ptr::{WithSafety, safety};
54/// type F = extern "C" fn(i32) -> i32;
55/// type G = <F as WithSafety<safety::Unsafe>>::F;
56/// // `G` is `unsafe extern "C" fn(i32) -> i32`
57/// # static_assertions::assert_type_eq_all!(G, unsafe extern "C" fn(i32) -> i32);
58/// ```
59pub trait WithSafety<Safety: safety::Safety>: FnPtr {
60 /// The function pointer type with the requested safety (preserving all other properties).
61 type F: FnPtr<Args = Self::Args, Output = Self::Output, Safety = Safety, Abi = Self::Abi>;
62}
63impl<Safety: safety::Safety, F: FnPtr + WithSafetyImpl<Safety, Self>> WithSafety<Safety> for F {
64 type F = <Self as WithSafetyImpl<Safety, Self>>::F;
65}
66
67/// Helper trait to compute the safe version of a function pointer type while preserving its abi, arguments and return type. Equivalent to [`WithSafety<Safe>`].
68///
69/// # Example
70///
71/// ```rust
72/// # use fn_ptr::AsSafe;
73/// type U = unsafe extern "C" fn(i32) -> i32;
74/// type S = <U as AsSafe>::F;
75/// // `S` is `extern "C" fn(i32) -> i32`
76/// # static_assertions::assert_type_eq_all!(S, extern "C" fn(i32) -> i32);
77/// ```
78pub trait AsSafe: WithSafety<Safe> {
79 /// The safe version of this function pointer type.
80 type F: FnPtr<Args = Self::Args, Output = Self::Output, Safety = Safe, Abi = Self::Abi>;
81}
82impl<F: FnPtr + WithSafety<Safe>> AsSafe for F {
83 type F = <F as WithSafety<Safe>>::F;
84}
85
86/// Helper trait to compute the unsafe version of a function pointer type while preserving arity, abi and signature.
87///
88/// # Example
89///
90/// ```rust
91/// # use fn_ptr::AsUnsafe;
92/// type S = extern "C" fn(i32) -> i32;
93/// type U = <S as AsUnsafe<S>>::F;
94/// // `U` is `unsafe extern "C" fn(i32) -> i32`
95/// # static_assertions::assert_type_eq_all!(U, unsafe extern "C" fn(i32) -> i32);
96/// ```
97pub trait AsUnsafe<F: FnPtr>: WithSafety<Unsafe> {
98 /// The unsafe version of a function pointer type.
99 type F: FnPtr<Args = F::Args, Output = F::Output, Safety = Unsafe, Abi = F::Abi>;
100}
101impl<F: FnPtr + WithSafety<Unsafe>> AsUnsafe<F> for F {
102 type F = <F as WithSafety<Unsafe>>::F;
103}
104
105/// Helper trait used by [`WithOutput`] (use it instead).
106/// This trait is required to allow [`FnPtr`] to be a subtrait of [`WithOutput`], which eliminates
107/// the need for a type bound when using a fixed output type.
108/// Using [`WithOutput`] directly would result in a cyclic supertrait error.
109pub trait WithOutputImpl<F: FnPtr = Self> {
110 /// The function pointer type with the requested output type (preserving all other properties).
111 type F<T>: FnPtr<Args = F::Args, Output = T, Safety = F::Safety, Abi = F::Abi>;
112}
113
114/// Helper trait to change the return type of a function pointer type while preserving its safety, abi and arguments.
115///
116/// This is used by [`with_output!`](crate::with_output) under the hood.
117///
118/// # Example
119///
120/// ```rust
121/// # use fn_ptr::WithOutput;
122/// type F = extern "C" fn(i32) -> i32;
123/// type G = <F as WithOutput<u32>>::F;
124/// // `G` is `extern "C" fn(i32) -> u32`
125/// # static_assertions::assert_type_eq_all!(G, extern "C" fn(i32) -> u32);
126/// ```
127pub trait WithOutput<T>: FnPtr + WithOutputImpl<Self> {
128 /// The function pointer type with the requested return type (preserving all other properties).
129 type F: FnPtr<Args = Self::Args, Output = T, Safety = Self::Safety, Abi = Self::Abi>;
130}
131impl<Output, F: FnPtr + WithOutputImpl<Self>> WithOutput<Output> for F {
132 type F = <Self as WithOutputImpl<Self>>::F<Output>;
133}
134
135/// Helper trait used by [`WithArgs`] (use it instead).
136/// This trait is required to allow [`FnPtr`] to be a subtrait of [`WithArgs`], which eliminates
137/// the need for a type bound when using a fixed args type.
138/// Using [`WithArgs`] directly would result in a cyclic supertrait error.
139pub trait WithArgsImpl<F: FnPtr = Self> {
140 /// The function pointer type with the requested argument type(s) (preserving all other properties).
141 type F<Args: Tuple>: FnPtr<Args = Args, Output = F::Output, Safety = F::Safety, Abi = F::Abi>;
142}
143
144/// Helper trait to change the argument types of a function pointer type while preserving its safety, abi and return type.
145///
146/// This is used by [`with_args!`](crate::with_args) under the hood.
147///
148/// # Example
149///
150/// ```rust
151/// # use fn_ptr::WithArgs;
152/// type F = extern "C" fn(i32) -> i32;
153/// type G = <F as WithArgs<(u8, u16)>>::F;
154/// // `G` `extern "C" fn(u8, u16) -> i32`
155/// # static_assertions::assert_type_eq_all!(G, extern "C" fn(u8, u16) -> i32);
156/// ```
157pub trait WithArgs<Args: Tuple>: FnPtr {
158 /// The function pointer type with the requested argument type(s) (preserving all other properties).
159 type F: FnPtr<Args = Args, Output = Self::Output, Safety = Self::Safety, Abi = Self::Abi>;
160}
161impl<Args: Tuple, F: FnPtr + WithArgsImpl<Self>> WithArgs<Args> for F {
162 type F = <Self as WithArgsImpl<Self>>::F<Args>;
163}
164
165/// Construct a function-pointer type identical to the given one but using the specified abi.
166///
167/// Accepts either:
168/// - an [`Abi`](crate::abi::Abi) marker type (e.g. [`C`](crate::abi::C), [`SysV64`](crate::abi::SysV64))
169/// - a string literal (e.g. `"C"`, `"system"`, `"stdcall"`).
170///
171/// # Examples
172///
173/// ```rust
174/// # use fn_ptr::{with_abi, abi};
175/// type F = with_abi!(abi::Rust, extern "C" fn(i32) -> i32);
176/// // `F` is `fn(i32) -> i32` (equivalent to `extern "Rust" fn(i32) -> i32`)
177/// # static_assertions::assert_type_eq_all!(F, fn(i32) -> i32);
178///
179/// type G = with_abi!("C", extern "system" fn());
180/// // `G` is `extern "C" fn()`
181/// # static_assertions::assert_type_eq_all!(G, extern "C" fn());
182/// ```
183#[macro_export]
184macro_rules! with_abi {
185 ( $abi:path, $ty:ty ) => {
186 <$ty as $crate::WithAbi<$abi>>::F
187 };
188
189 ( $lit:tt, $ty:ty ) => {
190 <$ty as $crate::WithAbi<$crate::abi!($lit)>>::F
191 };
192}
193
194/// Construct a function-pointer type identical to the given one but using
195/// the specified safety.
196///
197/// Accepts either:
198/// - a [`Safety`](crate::safety::Safety) marker type ([`Safe`](crate::safety::Safe) or [`Unsafe`](crate::safety::Unsafe))
199/// - safety keyword (`safe` or `unsafe`).
200/// - a boolean literal.
201///
202/// # Examples
203///
204/// ```rust
205/// # use fn_ptr::{with_safety, safety};
206/// type F = with_safety!(safety::Safe, unsafe extern "C" fn(i32) -> i32);
207/// // `F` is `extern "C" fn(i32) -> i32`
208/// # static_assertions::assert_type_eq_all!(F, extern "C" fn(i32) -> i32);
209///
210/// type G = with_safety!(unsafe, fn());
211/// // `G` is `unsafe fn()`
212/// # static_assertions::assert_type_eq_all!(G, unsafe fn());
213/// ```
214#[macro_export]
215macro_rules! with_safety {
216 ( safe, $ty:ty ) => {
217 $crate::with_safety!(@inner $crate::safety::Safe, $ty)
218 };
219 ( unsafe, $ty:ty ) => {
220 $crate::with_safety!(@inner $crate::safety::Unsafe, $ty)
221 };
222 ( $safety:path, $ty:ty ) => {
223 $crate::with_safety!(@inner $safety, $ty)
224 };
225 ( $safety:tt, $ty:ty ) => {
226 $crate::with_safety!(@inner $crate::safety!($safety), $ty)
227 };
228
229 ( @inner $safety:ty, $ty:ty ) => {
230 <$ty as $crate::WithSafety<$safety>>::F
231 };
232}
233
234/// Construct a function-pointer type identical to the given one but `safe`.
235///
236/// # Example
237///
238/// ```rust
239/// # use fn_ptr::make_safe;
240/// type U = unsafe extern "C" fn(i32);
241/// type S = make_safe!(U);
242/// // `S` is `extern "C" fn(i32)`
243/// # static_assertions::assert_type_eq_all!(S, extern "C" fn(i32));
244/// ```
245#[macro_export]
246macro_rules! make_safe {
247 ( $ty:ty ) => {
248 <$ty as $crate::WithSafety<$crate::safety::Safe>>::F
249 };
250}
251
252/// Construct a function-pointer type identical to the given one but `unsafe`.
253///
254/// # Example
255///
256/// ```rust
257/// # use fn_ptr::make_unsafe;
258/// type S = extern "C" fn(i32);
259/// type U = make_unsafe!(S);
260/// // `U` is `unsafe extern "C" fn(i32)`
261/// # static_assertions::assert_type_eq_all!(U, unsafe extern "C" fn(i32));
262/// ```
263#[macro_export]
264macro_rules! make_unsafe {
265 ( $ty:ty ) => {
266 <$ty as $crate::WithSafety<$crate::safety::Unsafe>>::F
267 };
268}
269
270/// Construct a function-pointer type identical to the given one but using
271/// the specified return type.
272///
273/// # Examples
274///
275/// ```rust
276/// # use fn_ptr::with_output;
277/// type F = extern "C" fn(i32) -> i32;
278/// type G = with_output!(u64, F);
279/// // `G` is `extern "C" fn(i32) -> u64`
280/// # static_assertions::assert_type_eq_all!(G, extern "C" fn(i32) -> u64);
281/// ```
282#[macro_export]
283macro_rules! with_output {
284 ( $out:ty, $ty:ty ) => {
285 <$ty as $crate::WithOutput<$out>>::F
286 };
287}
288
289/// Construct a function-pointer type identical to the given one but using
290/// the specified argument tuple type.
291///
292/// # Examples
293///
294/// ```rust
295/// # use fn_ptr::with_args;
296/// type F = extern "C" fn(i32) -> i32;
297/// type G = with_args!((u8, u16), F);
298/// // `G` is `extern "C" fn(u8, u16) -> i32`
299/// # static_assertions::assert_type_eq_all!(G, extern "C" fn(u8, u16) -> i32);
300/// ```
301#[macro_export]
302macro_rules! with_args {
303 ( $args:ty, $ty:ty ) => {
304 <$ty as $crate::WithArgs<$args>>::F
305 };
306}