closure_ffi/bare_closure.rs
1//! Provides the [`BareFnOnce`], [`BareFnMut`] and [`BareFn`] wrapper types which allow closures to
2//! be called through context-free unsafe bare functions.
3//!
4//! Variants which erase the signature of the bare function (e.g. [`UntypedBareFn`]) are also
5//! provided. This can be useful when a type needs to own wrappers for functions of different
6//! signatures.
7//!
8//! # Thread Safety
9//!
10//! The closure wrapper types provided by this module are (trivially) [`Send`] if and only if both
11//! the closure's type-erased storage and the executable memory allocator used are.
12//!
13//! Canonically, they should also always be [`Sync`], as the invariants required for soundly
14//! calling the wrapped closure across threads are encoded in the `unsafe`ness of the
15//! bare function pointer returned by [`BareFnOnce::leak`], [`BareFnMut::bare`] and
16//! [`BareFn::bare`], and documented on these (safe) functions.
17//!
18//! However, such a [`Sync`] impl makes it very easy to call the bare function in situations where
19//! it is not allowed:
20//!
21//! ```compile_fail
22//! use closure_ffi::BareFn;
23//! use std::{cell::Cell, thread};
24//! let cell = Cell::new(0);
25//! // WARNING: `wrapped` is Sync, but not the closure!
26//! let wrapped = BareFn::new_c(move || -> u32 {
27//! let val = cell.get();
28//! cell.set(val + 1);
29//! val
30//! });
31//! // `wrapped` can be borrowed here at is it Sync. But by `bare()` documentation,
32//! // calling the function is unsound as the closure is not Sync!
33//! thread::scope(|s| {
34//! s.spawn(|| unsafe { wrapped.bare()() });
35//! s.spawn(|| unsafe { wrapped.bare()() });
36//! });
37//! ```
38//!
39//! To help guard against this, [`Sync`] is only implemented:
40//! - for [`BareFnOnceAny`]: When the closure is [`Send`]. The user is still responsible for
41//! guarding against repeated calls.
42//! - for [`BareFnMutAny`]: When the closure is [`Send`]. The user is still responsible for guarding
43//! against unsynchronized calls.
44//! - for [`BareFnAny`]: When the closure is [`Sync`].
45
46use alloc::boxed::Box;
47use core::{marker::PhantomData, mem::ManuallyDrop};
48
49#[cfg(feature = "proc_macros")]
50#[doc(hidden)]
51pub use closure_ffi_proc_macros::bare_hrtb as bare_hrtb_impl;
52
53#[cfg(feature = "global_jit_alloc")]
54use crate::jit_alloc::GlobalJitAlloc;
55#[allow(unused_imports)]
56use crate::{
57 arch::AllocatedThunk,
58 cc,
59 jit_alloc::{JitAlloc, JitAllocError},
60 traits::{Any, FnMutThunk, FnOnceThunk, FnPtr, FnThunk, ToBoxedDyn},
61};
62
63#[cfg(not(feature = "coverage"))]
64#[doc(hidden)]
65#[macro_export]
66macro_rules! bare_hrtb_inner {
67 ($($tokens:tt)*) => {
68 $crate::bare_closure::bare_hrtb_impl! { $crate, $($tokens)* }
69 };
70}
71
72#[cfg(feature = "coverage")]
73#[doc(hidden)]
74#[macro_export]
75macro_rules! bare_hrtb_inner {
76 ($($tokens:tt)*) => {
77 $crate::bare_closure::bare_hrtb_impl! { #[coverage(off)] $crate, $($tokens)* }
78 };
79}
80
81/// Declares a wrapper type around a higher-ranked bare function which can be used with [BareFn] and
82/// friends.
83///
84/// <div class="warning">
85///
86/// Note that if using the `coverage` crate feature, the code generated by this macro will require
87/// the [`coverage_attribute`](https://doc.rust-lang.org/beta/unstable-book/language-features/coverage-attribute.html)
88/// unstable Rust feature to be enabled.
89///
90/// </div>
91///
92/// # Usage
93///
94/// The syntax is equivalent to that of a type alias:
95/// ```
96/// #![cfg_attr(feature = "coverage", feature(coverage_attribute))]
97///
98/// closure_ffi::bare_hrtb! {
99/// type MyFn = for<'a> extern "C" fn(&'a str) -> &'a u32;
100/// }
101/// ```
102///
103/// `unsafe` is automatically added to the function signature if absent. Generic type parameters and
104/// bounds can be added to the alias:
105/// ```
106/// #![cfg_attr(feature = "coverage", feature(coverage_attribute))]
107///
108/// closure_ffi::bare_hrtb! {
109/// type MyFn<T: Clone + 'static> = for<'a> extern "C" fn(&'a T) -> T;
110/// }
111/// ```
112///
113/// A calling convention marker type is also created under the alias named suffixed by `_CC`, with
114/// the same visibility.
115///
116/// # Limitations
117///
118/// ## Maximum of 3 independent lifetimes
119///
120/// Higher-ranked bare functions with more than 3 independent bound lifetimes are not supported.
121/// For example, the following will not compile:
122///
123/// ```compile_fail
124/// #![cfg_attr(feature = "coverage", feature(coverage_attribute))]
125///
126/// closure_ffi::bare_hrtb! {
127/// type MyFn = extern "C" fn<'a, 'b, 'c, 'd>(&'a u8, &'b u8) -> (&'c u8, &'d u8);
128/// }
129/// ```
130///
131/// ## No implicit higher-ranked lifetimes
132///
133/// Furthermore, implicit higher-ranked lifetimes are not supported in the signature. So
134/// ```compile_fail
135/// #![cfg_attr(feature = "coverage", feature(coverage_attribute))]
136///
137/// closure_ffi::bare_hrtb! {
138/// type MyFn = extern "C" fn(&u8) -> &u8;
139/// }
140/// ```
141///
142/// must instead be written as
143/// ```
144/// #![cfg_attr(feature = "coverage", feature(coverage_attribute))]
145///
146/// closure_ffi::bare_hrtb! {
147/// type MyFn = for<'a> extern "C" fn(&'a u8) -> &'a u8;
148/// }
149/// ```
150///
151/// ## Static bound requirements on generic parameters
152///
153/// Generic parameters whose lifetime is implicitly lower-bounded by one of the `for<...>` lifetimes
154/// must be `'static`. For example, the following will not compile without a `'static` bound on `T`
155/// and `U`, but no bound is required on `V`:
156///
157/// ```compile_fail
158/// #![cfg_attr(feature = "coverage", feature(coverage_attribute))]
159///
160/// struct RefMut<'a, T>(&'a mut T);
161///
162/// closure_ffi::bare_hrtb! {
163/// type MyFn<T, U, V> = for<'a> extern "C" fn(&'a T, RefMut<'a, U>) -> V;
164/// }
165/// ```
166///
167/// # Why use this macro?
168///
169/// Higher-ranked bare functions are not automatically supported by `closure-ffi` as
170/// - It is not possible to blanket implement traits for them;
171/// - Even if it was possible, type inference via closure annotations would become impossible when
172/// references are involved.
173///
174/// Hence the following won't compile:
175/// ```compile_fail
176/// #![cfg_attr(feature = "coverage", feature(coverage_attribute))]
177///
178/// use closure_ffi::BareFn;
179///
180/// fn take_higher_rank_fn(
181/// bare_fn: unsafe extern "C" fn(&Option<u32>) -> Option<&u32>
182/// ) {}
183///
184/// let bare_closure = BareFn::new_c(|opt: &Option<u32>| opt.as_ref());
185/// take_higher_rank_fn(bare_closure.bare());
186/// ```
187///
188/// However, using the type generated by this macro as the bare function type, we can get it to
189/// work:
190/// ```
191/// #![cfg_attr(feature = "coverage", feature(coverage_attribute))]
192///
193/// use closure_ffi::{BareFn, bare_hrtb};
194///
195/// bare_hrtb! {
196/// type MyFn = for<'a> extern "C" fn(&'a Option<u32>) -> Option<&'a u32>;
197/// }
198///
199/// fn take_higher_rank_fn(
200/// bare_fn: unsafe extern "C" fn(&Option<u32>) -> Option<&u32>
201/// ) {}
202///
203/// // alternatively, BareFn::with_cc(MyFn_CC, |opt| opt.as_ref())
204/// let bare_closure = BareFn::<MyFn>::new(|opt| opt.as_ref());
205/// take_higher_rank_fn(bare_closure.bare().into());
206/// ```
207#[cfg(feature = "proc_macros")]
208#[macro_export]
209macro_rules! bare_hrtb {
210 ($($tokens:tt)*) => {
211 $crate::bare_hrtb_inner! { $($tokens)* }
212 };
213}
214
215#[cfg(feature = "proc_macros")]
216pub use bare_hrtb;
217
218#[allow(unused_macros)]
219macro_rules! cc_shorthand {
220 ($fn_name:ident, $trait_ident:ident, $cc_ty:ty, $cc_name:literal $(,$cfg:meta)?) => {
221 $(#[cfg(any($cfg, doc))])?
222 #[doc = "Create a bare function thunk using the "]
223 #[doc = $cc_name]
224 #[doc = "calling convention for `fun`."]
225 ///
226 /// The W^X memory required is allocated using the global JIT allocator.
227 #[inline]
228 pub fn $fn_name<F>(fun: F) -> Self
229 where
230 F: ToBoxedDyn<S>,
231 ($cc_ty, F): $trait_ident<B>,
232 {
233 Self::with_cc(<$cc_ty>::default(), fun)
234 }
235 };
236}
237
238macro_rules! cc_shorthand_in {
239 ($fn_name:ident, $trait_ident:ident, $cc_ty:ty, $cc_name:literal $(,$cfg:meta)?) => {
240 $(#[cfg(any($cfg, doc))])?
241 #[doc = "Create a bare function thunk using the "]
242 #[doc = $cc_name]
243 #[doc = "calling convention for `fun`."]
244 ///
245 /// The W^X memory required is allocated using the provided JIT allocator.
246 #[inline]
247 pub fn $fn_name<F>(fun: F, jit_alloc: A) -> Self
248 where
249 F: ToBoxedDyn<S>,
250 ($cc_ty, F): $trait_ident<B>,
251 {
252 Self::with_cc_in(<$cc_ty>::default(), fun, jit_alloc)
253 }
254 };
255}
256
257macro_rules! bare_closure_impl {
258 (
259 ty_name: $ty_name:ident,
260 erased_ty_name: $erased_ty_name:ident,
261 non_sync_alias: $non_sync_alias:ident,
262 sync_alias: $sync_alias:ident,
263 sync_bounds: ($($sync_bounds: path),*),
264 sync_alias_bound: $sync_alias_bound: ty,
265 trait_ident: $trait_ident:ident,
266 thunk_template: $thunk_template:ident,
267 bare_toggle: $bare_toggle:meta,
268 bare_receiver: $bare_receiver:ty,
269 fn_trait_doc: $fn_trait_doc:literal,
270 ty_name_doc: $ty_name_doc:literal,
271 with_cc_doc: $with_cc_doc:literal,
272 with_cc_in_doc: $with_cc_in_doc:literal,
273 try_with_cc_in_doc: $try_with_cc_in_doc:literal,
274 non_sync_alias_doc: $non_sync_alias_doc:literal,
275 sync_alias_doc: $sync_alias_doc:literal,
276 sync_alias_bound_doc: $sync_alias_bound_doc:literal,
277 safety_doc: $safety_doc:literal
278 ) => {
279 #[cfg(feature = "global_jit_alloc")]
280 #[cfg_attr(docsrs, doc(cfg(all())))]
281 /// Type-erased wrapper around a
282 #[doc = $fn_trait_doc]
283 /// closure which exposes a pointer to a bare function thunk.
284 ///
285 /// This type cannot be directly constructed; it must be produced from a
286 #[doc = $ty_name_doc]
287 /// through the `into_untyped` method or the [`Into`] trait.
288 ///
289 /// # Type parameters
290 /// - `S`: The dynamically-sized type to use to type-erase the closure. Use this to enforce
291 /// lifetime bounds and marker traits which the closure must satisfy, e.g. `S = dyn Send +
292 /// 'a`. Without the `unstable` feature, this is limited to [`dyn Any`](Any) and
293 /// combinations of [`Send`] and [`Sync`] marker types.
294 /// - `A`: The [`JitAlloc`] implementation used to allocate and free executable memory.
295 ///
296 /// # Layout
297 #[doc = $ty_name_doc]
298 /// is `#[repr(transparent)]` with this type, so it is safe to transmute back and forth
299 /// provided the type parameters match.
300 #[allow(dead_code)]
301 pub struct $erased_ty_name<S: ?Sized, A: JitAlloc = GlobalJitAlloc> {
302 thunk: AllocatedThunk<A>,
303 // We can't directly own the closure, even through an UnsafeCell.
304 // Otherwise, holding a reference to a BareFnMut while the bare function is
305 // being called would be UB! So we reclaim the pointer in the Drop impl.
306 storage: *mut S,
307 }
308
309 // We copy the documentation to this type, since IDEs will often fetch it from here for
310 // pop-up documentation if neither feature is on
311 #[cfg(not(feature = "global_jit_alloc"))]
312 /// Type-erased wrapper around a
313 #[doc = $fn_trait_doc]
314 /// closure which exposes a pointer to a bare function thunk.
315 ///
316 /// This type cannot be directly constructed; it must be produced from a
317 #[doc = $ty_name_doc]
318 /// through the `into_untyped` method or the [`Into`] trait.
319 ///
320 /// # Type parameters
321 /// - `S`: The dynamically-sized type to use to type-erase the closure. Use this to enforce
322 /// lifetime bounds and marker traits which the closure must satisfy, e.g. `S = dyn Send +
323 /// 'a`. Without the `unstable` feature, this is limited to [`dyn Any`](Any) and
324 /// combinations of [`Send`] and [`Sync`] marker types.
325 /// - `A`: The [`JitAlloc`] implementation used to allocate and free executable memory.
326 ///
327 /// # Layout
328 #[doc = $ty_name_doc]
329 /// is `#[repr(transparent)]` with this type, so it is safe to transmute back and forth
330 /// provided the type parameters match.
331 #[allow(dead_code)]
332 pub struct $erased_ty_name<S: ?Sized, A: JitAlloc> {
333 thunk: AllocatedThunk<A>,
334 storage: *mut S,
335 }
336
337 // SAFETY: S and A can be moved to other threads
338 unsafe impl<S: ?Sized + Send, A: JitAlloc + Send> Send for $erased_ty_name<S, A> {}
339 // SAFETY: See macro invocation
340 unsafe impl<S: $($sync_bounds+)* ?Sized, A: JitAlloc> Sync for $erased_ty_name<S, A> {}
341
342 impl<S: ?Sized, A: JitAlloc> $erased_ty_name<S, A> {
343 #[$bare_toggle]
344 /// Return a type-erased pointer to the bare function thunk wrapping the closure.
345 ///
346 /// # Safety
347 /// While this method is safe, using the returned pointer is very much not. In
348 /// particular, the only safe thing to do with it is casting it to the exact bare
349 /// function signature it had before erasure. Even then, it must not be called when:
350 /// - The lifetime of `self` has expired, or `self` has been dropped.
351 #[doc = $safety_doc]
352 #[inline]
353 pub fn bare(self: $bare_receiver) -> *const () {
354 self.thunk.thunk_ptr()
355 }
356
357 /// Leak the underlying closure, returning the unsafe bare function pointer that invokes
358 /// it.
359 ///
360 /// `self` must be `'static` for this method to be called.
361 ///
362 /// # Safety
363 /// While this method is safe, using the returned pointer is very much not. In
364 /// particular, the only safe thing to do with it is casting it to the exact bare
365 /// function signature it had before erasure. Even then, it must not be called when:
366 #[doc = $safety_doc]
367 #[inline]
368 pub fn leak(self) -> *const ()
369 where
370 Self: 'static,
371 {
372 ManuallyDrop::new(self).thunk.thunk_ptr()
373 }
374
375 /// Weaken the bounds of the type-erased storage.
376 ///
377 /// For example, a [`UntypedBareFn<dyn Send + Sync>`] may be upcast into a [`UntypedBareFn<dyn Send>`].
378 pub fn upcast<U: ?Sized>(self) -> $erased_ty_name<U, A>
379 where PhantomData<S>: ToBoxedDyn<U>
380 {
381 // SAFETY: This is fine on stable since all trait objects implementing `ToBoxedDyn`
382 // only have the destructor in their vtable.
383 //
384 // With the `unstable` feature, it's sketchy as a boxed `dyn Subtrait` can `Unsize` into
385 // a `dyn Supertrait` when `Subtrait: Supertrait`. However, the undocumented layout of
386 // trait object vtables makes the destructor the first entry, so it's fine for now
387 // (and the foreseeable future).
388 unsafe { core::mem::transmute_copy(&ManuallyDrop::new(self)) }
389 }
390 }
391
392 impl<B: FnPtr, S: ?Sized, U: ?Sized, A: JitAlloc> From<$ty_name<B, S, A>> for $erased_ty_name<U, A>
393 where PhantomData<S>: ToBoxedDyn<U>
394 {
395 fn from(value: $ty_name<B, S, A>) -> Self {
396 value.into_untyped().upcast()
397 }
398 }
399
400 impl<S: ?Sized, A: JitAlloc> Drop for $erased_ty_name<S, A> {
401 fn drop(&mut self) {
402 // Free the closure
403 // SAFETY:
404 // - The caller of `bare()` promised not to call through the thunk after
405 // the lifetime of self expires, so no borrow on closure exists
406 drop(unsafe { Box::from_raw(self.storage) })
407 }
408 }
409
410 #[cfg(feature = "global_jit_alloc")]
411 #[cfg_attr(docsrs, doc(cfg(all())))]
412 /// Wrapper around a
413 #[doc = $fn_trait_doc]
414 /// closure which exposes a bare function thunk that can invoke it without
415 /// additional arguments.
416 ///
417 /// # Note
418 /// This is a generic implementation which allows customizing the closure's
419 /// type erased storage, which allows enforcing trait bounds like `Send` and `Sync` when
420 /// needed. However, this plays poorly with type inference. Consider using the
421 #[doc = $non_sync_alias_doc]
422 /// and
423 #[doc = $sync_alias_doc]
424 /// type aliases for the common cases of [`S = dyn Any + 'a`](Any) (no thread safety constraints)
425 /// and
426 #[doc = $sync_alias_bound_doc]
427 /// (minimum required to safely store/call the closure from other threads), respectively.
428 ///
429 /// # Type parameters
430 /// - `B`: The bare function pointer to expose the closure as. For higher-kinded bare
431 /// function pointers, you will need to use the [`bare_hrtb`] macro to define a wrapper
432 /// type.
433 /// - `S`: The dynamically-sized type to use to type-erase the closure. Use this to enforce
434 /// lifetime bounds and marker traits which the closure must satisfy, e.g. `S = dyn Send +
435 /// 'a`. Without the `unstable` feature, this is limited to [`dyn Any`](Any) and
436 /// combinations of [`Send`] and [`Sync`] marker types.
437 /// - `A`: The [`JitAlloc`] implementation used to allocate and free executable memory.
438 #[allow(dead_code)]
439 #[repr(transparent)]
440 pub struct $ty_name<B: FnPtr, S: ?Sized, A: JitAlloc = GlobalJitAlloc> {
441 untyped: $erased_ty_name<S, A>,
442 phantom: PhantomData<B>,
443 }
444
445 // We copy the documentation to this type, since IDEs will often fetch it from here for
446 // pop-up documentation of neither feature is on
447 #[cfg(not(feature = "global_jit_alloc"))]
448 /// Wrapper around a
449 #[doc = $fn_trait_doc]
450 /// closure which exposes a bare function thunk that can invoke it without
451 /// additional arguments.
452 ///
453 /// This is a generic implementation which allows customizing the closure's
454 /// type erased storage, which allows enforcing trait bounds like `Send` and `Sync` when
455 /// needed. However, this plays poorly with type inference. Consider using the
456 #[doc = $non_sync_alias_doc]
457 /// and
458 #[doc = $sync_alias_doc]
459 /// type aliases for the common cases of [`S = dyn Any + 'a`](Any) (no thread safety constraints)
460 /// and
461 #[doc = $sync_alias_bound_doc]
462 /// (minimum required to safely store/call the closure from other threads), respectively.
463 ///
464 /// # Type parameters
465 /// - `B`: The bare function pointer to expose the closure as. For higher-kinded bare
466 /// function pointers, you will need to use the [`bare_hrtb`] macro to define a wrapper
467 /// type.
468 /// - `S`: The dynamically-sized type to use to type-erase the closure. Use this to enforce
469 /// lifetime bounds and marker traits which the closure must satisfy, e.g. `S = dyn Send +
470 /// 'a`. Without the `unstable` feature, this is limited to [`dyn Any`](Any) and
471 /// combinations of [`Send`] and [`Sync`] marker types.
472 /// - `A`: The [`JitAlloc`] implementation used to allocate and free executable memory.
473 #[allow(dead_code)]
474 pub struct $ty_name<B: FnPtr, S: ?Sized, A: JitAlloc> {
475 untyped: $erased_ty_name<S, A>,
476 phantom: PhantomData<B>,
477 }
478
479 // Split the impl blocks so that the relevant functions appear first in docs
480 #[cfg(feature = "global_jit_alloc")]
481 impl<B: FnPtr, S: ?Sized> $ty_name<B, S, GlobalJitAlloc> {
482 /// Wraps `fun`, producing a bare function of signature `B`.
483 ///
484 /// This constructor is best used when the type of `B` is already known from an existing
485 /// type annotation. If you want to infer `B` from the closure arguments and a calling
486 /// convention, consider using
487 #[doc = $with_cc_doc]
488 /// or the `new_*` suffixed constructors instead.
489 ///
490 /// The W^X memory required is allocated using the global JIT allocator.
491 #[inline]
492 pub fn new<F>(fun: F) -> Self
493 where
494 F: ToBoxedDyn<S>,
495 (B::CC, F): $trait_ident<B>,
496 {
497 Self::new_in(fun, Default::default())
498 }
499
500 /// Wraps `fun`, producing a bare function with calling convention `cconv`.
501 ///
502 /// The W^X memory required is allocated using the global JIT allocator.
503 #[inline]
504 pub fn with_cc<CC, F>(cconv: CC, fun: F) -> Self
505 where
506 F: ToBoxedDyn<S>,
507 (CC, F): $trait_ident<B>,
508 {
509 Self::with_cc_in(cconv, fun, Default::default())
510 }
511
512 /// Create a
513 #[doc = $ty_name_doc]
514 /// directly from a
515 #[doc = concat!("[`", stringify!($trait_ident), "`].")]
516 ///
517 /// The W^X memory required is allocated using the global JIT allocator.
518 pub fn with_thunk<T>(thunk: T) -> Self where T: $trait_ident<B> + ToBoxedDyn<S>
519 {
520 Self::with_thunk_in(thunk, Default::default())
521 }
522 }
523
524 impl<B: FnPtr, S: ?Sized, A: JitAlloc> $ty_name<B, S, A> {
525 #[$bare_toggle]
526 /// Return a bare function pointer that invokes the underlying closure.
527 ///
528 /// # Safety
529 /// While this method is safe, the returned function pointer is not. In particular, it
530 /// must not be called when:
531 /// - The lifetime of `self` has expired, or `self` has been dropped.
532 #[doc = $safety_doc]
533 #[inline]
534 pub fn bare(self: $bare_receiver) -> B {
535 // SAFETY: B is a bare function pointer
536 unsafe { B::from_ptr(self.untyped.bare()) }
537 }
538
539 /// Leak the underlying closure, returning the unsafe bare function pointer that invokes
540 /// it.
541 ///
542 /// `self` must be `'static` for this method to be called.
543 ///
544 /// # Safety
545 /// While this method is safe, the returned function pointer is not. In particular, it
546 /// must not be called when:
547 #[doc = $safety_doc]
548 #[inline]
549 pub fn leak(self) -> B
550 where
551 Self: 'static,
552 {
553 // SAFETY: B is a bare function pointer
554 unsafe { B::from_ptr(self.untyped.leak()) }
555 }
556
557 /// Erase the signature type from this
558 #[doc = $ty_name_doc]
559 ///
560 /// The returned value also exposes the `bare` and `leak` functions.
561 /// However, they now return untyped pointers.
562 pub fn into_untyped(self) -> $erased_ty_name<S, A> {
563 self.untyped
564 }
565
566 /// Weaken the bounds of the type-erased storage.
567 ///
568 /// For example, a [`BareFnAny<B, dyn Send + Sync>`] may be upcast into a [`BareFnAny<B, dyn Send>`].
569 pub fn upcast<U: ?Sized>(self) -> $ty_name<B, U, A>
570 where PhantomData<S>: ToBoxedDyn<U>,
571 {
572 // SAFETY: This is fine on stable since all trait objects implementing `ToBoxedDyn`
573 // only have the destructor in their vtable.
574 //
575 // With the `unstable` feature, it's sketchy as a boxed `dyn Subtrait` can `Unsize` into
576 // a `dyn Supertrait` when `Subtrait: Supertrait`. However, the undocumented layout of
577 // trait object vtables makes the destructor the first entry, so it's fine for now
578 // (and the foreseeable future).
579 unsafe { core::mem::transmute_copy(&ManuallyDrop::new(self)) }
580 }
581
582 /// Wraps `fun`, producing a bare function with calling convention `cconv`.
583 ///
584 /// Uses the provided JIT allocator to allocate the W^X memory used to create the thunk.
585 #[allow(unused_variables)]
586 pub fn try_with_cc_in<CC, F>(
587 cconv: CC,
588 fun: F,
589 jit_alloc: A,
590 ) -> Result<Self, JitAllocError>
591 where
592 F: ToBoxedDyn<S>,
593 (CC, F): $trait_ident<B>,
594 {
595 let storage = Box::into_raw(F::to_boxed_unsize(fun));
596
597 // SAFETY:
598 // - thunk_template pointer obtained from the correct source
599 // - `closure` is a valid pointer to `fun`
600 let thunk = unsafe {
601 AllocatedThunk::new(
602 <(CC, F)>::$thunk_template,
603 storage as *const _, size_of::<F>(),
604 jit_alloc
605 )?
606 };
607 Ok(Self {
608 untyped: $erased_ty_name {
609 thunk,
610 storage
611 },
612 phantom: PhantomData,
613 })
614 }
615
616 /// Wraps `fun`, producing a bare function with calling convention `cconv`.
617 ///
618 /// Uses `jit_alloc` to allocate the W^X memory used to create the thunk.
619 ///
620 /// # Panics
621 /// If the provided JIT allocator fails to allocate memory. For a non-panicking
622 /// version, see
623 #[doc = $try_with_cc_in_doc]
624 #[allow(unused_variables)]
625 #[inline]
626 pub fn with_cc_in<CC, F>(cconv: CC, fun: F, jit_alloc: A) -> Self
627 where
628 F: ToBoxedDyn<S>,
629 (CC, F): $trait_ident<B>,
630 {
631 Self::try_with_cc_in(cconv, fun, jit_alloc).unwrap()
632 }
633
634 /// Wraps `fun`, producing a bare function with signature `B`.
635 ///
636 /// Uses `jit_alloc` to allocate the W^X memory used to create the thunk.
637 ///
638 /// This constructor is best used when the type of `B` is already known from an existing
639 /// type annotation. If you want to infer `B` from the closure arguments and a calling
640 /// convention, consider using
641 #[doc = $with_cc_in_doc]
642 /// instead.
643 ///
644 /// # Panics
645 /// If the provided JIT allocator fails to allocate memory. For a non-panicking
646 /// version, see
647 #[doc = $try_with_cc_in_doc]
648 #[inline]
649 pub fn new_in<F>(fun: F, jit_alloc: A) -> Self
650 where
651 F: ToBoxedDyn<S>,
652 (B::CC, F): $trait_ident<B>,
653 {
654 Self::with_cc_in(B::CC::default(), fun, jit_alloc)
655 }
656
657 /// Create a
658 #[doc = $ty_name_doc]
659 /// directly from a
660 #[doc = concat!("[`", stringify!($trait_ident), "`].")]
661 ///
662 /// Uses `jit_alloc` to allocate the W^X memory used to create the thunk.
663 pub fn try_with_thunk_in<T>(thunk: T, jit_alloc: A) -> Result<Self, JitAllocError>
664 where T: $trait_ident<B> + ToBoxedDyn<S>
665 {
666 // SAFETY: All implementors of `Fn*Thunk` are #[repr(transparent)] with the closure
667 let storage = Box::into_raw(T::to_boxed_unsize(thunk));
668
669 // SAFETY:
670 // - thunk_template pointer obtained from the correct source
671 // - `closure` is a valid pointer to `fun`
672 // - `size_of::<T>()` equals the size of the closure
673 let thunk = unsafe {
674 AllocatedThunk::new(
675 T::$thunk_template,
676 storage as *const _, size_of::<T>(),
677 jit_alloc
678 )?
679 };
680 Ok(Self {
681 untyped: $erased_ty_name {
682 thunk,
683 storage
684 },
685 phantom: PhantomData,
686 })
687 }
688
689 /// Create a
690 #[doc = $ty_name_doc]
691 /// directly from a
692 #[doc = concat!("[`", stringify!($trait_ident), "`].")]
693 ///
694 /// Uses `jit_alloc` to allocate the W^X memory used to create the thunk.
695 ///
696 /// # Panics
697 /// If the provided JIT allocator fails to allocate memory. For a non-panicking
698 /// version, see [`Self::try_with_thunk_in`].
699 #[inline]
700 pub fn with_thunk_in<T>(thunk: T, jit_alloc: A) -> Self
701 where T: $trait_ident<B> + ToBoxedDyn<S>
702 {
703 Self::try_with_thunk_in(thunk, jit_alloc).unwrap()
704 }
705 }
706
707 #[cfg(feature = "global_jit_alloc")]
708 impl<B: FnPtr, S: ?Sized> $ty_name<B, S, GlobalJitAlloc> {
709 cc_shorthand!(new_rust, $trait_ident, cc::Rust, "Rust");
710
711 cc_shorthand!(new_c, $trait_ident, cc::C, "C");
712
713 cc_shorthand!(new_system, $trait_ident, cc::System, "system");
714
715 cc_shorthand!(new_efiabi, $trait_ident, cc::Efiapi, "efiapi");
716
717 cc_shorthand!(
718 new_sysv64,
719 $trait_ident,
720 cc::Sysv64,
721 "sysv64",
722 all(not(windows), target_arch = "x86_64")
723 );
724
725 cc_shorthand!(
726 new_aapcs,
727 $trait_ident,
728 cc::Aapcs,
729 "aapcs",
730 any(doc, target_arch = "arm")
731 );
732
733 cc_shorthand!(
734 new_fastcall,
735 $trait_ident,
736 cc::Fastcall,
737 "fastcall",
738 all(windows, target_arch = "x86")
739 );
740
741 cc_shorthand!(
742 new_stdcall,
743 $trait_ident,
744 cc::Stdcall,
745 "stdcall",
746 all(windows, target_arch = "x86")
747 );
748
749 cc_shorthand!(
750 new_cdecl,
751 $trait_ident,
752 cc::Cdecl,
753 "cdecl",
754 all(windows, target_arch = "x86")
755 );
756
757 cc_shorthand!(
758 new_thiscall,
759 $trait_ident,
760 cc::Thiscall,
761 "thiscall",
762 all(windows, target_arch = "x86")
763 );
764
765 cc_shorthand!(
766 new_win64,
767 $trait_ident,
768 cc::Win64,
769 "win64",
770 all(windows, target_arch = "x86_64")
771 );
772
773 cc_shorthand!(
774 new_variadic,
775 $trait_ident,
776 cc::Variadic,
777 "`C` variadic",
778 feature = "c_variadic"
779 );
780 }
781
782 impl<B: FnPtr, S: ?Sized, A: JitAlloc> $ty_name<B, S, A> {
783 cc_shorthand_in!(new_rust_in, $trait_ident, cc::Rust, "Rust");
784
785 cc_shorthand_in!(new_c_in, $trait_ident, cc::C, "C");
786
787 cc_shorthand_in!(new_system_in, $trait_ident, cc::System, "system");
788
789 cc_shorthand_in!(new_efiabi_in, $trait_ident, cc::Efiapi, "efiapi");
790
791 cc_shorthand_in!(
792 new_sysv64_in,
793 $trait_ident,
794 cc::Sysv64,
795 "sysv64",
796 all(not(windows), target_arch = "x86_64")
797 );
798
799 cc_shorthand_in!(
800 new_aapcs_in,
801 $trait_ident,
802 cc::Aapcs,
803 "aapcs",
804 any(doc, target_arch = "arm")
805 );
806
807 cc_shorthand_in!(
808 new_fastcall_in,
809 $trait_ident,
810 cc::Fastcall,
811 "fastcall",
812 all(windows, target_arch = "x86")
813 );
814
815 cc_shorthand_in!(
816 new_stdcall_in,
817 $trait_ident,
818 cc::Stdcall,
819 "stdcall",
820 all(windows, target_arch = "x86")
821 );
822
823 cc_shorthand_in!(
824 new_cdecl_in,
825 $trait_ident,
826 cc::Cdecl,
827 "cdecl",
828 all(windows, target_arch = "x86")
829 );
830
831 cc_shorthand_in!(
832 new_thiscall_in,
833 $trait_ident,
834 cc::Thiscall,
835 "thiscall",
836 all(windows, target_arch = "x86")
837 );
838
839 cc_shorthand_in!(
840 new_win64_in,
841 $trait_ident,
842 cc::Win64,
843 "win64",
844 all(windows, target_arch = "x86_64")
845 );
846
847 cc_shorthand_in!(
848 new_variadic_in,
849 $trait_ident,
850 cc::Variadic,
851 "`C` variadic",
852 feature = "c_variadic"
853 );
854 }
855
856 #[cfg(feature = "global_jit_alloc")]
857 #[cfg_attr(docsrs, doc(cfg(all())))]
858 /// Wrapper around a
859 #[doc = $fn_trait_doc]
860 /// closure which exposes a bare function thunk that can invoke it without
861 /// additional arguments.
862 ///
863 /// This is a type alias only. Additional details and methods are described on the
864 #[doc = $ty_name_doc]
865 /// type.
866 pub type $non_sync_alias<'a, B, A = GlobalJitAlloc> = $ty_name<B, dyn Any + 'a, A>;
867
868 #[cfg(not(feature = "global_jit_alloc"))]
869 /// Wrapper around a
870 #[doc = $fn_trait_doc]
871 /// closure which exposes a bare function thunk that can invoke it without
872 /// additional arguments.
873 ///
874 /// This is a type alias only. Additional details and methods are described on the
875 #[doc = $ty_name_doc]
876 /// type.
877 pub type $non_sync_alias<'a, B, A> = $ty_name<B, dyn Any + 'a, A>;
878
879 #[cfg(feature = "global_jit_alloc")]
880 #[cfg_attr(docsrs, doc(cfg(all())))]
881 /// Wrapper around a
882 #[doc = $fn_trait_doc]
883 /// closure which exposes a bare function thunk that can invoke it without
884 /// additional arguments.
885 ///
886 /// Unlike
887 #[doc = $non_sync_alias_doc]
888 /// this type enforces the correct combination of [`Send`] and [`Sync`] on the
889 /// closure so that it is safe to both store and call from other threads.
890 ///
891 /// This is a type alias only. Additional details and methods are described on the
892 #[doc = $ty_name_doc]
893 /// type.
894 pub type $sync_alias<'a, B, A = GlobalJitAlloc> = $ty_name<B, $sync_alias_bound, A>;
895
896 #[cfg(not(feature = "global_jit_alloc"))]
897 /// Wrapper around a
898 #[doc = $fn_trait_doc]
899 /// closure which exposes a bare function thunk that can invoke it without
900 /// additional arguments.
901 ///
902 /// Unlike
903 #[doc = $non_sync_alias_doc]
904 /// this type enforces the correct combination of [`Send`] and [`Sync`] on the
905 /// closure so that it is safe to both store and call from other threads.
906 ///
907 /// This is a type alias only. Additional details and methods are described on the
908 #[doc = $ty_name_doc]
909 /// type.
910 pub type $sync_alias<'a, B, A> = $ty_name<B, $sync_alias_bound, A>;
911 };
912}
913
914// TODO:
915// BareFnOnce still needs work.
916// In particular, to avoid leaks we need to have the compiler generated thunk
917// call `release` on the allocator after it's done running, then drop the allocator.
918// Then, to avoid double frees we need `bare` to be taken by value.
919//
920// At the moment, we simply force leaking for `BareFnOnce` by omitting `bare()`.
921
922bare_closure_impl!(
923 ty_name: BareFnOnceAny,
924 erased_ty_name: UntypedBareFnOnce,
925 non_sync_alias: BareFnOnce,
926 sync_alias: BareFnOnceSync,
927 sync_bounds: (Send), // FnOnce only needs to be Send
928 sync_alias_bound: dyn Send + 'a,
929 trait_ident: FnOnceThunk,
930 thunk_template: THUNK_TEMPLATE_ONCE,
931 bare_toggle: cfg(any()),
932 bare_receiver: Self,
933 fn_trait_doc: "[`FnOnce`]",
934 ty_name_doc: "[`BareFnOnceAny`]",
935 with_cc_doc: "[`with_cc`](BareFnOnceAny::with_cc)",
936 with_cc_in_doc: "[`with_cc_in`](BareFnOnceAny::with_cc_in)",
937 try_with_cc_in_doc: "[`try_with_cc_in`](BareFnOnceAny::try_with_cc_in)",
938 non_sync_alias_doc: "[`BareFnOnce`]",
939 sync_alias_doc: "[`BareFnOnceSync`]",
940 sync_alias_bound_doc: "[`S = dyn Send + 'a`](Send)",
941 safety_doc: "- The function has been called before.\n
942- The closure is not `Send`, if calling from a different thread than the current one."
943);
944
945bare_closure_impl!(
946 ty_name: BareFnMutAny,
947 erased_ty_name: UntypedBareFnMut,
948 non_sync_alias: BareFnMut,
949 sync_alias: BareFnMutSync,
950 sync_bounds: (Send), // For FnMut we only need Send to make synchronized calls safe
951 sync_alias_bound: dyn Send + 'a,
952 trait_ident: FnMutThunk,
953 thunk_template: THUNK_TEMPLATE_MUT,
954 bare_toggle: cfg(all()),
955 bare_receiver: &Self,
956 fn_trait_doc: "[`FnMut`]",
957 ty_name_doc: "[`BareFnMutAny`]",
958 with_cc_doc: "[`with_cc`](BareFnMutAny::with_cc)",
959 with_cc_in_doc: "[`with_cc_in`](BareFnMutAny::with_cc_in)",
960 try_with_cc_in_doc: "[`try_with_cc_in`](BareFnMutAny::try_with_cc_in)",
961 non_sync_alias_doc: "[`BareFnMut`]",
962 sync_alias_doc: "[`BareFnMutSync`]",
963 sync_alias_bound_doc: "[`S = dyn Send + 'a`](Send)",
964 safety_doc: "- The mutable borrow induced by a previous call is still active (e.g. through recursion)
965 or concurrent (has no happens-before relationship) with the current one.\n
966- The closure is not `Send`, if calling from a different thread than the current one."
967);
968bare_closure_impl!(
969 ty_name: BareFnAny,
970 erased_ty_name: UntypedBareFn,
971 non_sync_alias: BareFn,
972 sync_alias: BareFnSync,
973 sync_bounds: (Sync),
974 sync_alias_bound: dyn Send + Sync + 'a,
975 trait_ident: FnThunk,
976 thunk_template: THUNK_TEMPLATE,
977 bare_toggle: cfg(all()),
978 bare_receiver: &Self,
979 fn_trait_doc: "[`Fn`]",
980 ty_name_doc: "[`BareFnAny`]",
981 with_cc_doc: "[`with_cc`](BareFnAny::with_cc)",
982 with_cc_in_doc: "[`with_cc_in`](BareFnAny::with_cc_in)",
983 try_with_cc_in_doc: "[`try_with_cc_in`](BareFnAny::try_with_cc_in)",
984 non_sync_alias_doc: "[`BareFn`]",
985 sync_alias_doc: "[`BareFnSync`]",
986 sync_alias_bound_doc: "[`S = dyn Send + Sync + 'a`](Sync)",
987 safety_doc: "- The closure is not `Sync`, if calling from a different thread than the current one."
988);