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", target_arch = "x86_64");
250cc_impl!(Sysv64Unwind, "sysv64-unwind", target_arch = "x86_64");
251
252cc_impl!(Win64, "win64", target_arch = "x86_64");
253cc_impl!(Win64Unwind, "win64-unwind", target_arch = "x86_64");
254
255cc_impl!(Aapcs, "aapcs", target_arch = "arm");
256cc_impl!(AapcsUnwind, "aapcs-unwind", target_arch = "arm");
257
258cc_impl!(Fastcall, "fastcall", target_arch = "x86");
259cc_impl!(FastcallUnwind, "fastcall-unwind", target_arch = "x86");
260
261cc_impl!(Stdcall, "stdcall", target_arch = "x86");
262cc_impl!(StdcallUnwind, "stdcall-unwind", target_arch = "x86");
263
264cc_impl!(Cdecl, "cdecl", target_arch = "x86");
265cc_impl!(CdeclUnwind, "cdecl-unwind", target_arch = "x86");
266
267cc_impl!(Thiscall, "thiscall", target_arch = "x86");
268cc_impl!(ThiscallUnwind, "thiscall-unwind", target_arch = "x86");
269
270#[cfg(feature = "c_variadic")]
271macro_rules! cc_thunk_impl_triple_variadic {
272 (
273 $cconv:ty,
274 $cconv_lit:literal,
275 $extra_idx: tt,
276 ($($id_tys: ident,)*),
277 ($($tuple_idx: tt,)*),
278 ($($args:ident: $tys:ty,)*)
279 ) => {
280 #[doc(hidden)]
281 unsafe impl<R, $($id_tys),*> $crate::traits::FnPtr for unsafe extern $cconv_lit fn($($tys,)* ...) -> R {
282 type CC = $cconv;
283 type Args<'a, 'b, 'c> = ($($tys,)* core::ffi::VaList<'a>,);
284 type Ret<'a, 'b, 'c> = R;
285
286 #[allow(unused_variables)]
287 #[inline(always)]
288 unsafe fn call<'a, 'b, 'c>(self, args: Self::Args<'a, 'b, 'c>) -> Self::Ret<'a, 'b, 'c>
289 {
290 const {
291 panic!("FnPtr::call is not supported on C variadics due to a language limitations")
292 }
293 }
294
295 #[inline(always)]
296 unsafe fn from_ptr(ptr: *const ()) -> Self {
297 unsafe { core::mem::transmute_copy(&ptr) }
298 }
299
300 #[inline(always)]
301 fn to_ptr(self) -> *const () {
302 self as *const _
303 }
304
305 #[inline(always)]
306 fn make_once_thunk<F>(fun: F) -> impl $crate::traits::FnOnceThunk<Self>
307 where
308 F: for<'a, 'b, 'c> $crate::traits::PackedFnOnce<'a, 'b, 'c, Self>
309 {
310 #[inline(always)]
312 fn coerce<R, $($id_tys,)* F>(fun: F) -> F
313 where F: for<'va> FnOnce($($tys,)* core::ffi::VaList<'va>) -> R {
314 fun
315 }
316 let coerced = coerce(move |$($args,)* va| fun(($($args,)* va,)));
317 (Self::CC::default(), coerced)
318 }
319
320 #[inline(always)]
321 fn make_mut_thunk<F>(mut fun: F) -> impl $crate::traits::FnMutThunk<Self>
322 where
323 F: for<'a, 'b, 'c> $crate::traits::PackedFnMut<'a, 'b, 'c, Self>
324 {
325 #[inline(always)]
326 fn coerce<R, $($id_tys,)* F>(fun: F) -> F
327 where F: for<'va> FnMut($($tys,)* core::ffi::VaList<'va>) -> R {
328 fun
329 }
330 let coerced = coerce(move |$($args,)* va| fun(($($args,)* va,)));
331 (Self::CC::default(), coerced)
332 }
333
334 #[inline(always)]
335 fn make_thunk<F>(fun: F) -> impl $crate::traits::FnThunk<Self>
336 where
337 F: for<'a, 'b, 'c> $crate::traits::PackedFn<'a, 'b, 'c, Self>
338 {
339 #[inline(always)]
340 fn coerce<R, $($id_tys,)* F>(fun: F) -> F
341 where F: for<'va> Fn($($tys,)* core::ffi::VaList<'va>) -> R {
342 fun
343 }
344 let coerced = coerce(move |$($args,)* va| fun(($($args,)* va,)));
345 (Self::CC::default(), coerced)
346 }
347 }
348
349 #[doc(hidden)]
350 unsafe impl<F: for<'va> FnOnce($($tys,)* core::ffi::VaList<'va>) -> R, R, $($id_tys),*>
351 $crate::traits::FnOnceThunk<unsafe extern $cconv_lit fn($($tys,)* ...) -> R> for ($cconv, F)
352 {
353 const THUNK_TEMPLATE_ONCE: *const u8 = {
354 #[cfg_attr(feature = "coverage", coverage(off))]
355 unsafe extern $cconv_lit fn thunk<F, R, $($id_tys),*>($($args: $tys,)* va_args: ...) -> R
356 where
357 F: for<'va> FnOnce($($tys,)* core::ffi::VaList<'va>) -> R
358 {
359 if const { core::mem::size_of::<F>() == 0 } {
360 let fun: F = unsafe { core::mem::zeroed() };
361 fun($($args,)* va_args)
362 }
363 else {
364 let closure_ptr: *mut F;
365 $crate::arch::_thunk_asm!(closure_ptr);
366 $crate::arch::_invoke(|| closure_ptr.read()($($args,)* va_args))
367 }
368 }
369 thunk::<F, R, $($tys),*> as *const u8
370 };
371
372 #[allow(unused_variables)]
373 #[inline(always)]
374 unsafe fn call_once<'a, 'b, 'c>(
375 self,
376 args: <unsafe extern $cconv_lit fn($($tys,)* ...) -> R as $crate::traits::FnPtr>::Args<'a, 'b, 'c>
377 ) ->
378 <unsafe extern $cconv_lit fn($($tys,)* ...) -> R as $crate::traits::FnPtr>::Ret<'a, 'b, 'c>
379 {
380 (self.1)($(args.$tuple_idx,)* args.$extra_idx)
381 }
382 }
383
384 #[doc(hidden)]
385 unsafe impl<F: for<'va> FnMut($($tys,)* core::ffi::VaList<'va>) -> R, R, $($id_tys),*>
386 $crate::traits::FnMutThunk<unsafe extern $cconv_lit fn($($tys,)* ...) -> R> for ($cconv, F)
387 {
388 const THUNK_TEMPLATE_MUT: *const u8 = {
389 #[cfg_attr(feature = "coverage", coverage(off))]
390 unsafe extern $cconv_lit fn thunk<F, R, $($id_tys),*>($($args: $tys,)* va_args: ...) -> R
391 where
392 F: for<'va> FnMut($($tys,)* core::ffi::VaList<'va>) -> R
393 {
394 if const { core::mem::size_of::<F>() == 0 } {
395 let fun: &mut F = unsafe { &mut *core::ptr::dangling_mut() };
396 fun($($args,)* va_args)
397 }
398 else {
399 let closure_ptr: *mut F;
400 $crate::arch::_thunk_asm!(closure_ptr);
401 $crate::arch::_invoke(|| (&mut *closure_ptr)($($args,)* va_args))
402 }
403 }
404 thunk::<F, R, $($tys),*> as *const u8
405 };
406
407 #[allow(unused_variables)]
408 #[inline(always)]
409 unsafe fn call_mut<'a, 'b, 'c>(
410 &mut self,
411 args: <unsafe extern $cconv_lit fn($($tys,)* ...) -> R as $crate::traits::FnPtr>::Args<'a, 'b, 'c>
412 ) ->
413 <unsafe extern $cconv_lit fn($($tys,)* ...) -> R as $crate::traits::FnPtr>::Ret<'a, 'b, 'c>
414 {
415 (self.1)($(args.$tuple_idx,)* args.$extra_idx)
416 }
417 }
418
419 #[doc(hidden)]
420 unsafe impl<F: for<'va> Fn($($tys,)* core::ffi::VaList<'va>) -> R, R, $($id_tys),*>
421 $crate::traits::FnThunk<unsafe extern $cconv_lit fn($($tys,)* ...) -> R> for ($cconv, F)
422 {
423 const THUNK_TEMPLATE: *const u8 = {
424 #[cfg_attr(feature = "coverage", coverage(off))]
425 unsafe extern $cconv_lit fn thunk<F, R, $($id_tys),*>($($args: $tys,)* va_args: ...) -> R
426 where
427 F: for<'va> Fn($($tys,)* core::ffi::VaList<'va>) -> R
428 {
429 if const { core::mem::size_of::<F>() == 0 } {
430 let fun: &F = unsafe { &*core::ptr::dangling_mut() };
431 fun($($args,)* va_args)
432 }
433 else {
434 let closure_ptr: *const F;
435 $crate::arch::_thunk_asm!(closure_ptr);
436 $crate::arch::_invoke(|| (&*closure_ptr)($($args,)* va_args))
437 }
438 }
439 thunk::<F, R, $($tys),*> as *const u8
440 };
441
442 #[allow(unused_variables)]
443 #[inline(always)]
444 unsafe fn call<'a, 'b, 'c>(
445 &self,
446 args: <unsafe extern $cconv_lit fn($($tys,)* ...) -> R as $crate::traits::FnPtr>::Args<'a, 'b, 'c>
447 ) ->
448 <unsafe extern $cconv_lit fn($($tys,)* ...) -> R as $crate::traits::FnPtr>::Ret<'a, 'b, 'c>
449 {
450 (self.1)($(args.$tuple_idx,)* args.$extra_idx)
451 }
452 }
453 };
454}
455
456#[derive(Debug, Clone, Copy, Default)]
460#[cfg(any(doc, feature = "c_variadic"))]
461pub struct Variadic;
462#[cfg(feature = "c_variadic")]
463cc_trait_impl!(Variadic, "C", cc_thunk_impl_triple_variadic);