1macro_rules! cc_thunk_impl_triple {
4 (
5 $cconv:ty,
6 $cconv_lit:literal,
7 $extra_idx: tt,
8 ($($id_tys: ident,)*),
9 ($($tuple_idx: tt,)*),
10 ($($args:ident: $tys:ty,)*)
11 ) => {
12 #[doc(hidden)]
13 unsafe impl<R, $($id_tys),*> $crate::traits::FnPtr for unsafe extern $cconv_lit fn($($tys,)*) -> R {
14 type CC = $cconv;
15 type Args<'a, 'b, 'c> = ($($tys,)*);
16 type Ret<'a, 'b, 'c> = R;
17
18 #[allow(unused_variables)]
19 #[inline(always)]
20 unsafe fn call<'a, 'b, 'c>(self, args: Self::Args<'a, 'b, 'c>) -> Self::Ret<'a, 'b, 'c>
21 {
22 unsafe { (self)($(args.$tuple_idx,)*) }
23 }
24
25 #[inline(always)]
26 unsafe fn from_ptr(ptr: *const ()) -> Self {
27 unsafe { core::mem::transmute_copy(&ptr) }
28 }
29
30 #[inline(always)]
31 fn to_ptr(self) -> *const () {
32 self as *const _
33 }
34
35 #[inline(always)]
36 fn make_once_thunk<F>(fun: F) -> impl $crate::traits::FnOnceThunk<Self>
37 where
38 F: for<'a, 'b, 'c> $crate::traits::PackedFnOnce<'a, 'b, 'c, Self>
39 {
40 (Self::CC::default(), move |$($args,)*| fun(($($args,)*)))
41 }
42
43 #[inline(always)]
44 fn make_mut_thunk<F>(mut fun: F) -> impl $crate::traits::FnMutThunk<Self>
45 where
46 F: for<'a, 'b, 'c> $crate::traits::PackedFnMut<'a, 'b, 'c, Self>
47 {
48 (Self::CC::default(), move |$($args,)*| fun(($($args,)*)))
49 }
50
51 #[inline(always)]
52 fn make_thunk<F>(fun: F) -> impl $crate::traits::FnThunk<Self>
53 where
54 F: for<'a, 'b, 'c> $crate::traits::PackedFn<'a, 'b, 'c, Self>
55 {
56 (Self::CC::default(), move |$($args,)*| fun(($($args,)*)))
57 }
58 }
59
60 #[doc(hidden)]
61 unsafe impl<F: FnOnce($($tys),*) -> R, R, $($id_tys),*>
62 $crate::traits::FnOnceThunk<unsafe extern $cconv_lit fn($($tys,)*) -> R> for ($cconv, F)
63 {
64 const THUNK_TEMPLATE_ONCE: *const u8 = {
65 #[cfg_attr(feature = "coverage", coverage(off))]
66 #[allow(clippy::too_many_arguments)]
67 unsafe extern $cconv_lit fn thunk<F: FnOnce($($tys),*) -> R, R, $($id_tys),*>($($args: $tys),*) -> R {
68 if const { core::mem::size_of::<F>() == 0 } {
69 let fun: F = unsafe { core::mem::zeroed() };
70 fun($($args),*)
71 }
72 else {
73 let closure_ptr: *mut F;
74 $crate::arch::_thunk_asm!(closure_ptr);
75 $crate::arch::_invoke(|| closure_ptr.read()($($args),*))
76 }
77 }
78 thunk::<F, R, $($tys),*> as *const u8
79 };
80
81 #[allow(unused_variables)]
82 #[inline(always)]
83 unsafe fn call_once<'a, 'b, 'c>(self, args: ($($tys,)*)) ->
84 <unsafe extern $cconv_lit fn($($tys,)*) -> R as $crate::traits::FnPtr>::Ret<'a, 'b, 'c>
85 {
86 (self.1)($(args.$tuple_idx,)*)
87 }
88 }
89
90 #[doc(hidden)]
91 unsafe impl<F: FnMut($($tys),*) -> R, R, $($id_tys),*>
92 $crate::traits::FnMutThunk<unsafe extern $cconv_lit fn($($tys,)*) -> R> for ($cconv, F)
93 {
94 const THUNK_TEMPLATE_MUT: *const u8 = {
95 #[cfg_attr(feature = "coverage", coverage(off))]
96 #[allow(clippy::too_many_arguments)]
97 unsafe extern $cconv_lit fn thunk<F: FnMut($($tys),*) -> R, R, $($id_tys),*>($($args: $tys),*) -> R {
98 if const { core::mem::size_of::<F>() == 0 } {
99 let fun: &mut F = unsafe { &mut *core::ptr::dangling_mut() };
100 fun($($args),*)
101 }
102 else {
103 let closure_ptr: *mut F;
104 $crate::arch::_thunk_asm!(closure_ptr);
105 $crate::arch::_invoke(|| (&mut *closure_ptr)($($args),*))
106 }
107 }
108 thunk::<F, R, $($tys),*> as *const u8
109 };
110
111 #[allow(unused_variables)]
112 #[inline(always)]
113 unsafe fn call_mut<'a, 'b, 'c>(&mut self, args: ($($tys,)*)) ->
114 <unsafe extern $cconv_lit fn($($tys,)*) -> R as $crate::traits::FnPtr>::Ret<'a, 'b, 'c>
115 {
116 (self.1)($(args.$tuple_idx,)*)
117 }
118
119 }
120
121 #[doc(hidden)]
122 unsafe impl<F: Fn($($tys),*) -> R, R, $($id_tys),*>
123 $crate::traits::FnThunk<unsafe extern $cconv_lit fn($($tys,)*) -> R> for ($cconv, F)
124 {
125 const THUNK_TEMPLATE: *const u8 = {
126 #[cfg_attr(feature = "coverage", coverage(off))]
127 #[allow(clippy::too_many_arguments)]
128 unsafe extern $cconv_lit fn thunk<F: Fn($($tys),*) -> R, R, $($id_tys),*>($($args: $tys),*) -> R {
129 if const { core::mem::size_of::<F>() == 0 } {
130 let fun: &F = unsafe { &*core::ptr::dangling_mut() };
131 fun($($args),*)
132 }
133 else {
134 let closure_ptr: *const F;
135 $crate::arch::_thunk_asm!(closure_ptr);
136 $crate::arch::_invoke(|| (&*closure_ptr)($($args),*))
137 }
138 }
139 thunk::<F, R, $($tys),*> as *const u8
140 };
141
142 #[allow(unused_variables)]
143 #[inline(always)]
144 unsafe fn call<'a, 'b, 'c>(&self, args: ($($tys,)*)) ->
145 <unsafe extern $cconv_lit fn($($tys,)*) -> R as $crate::traits::FnPtr>::Ret<'a, 'b, 'c>
146 {
147 (self.1)($(args.$tuple_idx,)*)
148 }
149 }
150 };
151}
152
153macro_rules! cc_trait_impl_recursive {
154 (
156 $cconv:ty,
157 $cconv_lit:literal,
158 $impl_macro:ident,
159 [$head_extra_idx:tt, $($tail_extra_idx:tt,)*],
160 [$head_id_ty:ident, $($tail_id_tys:ident,)*] ($($id_tys:ident,)*),
161 [$head_tuple_idx:tt, $($tail_tuple_idx:tt,)*] ($($tuple_idx:tt,)*),
162 [$head_arg:ident: $head_ty:ty, $($tail_args:ident: $tail_tys:ty,)*] ($($args:ident: $tys:ty,)*)
163 ) => {
164 $impl_macro!(
165 $cconv,
166 $cconv_lit,
167 $head_extra_idx,
168 ($($id_tys,)*),
169 ($($tuple_idx,)*),
170 ($($args: $tys,)*)
171 );
172
173 cc_trait_impl_recursive!(
174 $cconv,
175 $cconv_lit,
176 $impl_macro,
177 [$($tail_extra_idx,)*],
178 [$($tail_id_tys,)*] ($($id_tys,)* $head_id_ty,),
179 [$($tail_tuple_idx,)*] ($($tuple_idx,)* $head_tuple_idx,),
180 [$($tail_args: $tail_tys,)*] ($($args: $tys,)* $head_arg: $head_ty,)
181 );
182 };
183
184 (
186 $cconv:ty,
187 $cconv_lit:literal,
188 $impl_macro:ident,
189 [$extra_idx:tt,],
190 [] ($($id_tys:ident,)*),
191 [] ($($tuple_idx:tt,)*),
192 [] ($($args:ident: $tys:ty,)*)
193 ) => {
194 $impl_macro!(
195 $cconv,
196 $cconv_lit,
197 $extra_idx,
198 ($($id_tys,)*),
199 ($($tuple_idx,)*),
200 ($($args: $tys,)*)
201 );
202 };
203}
204
205macro_rules! cc_trait_impl {
206 ($cconv:ty, $cconv_lit:literal, $impl_macro:ident) => {
207 cc_trait_impl_recursive!(
208 $cconv,
209 $cconv_lit,
210 $impl_macro,
211 [0,1,2,3,4,5,6,7,8,9,10,11,12,],
212 [T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,](),
213 [0,1,2,3,4,5,6,7,8,9,10,11,](),
214 [a0:T0,a1:T1,a2:T2,a3:T3,a4:T4,a5:T5,a6:T6,a7:T7,a8:T8,a9:T9,a10:T10,a11:T11,]()
215 );
216 };
217}
218
219macro_rules! cc_impl {
220 ($ty_name:tt, $lit_name:literal $(,$cfg:meta)?) => {
221 #[doc = "Marker type representing the"]
222 #[doc = $lit_name]
223 #[doc = "calling convention."]
224 #[derive(Debug, Clone, Copy, Default)]
225 $(#[cfg(any($cfg, doc))])?
226 pub struct $ty_name;
227 $(#[cfg($cfg)])?
228 cc_trait_impl!($ty_name, $lit_name, cc_thunk_impl_triple);
229 };
230}
231
232#[derive(Debug, Clone, Copy, Default)]
238pub struct Rust;
239cc_trait_impl!(Rust, "Rust", cc_thunk_impl_triple);
240
241cc_impl!(C, "C");
242cc_impl!(CUnwind, "C-unwind");
243
244cc_impl!(System, "system");
245cc_impl!(SystemUnwind, "system-unwind");
246
247cc_impl!(Efiapi, "efiapi");
248
249cc_impl!(Sysv64, "sysv64", all(not(windows), target_arch = "x86_64"));
250cc_impl!(
251 Sysv64Unwind,
252 "sysv64-unwind",
253 all(not(windows), target_arch = "x86_64")
254);
255
256cc_impl!(Aapcs, "aapcs", target_arch = "arm");
257cc_impl!(AapcsUnwind, "aapcs-unwind", target_arch = "arm");
258
259cc_impl!(Fastcall, "fastcall", all(windows, target_arch = "x86"));
260cc_impl!(
261 FastcallUnwind,
262 "fastcall-unwind",
263 all(windows, target_arch = "x86")
264);
265
266cc_impl!(Stdcall, "stdcall", all(windows, target_arch = "x86"));
267cc_impl!(
268 StdcallUnwind,
269 "stdcall-unwind",
270 all(windows, target_arch = "x86")
271);
272
273cc_impl!(Cdecl, "cdecl", all(windows, target_arch = "x86"));
274cc_impl!(
275 CdeclUnwind,
276 "cdecl-unwind",
277 all(windows, target_arch = "x86")
278);
279
280cc_impl!(Thiscall, "thiscall", all(windows, target_arch = "x86"));
281cc_impl!(
282 ThiscallUnwind,
283 "thiscall-unwind",
284 all(windows, target_arch = "x86")
285);
286
287cc_impl!(Win64, "win64", all(windows, target_arch = "x86_64"));
288cc_impl!(
289 Win64Unwind,
290 "win64-unwind",
291 all(windows, target_arch = "x86_64")
292);
293
294#[cfg(feature = "c_variadic")]
295macro_rules! cc_thunk_impl_triple_variadic {
296 (
297 $cconv:ty,
298 $cconv_lit:literal,
299 $extra_idx: tt,
300 ($($id_tys: ident,)*),
301 ($($tuple_idx: tt,)*),
302 ($($args:ident: $tys:ty,)*)
303 ) => {
304 #[doc(hidden)]
305 unsafe impl<R, $($id_tys),*> $crate::traits::FnPtr for unsafe extern $cconv_lit fn($($tys,)* ...) -> R {
306 type CC = $cconv;
307 type Args<'a, 'b, 'c> = ($($tys,)* core::ffi::VaListImpl<'a>,);
308 type Ret<'a, 'b, 'c> = R;
309
310 #[allow(unused_variables)]
311 #[inline(always)]
312 unsafe fn call<'a, 'b, 'c>(self, args: Self::Args<'a, 'b, 'c>) -> Self::Ret<'a, 'b, 'c>
313 {
314 const {
315 panic!("FnPtr::call is not supported on C variadics due to a language limitations")
316 }
317 }
318
319 #[inline(always)]
320 unsafe fn from_ptr(ptr: *const ()) -> Self {
321 unsafe { core::mem::transmute_copy(&ptr) }
322 }
323
324 #[inline(always)]
325 fn to_ptr(self) -> *const () {
326 self as *const _
327 }
328
329 #[inline(always)]
330 fn make_once_thunk<F>(fun: F) -> impl $crate::traits::FnOnceThunk<Self>
331 where
332 F: for<'a, 'b, 'c> $crate::traits::PackedFnOnce<'a, 'b, 'c, Self>
333 {
334 #[inline(always)]
336 fn coerce<R, $($id_tys,)* F>(fun: F) -> F
337 where F: for<'va> FnOnce($($tys,)* core::ffi::VaListImpl<'va>) -> R {
338 fun
339 }
340 let coerced = coerce(move |$($args,)* va| fun(($($args,)* va,)));
341 (Self::CC::default(), coerced)
342 }
343
344 #[inline(always)]
345 fn make_mut_thunk<F>(mut fun: F) -> impl $crate::traits::FnMutThunk<Self>
346 where
347 F: for<'a, 'b, 'c> $crate::traits::PackedFnMut<'a, 'b, 'c, Self>
348 {
349 #[inline(always)]
350 fn coerce<R, $($id_tys,)* F>(fun: F) -> F
351 where F: for<'va> FnMut($($tys,)* core::ffi::VaListImpl<'va>) -> R {
352 fun
353 }
354 let coerced = coerce(move |$($args,)* va| fun(($($args,)* va,)));
355 (Self::CC::default(), coerced)
356 }
357
358 #[inline(always)]
359 fn make_thunk<F>(fun: F) -> impl $crate::traits::FnThunk<Self>
360 where
361 F: for<'a, 'b, 'c> $crate::traits::PackedFn<'a, 'b, 'c, Self>
362 {
363 #[inline(always)]
364 fn coerce<R, $($id_tys,)* F>(fun: F) -> F
365 where F: for<'va> Fn($($tys,)* core::ffi::VaListImpl<'va>) -> R {
366 fun
367 }
368 let coerced = coerce(move |$($args,)* va| fun(($($args,)* va,)));
369 (Self::CC::default(), coerced)
370 }
371 }
372
373 #[doc(hidden)]
374 unsafe impl<F: for<'va> FnOnce($($tys,)* core::ffi::VaListImpl<'va>) -> R, R, $($id_tys),*>
375 $crate::traits::FnOnceThunk<unsafe extern $cconv_lit fn($($tys,)* ...) -> R> for ($cconv, F)
376 {
377 const THUNK_TEMPLATE_ONCE: *const u8 = {
378 #[cfg_attr(feature = "coverage", coverage(off))]
379 unsafe extern $cconv_lit fn thunk<F, R, $($id_tys),*>($($args: $tys,)* va_args: ...) -> R
380 where
381 F: for<'va> FnOnce($($tys,)* core::ffi::VaListImpl<'va>) -> R
382 {
383 if const { core::mem::size_of::<F>() == 0 } {
384 let fun: F = unsafe { core::mem::zeroed() };
385 fun($($args,)* va_args)
386 }
387 else {
388 let closure_ptr: *mut F;
389 $crate::arch::_thunk_asm!(closure_ptr);
390 $crate::arch::_invoke(|| closure_ptr.read()($($args,)* va_args))
391 }
392 }
393 thunk::<F, R, $($tys),*> as *const u8
394 };
395
396 #[allow(unused_variables)]
397 #[inline(always)]
398 unsafe fn call_once<'a, 'b, 'c>(
399 self,
400 args: <unsafe extern $cconv_lit fn($($tys,)* ...) -> R as $crate::traits::FnPtr>::Args<'a, 'b, 'c>
401 ) ->
402 <unsafe extern $cconv_lit fn($($tys,)* ...) -> R as $crate::traits::FnPtr>::Ret<'a, 'b, 'c>
403 {
404 (self.1)($(args.$tuple_idx,)* args.$extra_idx)
405 }
406 }
407
408 #[doc(hidden)]
409 unsafe impl<F: for<'va> FnMut($($tys,)* core::ffi::VaListImpl<'va>) -> R, R, $($id_tys),*>
410 $crate::traits::FnMutThunk<unsafe extern $cconv_lit fn($($tys,)* ...) -> R> for ($cconv, F)
411 {
412 const THUNK_TEMPLATE_MUT: *const u8 = {
413 #[cfg_attr(feature = "coverage", coverage(off))]
414 unsafe extern $cconv_lit fn thunk<F, R, $($id_tys),*>($($args: $tys,)* va_args: ...) -> R
415 where
416 F: for<'va> FnMut($($tys,)* core::ffi::VaListImpl<'va>) -> R
417 {
418 if const { core::mem::size_of::<F>() == 0 } {
419 let fun: &mut F = unsafe { &mut *core::ptr::dangling_mut() };
420 fun($($args,)* va_args)
421 }
422 else {
423 let closure_ptr: *mut F;
424 $crate::arch::_thunk_asm!(closure_ptr);
425 $crate::arch::_invoke(|| (&mut *closure_ptr)($($args,)* va_args))
426 }
427 }
428 thunk::<F, R, $($tys),*> as *const u8
429 };
430
431 #[allow(unused_variables)]
432 #[inline(always)]
433 unsafe fn call_mut<'a, 'b, 'c>(
434 &mut self,
435 args: <unsafe extern $cconv_lit fn($($tys,)* ...) -> R as $crate::traits::FnPtr>::Args<'a, 'b, 'c>
436 ) ->
437 <unsafe extern $cconv_lit fn($($tys,)* ...) -> R as $crate::traits::FnPtr>::Ret<'a, 'b, 'c>
438 {
439 (self.1)($(args.$tuple_idx,)* args.$extra_idx)
440 }
441 }
442
443 #[doc(hidden)]
444 unsafe impl<F: for<'va> Fn($($tys,)* core::ffi::VaListImpl<'va>) -> R, R, $($id_tys),*>
445 $crate::traits::FnThunk<unsafe extern $cconv_lit fn($($tys,)* ...) -> R> for ($cconv, F)
446 {
447 const THUNK_TEMPLATE: *const u8 = {
448 #[cfg_attr(feature = "coverage", coverage(off))]
449 unsafe extern $cconv_lit fn thunk<F, R, $($id_tys),*>($($args: $tys,)* va_args: ...) -> R
450 where
451 F: for<'va> Fn($($tys,)* core::ffi::VaListImpl<'va>) -> R
452 {
453 if const { core::mem::size_of::<F>() == 0 } {
454 let fun: &F = unsafe { &*core::ptr::dangling_mut() };
455 fun($($args,)* va_args)
456 }
457 else {
458 let closure_ptr: *const F;
459 $crate::arch::_thunk_asm!(closure_ptr);
460 $crate::arch::_invoke(|| (&*closure_ptr)($($args,)* va_args))
461 }
462 }
463 thunk::<F, R, $($tys),*> as *const u8
464 };
465
466 #[allow(unused_variables)]
467 #[inline(always)]
468 unsafe fn call<'a, 'b, 'c>(
469 &self,
470 args: <unsafe extern $cconv_lit fn($($tys,)* ...) -> R as $crate::traits::FnPtr>::Args<'a, 'b, 'c>
471 ) ->
472 <unsafe extern $cconv_lit fn($($tys,)* ...) -> R as $crate::traits::FnPtr>::Ret<'a, 'b, 'c>
473 {
474 (self.1)($(args.$tuple_idx,)* args.$extra_idx)
475 }
476 }
477 };
478}
479
480#[derive(Debug, Clone, Copy, Default)]
484#[cfg(any(doc, feature = "c_variadic"))]
485pub struct Variadic;
486#[cfg(feature = "c_variadic")]
487cc_trait_impl!(Variadic, "C", cc_thunk_impl_triple_variadic);