fn_ptr/
impl.rs

1// NOTE: ABI target cfgs are provided by the build script as `has_abi_<name>`.
2
3macro_rules! impl_fn {
4    // main entry point
5    ($($nm:ident : $ty:ident),*) => {
6        impl_fn!(@recurse ($($nm : $ty),*) ());
7    };
8
9    // recurse for all parameter counts
10    (@recurse () ($($nm:ident : $ty:ident),*)) => {
11        impl_fn!(@impl_all ($($nm : $ty),*));
12    };
13    (@recurse ($hd_nm:ident : $hd_ty:ident $(, $tl_nm:ident : $tl_ty:ident)*) ($($nm:ident : $ty:ident),*)) => {
14        impl_fn!(@impl_all ($($nm : $ty),*));
15        impl_fn!(@recurse ($($tl_nm : $tl_ty),*) ($($nm : $ty,)* $hd_nm : $hd_ty));
16    };
17
18    // call for every abi
19    (@impl_all ($($nm:ident : $ty:ident),*)) => {
20        // Always-present
21        impl_fn!(@impl_u_and_s ($($nm : $ty),*), Rust, "Rust");
22        impl_fn!(@impl_u_and_s ($($nm : $ty),*), C, "C");
23        impl_fn!(@impl_u_and_s ($($nm : $ty),*), CUnwind, "C-unwind");
24        impl_fn!(@impl_u_and_s ($($nm : $ty),*), System, "system");
25        impl_fn!(@impl_u_and_s ($($nm : $ty),*), SystemUnwind, "system-unwind");
26
27        // Common platform ABIs
28        #[cfg(has_abi_cdecl)]
29        impl_fn!(@impl_u_and_s ($($nm : $ty),*), Cdecl, "cdecl");
30        #[cfg(has_abi_cdecl)]
31        impl_fn!(@impl_u_and_s ($($nm : $ty),*), CdeclUnwind, "cdecl-unwind");
32
33        #[cfg(has_abi_stdcall)]
34        impl_fn!(@impl_u_and_s ($($nm : $ty),*), Stdcall, "stdcall");
35        #[cfg(has_abi_stdcall)]
36        impl_fn!(@impl_u_and_s ($($nm : $ty),*), StdcallUnwind, "stdcall-unwind");
37
38        #[cfg(has_abi_fastcall)]
39        impl_fn!(@impl_u_and_s ($($nm : $ty),*), Fastcall, "fastcall");
40        #[cfg(has_abi_fastcall)]
41        impl_fn!(@impl_u_and_s ($($nm : $ty),*), FastcallUnwind, "fastcall-unwind");
42
43        #[cfg(has_abi_thiscall)]
44        impl_fn!(@impl_u_and_s ($($nm : $ty),*), Thiscall, "thiscall");
45        #[cfg(has_abi_thiscall)]
46        impl_fn!(@impl_u_and_s ($($nm : $ty),*), ThiscallUnwind, "thiscall-unwind");
47
48        #[cfg(has_abi_vectorcall)]
49        impl_fn!(@impl_u_and_s ($($nm : $ty),*), Vectorcall, "vectorcall");
50        #[cfg(has_abi_vectorcall)]
51        impl_fn!(@impl_u_and_s ($($nm : $ty),*), VectorcallUnwind, "vectorcall-unwind");
52
53        #[cfg(has_abi_win64)]
54        impl_fn!(@impl_u_and_s ($($nm : $ty),*), Win64, "win64");
55        #[cfg(has_abi_win64)]
56        impl_fn!(@impl_u_and_s ($($nm : $ty),*), Win64Unwind, "win64-unwind");
57
58        #[cfg(has_abi_sysv64)]
59        impl_fn!(@impl_u_and_s ($($nm : $ty),*), SysV64, "sysv64");
60        #[cfg(has_abi_sysv64)]
61        impl_fn!(@impl_u_and_s ($($nm : $ty),*), SysV64Unwind, "sysv64-unwind");
62
63        #[cfg(has_abi_aapcs)]
64        impl_fn!(@impl_u_and_s ($($nm : $ty),*), Aapcs, "aapcs");
65        #[cfg(has_abi_aapcs)]
66        impl_fn!(@impl_u_and_s ($($nm : $ty),*), AapcsUnwind, "aapcs-unwind");
67    };
68
69    // call for safe and unsafe
70    (@impl_u_and_s ($($nm:ident : $ty:ident),*), $abi_ident:ident, $abi_str:expr) => {
71        impl_fn!(@impl_core ($($nm : $ty),*), extern $abi_str fn($($ty),*) -> Ret, true, $abi_ident, $abi_str);
72        impl_fn!(@impl_core ($($nm : $ty),*), unsafe extern $abi_str fn($($ty),*) -> Ret, false, $abi_ident, $abi_str);
73    };
74
75    // core macro
76    (@impl_core ($($nm:ident : $ty:ident),*), $fn_type:ty, $safety:tt, $abi_ident:ident, $call_conv:expr) => {
77        #[automatically_derived]
78        impl<Ret, $($ty),*> $crate::FnPtr for $fn_type {
79            type Args = ($($ty,)*);
80            type Output = Ret;
81
82            type ArityMarker = impl_fn!(@arity_marker ($($ty),*));
83            type SafetyMarker = $crate::safety!($safety);
84            type AbiMarker = $crate::marker::$abi_ident;
85
86            const ARITY: ::core::primitive::usize = <Self::ArityMarker as $crate::marker::Arity>::N;
87            const IS_SAFE: ::core::primitive::bool = <Self::SafetyMarker as $crate::marker::Safety>::IS_SAFE;
88            const ABI: $crate::Abi = <$crate::marker::$abi_ident as $crate::marker::Abi>::VALUE;
89            const IS_EXTERN: ::core::primitive::bool = !matches!(Self::ABI, $crate::Abi::Rust);
90
91            fn as_ptr(&self) -> $crate::UntypedFnPtr {
92                *self as $crate::UntypedFnPtr
93            }
94            unsafe fn from_ptr(ptr: $crate::UntypedFnPtr) -> Self {
95                ::core::assert!(!ptr.is_null());
96                unsafe { ::core::mem::transmute::<$crate::UntypedFnPtr, Self>(ptr) }
97            }
98        }
99        impl_fn!(@impl_safe_fn_type ($($nm : $ty),*), $fn_type, $safety);
100
101        #[automatically_derived]
102        impl<Ret: 'static, $($ty: 'static),*> $crate::StaticFnPtr for $fn_type {
103        }
104
105        // WithSafety
106        #[automatically_derived]
107        impl<Ret, $($ty),*> $crate::WithSafety<$crate::marker::Safe> for $fn_type {
108            type F = extern $call_conv fn($($ty),*) -> Ret;
109        }
110        #[automatically_derived]
111        impl<Ret, $($ty),*> $crate::WithSafety<$crate::marker::Unsafe> for $fn_type {
112            type F = unsafe extern $call_conv fn($($ty),*) -> Ret;
113        }
114
115        // HasAbi
116        #[automatically_derived]
117        impl<Ret, $($ty),*> $crate::HasAbi<$crate::marker::$abi_ident> for $fn_type {}
118
119        // WithAbi
120        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "Rust");
121        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "C");
122        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "system");
123        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "C-unwind");
124        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "system-unwind");
125
126        #[cfg(has_abi_cdecl)]
127        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "cdecl");
128        #[cfg(has_abi_cdecl)]
129        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "cdecl-unwind");
130
131        #[cfg(has_abi_stdcall)]
132        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "stdcall");
133        #[cfg(has_abi_stdcall)]
134        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "stdcall-unwind");
135
136        #[cfg(has_abi_fastcall)]
137        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "fastcall");
138        #[cfg(has_abi_fastcall)]
139        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "fastcall-unwind");
140
141        #[cfg(has_abi_thiscall)]
142        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "thiscall");
143        #[cfg(has_abi_thiscall)]
144        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "thiscall-unwind");
145
146        #[cfg(has_abi_vectorcall)]
147        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "vectorcall");
148        #[cfg(has_abi_vectorcall)]
149        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "vectorcall-unwind");
150
151        #[cfg(has_abi_win64)]
152        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "win64");
153        #[cfg(has_abi_win64)]
154        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "win64-unwind");
155
156        #[cfg(has_abi_sysv64)]
157        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "sysv64");
158        #[cfg(has_abi_sysv64)]
159        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "sysv64-unwind");
160
161        #[cfg(has_abi_aapcs)]
162        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "aapcs");
163        #[cfg(has_abi_aapcs)]
164        impl_fn!(@impl_withabi ($($nm : $ty),*), $fn_type, $safety, "aapcs-unwind");
165    };
166
167    (@impl_withabi ($($nm:ident : $ty:ident),*), $fn_type:ty, $safety:tt, $abi:tt) => {
168        #[automatically_derived]
169        impl<Ret, $($ty),*> $crate::WithAbi<$crate::abi!($abi)> for $fn_type {
170            type F = impl_fn!(@make_unsafe extern $abi fn($($ty),*) -> Ret, $safety);
171        }
172    };
173
174    (@arity_marker ()) => { $crate::marker::A0 };
175    (@arity_marker ($a:ty)) => { $crate::marker::A1 };
176    (@arity_marker ($a:ty, $b:ty)) => { $crate::marker::A2 };
177    (@arity_marker ($a:ty, $b:ty, $c:ty)) => { $crate::marker::A3 };
178    (@arity_marker ($a:ty, $b:ty, $c:ty, $d:ty)) => { $crate::marker::A4 };
179    (@arity_marker ($a:ty, $b:ty, $c:ty, $d:ty, $e:ty)) => { $crate::marker::A5 };
180    (@arity_marker ($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty)) => { $crate::marker::A6 };
181    (@arity_marker ($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty, $g:ty)) => { $crate::marker::A7 };
182    (@arity_marker ($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty, $g:ty, $h:ty)) => { $crate::marker::A8 };
183    (@arity_marker ($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty, $g:ty, $h:ty, $i:ty)) => { $crate::marker::A9 };
184    (@arity_marker ($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty, $g:ty, $h:ty, $i:ty, $j:ty)) => { $crate::marker::A10 };
185    (@arity_marker ($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty, $g:ty, $h:ty, $i:ty, $j:ty, $k:ty)) => { $crate::marker::A11 };
186    (@arity_marker ($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty, $g:ty, $h:ty, $i:ty, $j:ty, $k:ty, $l:ty)) => { $crate::marker::A12 };
187
188    (@make_unsafe $fn_type:ty, true) => { $fn_type };
189    (@make_unsafe extern $abi:literal fn($($args:ty),*) -> $ret:ty, false) => {
190        unsafe extern $abi fn($($args),*) -> $ret
191    };
192
193    (@impl_safe_fn_type ($($nm:ident : $ty:ident),*), $fn_type:ty, true) => {
194        #[automatically_derived]
195        impl<Ret, $($ty),*> $crate::SafeFnPtr for $fn_type {
196            fn invoke(&self, impl_fn!(@call_args ($($nm),*)): Self::Args) -> Self::Output {
197                (*self)($($nm),*)
198            }
199        }
200    };
201    (@impl_safe_fn_type ($($nm:ident : $ty:ident),*), $fn_type:ty, false) => {
202        #[automatically_derived]
203        impl<Ret, $($ty),*> $crate::UnsafeFnPtr for $fn_type {
204            unsafe fn invoke(&self, impl_fn!(@call_args ($($nm),*)): Self::Args) -> Self::Output {
205                unsafe { (*self)($($nm),*) }
206            }
207        }
208    };
209
210    (@call_args ($single:ident)) => { ($single,) };
211    (@call_args ($($args:ident),*)) => { ($($args),*) };
212}
213
214// Default: generate impls up to 6 arguments
215#[cfg(not(feature = "max-arity-12"))]
216impl_fn! {
217    __arg_0: A, __arg_1: B, __arg_2: C, __arg_3: D, __arg_4: E, __arg_5: F
218}
219
220// Optional: generate impls up to 12 arguments when feature is enabled
221#[cfg(feature = "max-arity-12")]
222impl_fn! {
223    __arg_0: A, __arg_1: B, __arg_2: C, __arg_3: D, __arg_4: E, __arg_5: F, __arg_6: G,
224    __arg_7: H, __arg_8: I, __arg_9: J, __arg_10: K, __arg_11: L
225}