1#![allow(non_snake_case)]
2
3use super::Closure;
4use alloc::boxed::Box;
5use core::ffi::c_void;
6#[allow(unused_imports)]
7use docfg::docfg;
8
9pub trait CallingConvention: sealed::Sealed {
10 type Destructor: Copy;
11
12 unsafe fn destroy(f: Self::Destructor, user_data: *mut c_void);
13}
14
15pub trait AsExtern<Cc: CallingConvention>: sealed::Sealed {
16 type Args;
17 type Extern: Copy;
18 type Output;
19
20 unsafe fn call_mut(f: Self::Extern, args: Self::Args, user_data: *mut c_void) -> Self::Output;
21}
22
23pub trait IntoExtern<Ext: ?Sized + AsExtern<Cc>, Cc: CallingConvention> {
24 fn into_extern(self: Box<Self>) -> Closure<Ext, Cc>;
25}
26
27macro_rules! impl_ {
28 (
29 $abi:literal as $ident:ident => ($($arg:ident),*) $(+ $($trait:ident),+)?
30 ) => {
31 impl<'a, $($arg,)* __OUT__> AsExtern<$ident> for dyn 'a + $($($trait+)+)? FnMut($($arg,)*) -> __OUT__ {
32 type Args = ($($arg,)*);
33 type Extern = unsafe extern $abi fn($($arg,)* *mut c_void) -> __OUT__;
34 type Output = __OUT__;
35
36 #[inline(always)]
37 unsafe fn call_mut(f: Self::Extern, ($($arg,)*): ($($arg,)*), user_data: *mut c_void) -> Self::Output {
38 (f)($($arg,)* user_data)
39 }
40 }
41
42 impl<'a, $($arg,)* __F__: 'a + $($($trait+)+)? FnMut($($arg,)*) -> __OUT__, __OUT__> IntoExtern<dyn 'a + $($($trait+)+)? FnMut($($arg,)*) -> __OUT__, $ident> for __F__ {
43 #[inline]
44 fn into_extern(self: Box<Self>) -> Closure<dyn 'a + $($($trait+)+)? FnMut($($arg,)*) -> __OUT__, $ident> {
45 unsafe extern $abi fn call<$($arg,)* __F__: FnMut($($arg,)*) -> __OUT__, __OUT__>($($arg: $arg,)* user_data: *mut c_void) -> __OUT__ {
46 return (&mut *user_data.cast::<__F__>())($($arg),*)
47 }
48
49 unsafe extern $abi fn destroy<__F__>(user_data: *mut c_void) {
50 drop(Box::from_raw(user_data.cast::<__F__>()))
51 }
52
53 let user_data = Box::into_raw(self).cast();
54 return unsafe {
55 Closure::from_extern(
56 call::<$($arg,)* Self, __OUT__> as unsafe extern $abi fn($($arg,)* *mut c_void) -> __OUT__,
57 user_data,
58 Some(destroy::<Self> as unsafe extern $abi fn(*mut c_void))
59 )
60 }
61 }
62 }
63 }
64}
65
66macro_rules! impl_fn {
67 (
68 $(#[cfg($cfg:meta)])?
69 $abi:literal as $ident:ident {
70 $(
71 ($($arg:ident),*)
72 ),+ $(,)?
73 }
74 ) => {
75 $(
76 impl_! { $abi as $ident => ($($arg),*) }
77 impl_! { $abi as $ident => ($($arg),*) + Send }
78 impl_! { $abi as $ident => ($($arg),*) + Sync }
79 impl_! { $abi as $ident => ($($arg),*) + Send, Sync }
80 )+
81 };
82}
83
84macro_rules! cc {
85 ($($(#[cfg($cfg:meta)])? $abi:literal as $ident:ident),+ $(,)?) => {
86 $(
87 $(
88 #[cfg(any(docsrs, $cfg))]
89 #[cfg_attr(docsrs, doc(cfg($cfg)))]
90 )?
91 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
92 #[doc = concat!("The \"", $abi, "\" calling convention")]
93 pub struct $ident;
94
95 $(
96 #[cfg(any(docsrs, $cfg))]
97 #[cfg_attr(docsrs, doc(cfg($cfg)))]
98 )?
99 impl CallingConvention for $ident {
100 type Destructor = unsafe extern $abi fn(*mut c_void);
101
102 #[inline(always)]
103 unsafe fn destroy(f: Self::Destructor, user_data: *mut c_void) {
104 (f)(user_data)
105 }
106 }
107
108 $(
109 #[cfg(any(docsrs, $cfg))]
110 #[cfg_attr(docsrs, doc(cfg($cfg)))]
111 )?
112 impl sealed::Sealed for $ident {}
113
114 $(
115 #[cfg(any(docsrs, $cfg))]
116 #[cfg_attr(docsrs, doc(cfg($cfg)))]
117 )?
118 impl_fn! {
119 $abi as $ident {
120 (),
121 (A),
122 (A, B),
123 (A, B, C_),
124 (A, B, C_, D),
125 (A, B, C_, D, E),
126 (A, B, C_, D, E, F),
127 (A, B, C_, D, E, F, G),
128 (A, B, C_, D, E, F, G, H),
129 (A, B, C_, D, E, F, G, H, I),
130 (A, B, C_, D, E, F, G, H, I, J),
131 (A, B, C_, D, E, F, G, H, I, J, K),
132 (A, B, C_, D, E, F, G, H, I, J, K, L),
133 (A, B, C_, D, E, F, G, H, I, J, K, L, M),
134 (A, B, C_, D, E, F, G, H, I, J, K, L, M, N),
135 }
136 }
137 )+
138 };
139}
140
141macro_rules! seal {
142 (
143 $(
144 ($($arg:ident),*)
145 ),+ $(,)?
146 ) => {
147 $(
148 impl<'a, $($arg,)* __OUT__> sealed::Sealed for dyn 'a + FnMut($($arg,)*) -> __OUT__ {}
149 impl<'a, $($arg,)* __OUT__> sealed::Sealed for dyn 'a + Send + FnMut($($arg,)*) -> __OUT__ {}
150 impl<'a, $($arg,)* __OUT__> sealed::Sealed for dyn 'a + Sync + FnMut($($arg,)*) -> __OUT__ {}
151 impl<'a, $($arg,)* __OUT__> sealed::Sealed for dyn 'a + Send + Sync + FnMut($($arg,)*) -> __OUT__ {}
152 )+
153 };
154}
155
156cc! {
158 #[cfg(any(target_arch = "x86"))]
159 "stdcall" as StdCall,
160 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
161 "aapcs" as Aapcs,
162 "cdecl" as Cdecl,
163 #[cfg(any(target_arch = "x86"))]
164 "fastcall" as FastCall,
165 #[cfg(any(target_arch = "x86"))]
166 "thiscall" as ThisCall,
167 "Rust" as Rust,
168 "system" as System,
169 "C" as C,
170 #[cfg(all(windows, any(target_arch = "x86_64", target_arch = "aarch64")))]
171 "win64" as Win64,
172 #[cfg(any(target_arch = "x86_64"))]
173 "sysv64" as Sysv64
174}
175
176seal! {
177 (),
178 (A),
179 (A, B),
180 (A, B, C_),
181 (A, B, C_, D),
182 (A, B, C_, D, E),
183 (A, B, C_, D, E, F),
184 (A, B, C_, D, E, F, G),
185 (A, B, C_, D, E, F, G, H),
186 (A, B, C_, D, E, F, G, H, I),
187 (A, B, C_, D, E, F, G, H, I, J),
188 (A, B, C_, D, E, F, G, H, I, J, K),
189 (A, B, C_, D, E, F, G, H, I, J, K, L),
190 (A, B, C_, D, E, F, G, H, I, J, K, L, M),
191 (A, B, C_, D, E, F, G, H, I, J, K, L, M, N),
192}
193
194mod sealed {
195 pub trait Sealed {}
196}