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);