1#[doc(hidden)]
6#[cfg(feature = "no_std")]
7pub use alloc::boxed::Box;
8use core::{marker::PhantomData, mem::ManuallyDrop};
9#[doc(hidden)]
10#[cfg(not(feature = "no_std"))]
11pub use std::boxed::Box;
12
13#[cfg(feature = "proc_macros")]
14#[doc(inline)]
15pub use closure_ffi_proc_macros::bare_dyn;
16
17#[cfg(any(feature = "bundled_jit_alloc", feature = "custom_jit_alloc"))]
18use crate::jit_alloc::GlobalJitAlloc;
19#[allow(unused_imports)]
20use crate::{
21 arch::{create_thunk, ThunkInfo},
22 cc,
23 jit_alloc::{JitAlloc, JitAllocError},
24 thunk::{FnMutThunk, FnOnceThunk, FnThunk},
25};
26
27macro_rules! cc_shorthand {
28 ($fn_name:ident, $trait_ident:ident, $cc_ty:ty, $cc_name:literal $(,$cfg:meta)?) => {
29 $(#[cfg(any($cfg, doc))])?
30 #[doc = "Create a bare function thunk using the "]
31 #[doc = $cc_name]
32 #[doc = "calling convention for `fun`."]
33 #[inline]
36 pub fn $fn_name(fun: F) -> Self
37 where
38 ($cc_ty, F): $trait_ident<$cc_ty, B>,
39 {
40 Self::new(<$cc_ty>::default(), fun)
41 }
42 };
43}
44
45macro_rules! cc_shorthand_in {
46 ($fn_name:ident, $trait_ident:ident, $cc_ty:ty, $cc_name:literal $(,$cfg:meta)?) => {
47 $(#[cfg(any($cfg, doc))])?
48 #[doc = "Create a bare function thunk using the "]
49 #[doc = $cc_name]
50 #[doc = "calling convention for `fun`."]
51 #[inline]
54 pub fn $fn_name(fun: F, jit_alloc: A) -> Self
55 where
56 ($cc_ty, F): $trait_ident<$cc_ty, B>,
57 {
58 Self::new_in(<$cc_ty>::default(), fun, jit_alloc)
59 }
60 };
61}
62
63macro_rules! bare_closure_impl {
64 (
65 $ty_name:ident,
66 $trait_ident:ident,
67 $thunk_template:ident,
68 $bare_toggle:meta,
69 $bare_receiver:ty,
70 $fn_trait_doc:literal,
71 $safety_doc:literal
72 ) => {
73 #[cfg(any(feature = "bundled_jit_alloc", feature = "custom_jit_alloc"))]
74 #[cfg_attr(feature = "build-docs", doc(cfg(all())))]
75 #[doc = $fn_trait_doc]
77 #[allow(dead_code)]
80 pub struct $ty_name<B: Copy, F, A: JitAlloc = GlobalJitAlloc> {
81 thunk_info: ThunkInfo,
82 jit_alloc: A,
83 closure: *mut F,
87 phantom: PhantomData<B>,
88 }
89
90 #[cfg(not(any(feature = "bundled_jit_alloc", feature = "custom_jit_alloc")))]
91 #[doc = $fn_trait_doc]
93 #[allow(dead_code)]
96 pub struct $ty_name<B: Copy, F, A: JitAlloc> {
97 thunk_info: ThunkInfo,
98 jit_alloc: A,
99 closure: *mut F,
100 phantom: PhantomData<B>,
101 }
102
103 unsafe impl<B: Copy, F: Send, A: JitAlloc + Send> Send for $ty_name<B, F, A> {}
105 unsafe impl<B: Copy, F: Sync, A: JitAlloc + Sync> Sync for $ty_name<B, F, A> {}
107
108 impl<B: Copy, F, A: JitAlloc> $ty_name<B, F, A> {
109 #[allow(unused_variables)]
114 #[deprecated(since = "0.3.0", note = "please use `try_new_in` instead")]
115 pub fn with_jit_alloc<CC>(
116 cconv: CC,
117 fun: F,
118 jit_alloc: A,
119 ) -> Result<Self, JitAllocError>
120 where
121 (CC, F): $trait_ident<CC, B>,
122 {
123 Self::try_new_in(cconv, fun, jit_alloc)
124 }
125
126 #[allow(unused_variables)]
131 pub fn try_new_in<CC>(cconv: CC, fun: F, jit_alloc: A) -> Result<Self, JitAllocError>
132 where
133 (CC, F): $trait_ident<CC, B>,
134 {
135 let closure = Box::into_raw(Box::new(fun));
136
137 let thunk_info = unsafe {
141 create_thunk(<(CC, F)>::$thunk_template, closure as *const _, &jit_alloc)?
142 };
143 Ok(Self {
144 thunk_info,
145 jit_alloc,
146 closure,
147 phantom: PhantomData,
148 })
149 }
150
151 #[allow(unused_variables)]
160 pub fn new_in<CC>(cconv: CC, fun: F, jit_alloc: A) -> Self
161 where
162 (CC, F): $trait_ident<CC, B>,
163 {
164 Self::try_new_in(cconv, fun, jit_alloc).unwrap()
165 }
166
167 cc_shorthand_in!(new_c_in, $trait_ident, cc::C, "C");
168
169 cc_shorthand_in!(new_system_in, $trait_ident, cc::System, "system");
170
171 cc_shorthand_in!(
172 new_sysv64_in,
173 $trait_ident,
174 cc::Sysv64,
175 "sysv64",
176 all(not(windows), target_arch = "x86_64")
177 );
178
179 cc_shorthand_in!(
180 new_aapcs_in,
181 $trait_ident,
182 cc::Aapcs,
183 "aapcs",
184 any(doc, target_arch = "arm")
185 );
186
187 cc_shorthand_in!(
188 new_fastcall_in,
189 $trait_ident,
190 cc::Fastcall,
191 "fastcall",
192 all(windows, any(target_arch = "x86_64", target_arch = "x86"))
193 );
194
195 cc_shorthand_in!(
196 new_stdcall_in,
197 $trait_ident,
198 cc::Stdcall,
199 "stdcall",
200 all(windows, any(target_arch = "x86_64", target_arch = "x86"))
201 );
202
203 cc_shorthand_in!(
204 new_cdecl_in,
205 $trait_ident,
206 cc::Cdecl,
207 "cdecl",
208 all(windows, any(target_arch = "x86_64", target_arch = "x86"))
209 );
210
211 cc_shorthand_in!(
212 new_thiscall_in,
213 $trait_ident,
214 cc::Thiscall,
215 "thiscall",
216 all(windows, target_arch = "x86")
217 );
218
219 cc_shorthand_in!(
220 new_win64_in,
221 $trait_ident,
222 cc::Win64,
223 "win64",
224 all(windows, target_arch = "x86_64")
225 );
226
227 #[$bare_toggle]
228 #[doc = $safety_doc]
235 #[inline]
236 pub fn bare(self: $bare_receiver) -> B {
237 unsafe { core::mem::transmute_copy(&self.thunk_info.thunk) }
239 }
240
241 #[doc = $safety_doc]
250 #[inline]
251 pub fn leak(self) -> B
252 where
253 Self: 'static,
254 {
255 let no_drop = ManuallyDrop::new(self);
256 unsafe { core::mem::transmute_copy(&no_drop.thunk_info.thunk) }
258 }
259 }
260
261 impl<B: Copy, F, A: JitAlloc> Drop for $ty_name<B, F, A> {
262 fn drop(&mut self) {
263 unsafe { self.jit_alloc.release(self.thunk_info.alloc_base).ok() };
270
271 drop(unsafe { Box::from_raw(self.closure) })
276 }
277 }
278
279 #[cfg(any(feature = "bundled_jit_alloc", feature = "custom_jit_alloc"))]
280 impl<B: Copy, F> $ty_name<B, F, GlobalJitAlloc> {
281 #[inline]
285 pub fn new<CC>(cconv: CC, fun: F) -> Self
286 where
287 (CC, F): $trait_ident<CC, B>,
288 {
289 Self::new_in(cconv, fun, Default::default())
290 }
291
292 cc_shorthand!(new_c, $trait_ident, cc::C, "C");
293
294 cc_shorthand!(new_system, $trait_ident, cc::System, "system");
295
296 cc_shorthand!(
297 new_sysv64,
298 $trait_ident,
299 cc::Sysv64,
300 "sysv64",
301 all(not(windows), target_arch = "x86_64")
302 );
303
304 cc_shorthand!(
305 new_aapcs,
306 $trait_ident,
307 cc::Aapcs,
308 "aapcs",
309 any(doc, target_arch = "arm")
310 );
311
312 cc_shorthand!(
313 new_fastcall,
314 $trait_ident,
315 cc::Fastcall,
316 "fastcall",
317 all(windows, any(target_arch = "x86_64", target_arch = "x86"))
318 );
319
320 cc_shorthand!(
321 new_stdcall,
322 $trait_ident,
323 cc::Stdcall,
324 "stdcall",
325 all(windows, any(target_arch = "x86_64", target_arch = "x86"))
326 );
327
328 cc_shorthand!(
329 new_cdecl,
330 $trait_ident,
331 cc::Cdecl,
332 "cdecl",
333 all(windows, any(target_arch = "x86_64", target_arch = "x86"))
334 );
335
336 cc_shorthand!(
337 new_thiscall,
338 $trait_ident,
339 cc::Thiscall,
340 "thiscall",
341 all(windows, target_arch = "x86")
342 );
343
344 cc_shorthand!(
345 new_win64,
346 $trait_ident,
347 cc::Win64,
348 "win64",
349 all(windows, target_arch = "x86_64")
350 );
351 }
352 };
353}
354
355bare_closure_impl!(
364 BareFnOnce,
365 FnOnceThunk,
366 THUNK_TEMPLATE_ONCE,
367 cfg(any()),
368 Self,
369 "[`FnOnce`]",
370 "- The function has been called before.\n
371- The closure is not `Send`, if calling from a different thread than the current one."
372);
373
374bare_closure_impl!(
375 BareFnMut,
376 FnMutThunk,
377 THUNK_TEMPLATE_MUT,
378 cfg(all()),
379 &Self,
380 "[`FnMut`]",
381 "- A borrow induced by a previous call is still active.\n
382- The closure is not `Sync`, if calling from a different thread than the current one."
383);
384bare_closure_impl!(
385 BareFn,
386 FnThunk,
387 THUNK_TEMPLATE,
388 cfg(all()),
389 &Self,
390 "[`Fn`]",
391 "- The closure is not `Sync`, if calling from a different thread than the current one."
392);