closure_ffi/
traits.rs

1//! Traits that `closure-ffi` uses to power its functionality.
2
3use alloc::boxed::Box;
4
5/// Dummy trait implemented by every type.
6///
7/// As such, its trait object vtable only contains the drop impl for the type. Used to type erase
8/// the closure type in [`BareFn`](crate::BareFn) and friends.
9pub trait Any {}
10impl<T: ?Sized> Any for T {}
11
12/// Trait to construct a [`Box<dyn Trait>`] from a type implementing
13/// [`Unsize<dyn Trait>`](core::marker::Unsize).
14///
15/// Since [`Unsize<T>`](core::marker::Unsize) is gated behind the `unsize` nightly feature,
16/// on stable Rust this trait is only implemented for:
17/// - [`dyn Any + '_`](Any)
18/// - [`dyn Send + '_`](Send)
19/// - [`dyn Sync + '_`](Sync)
20/// - `dyn Send + Sync + '_`
21///
22/// Enable the `unstable` feature to support all possible coercions.
23///
24/// # Safety
25/// - `T` must be some trait object type `dyn Trait + Markers + 'a`, where `Markers` are optional
26///   marker traits (e.g. [`Send`] and [`Sync`]).
27/// - Given the same `T` as above, implementers must also implement `Trait`, `Markers` and outlive
28///   `'a`.
29pub unsafe trait ToBoxedDyn<T: ?Sized> {
30    /// Constructs a [`Box<T>`] from `Self`, coercing into the unsized type.
31    fn to_boxed_unsize(value: Self) -> Box<T>;
32}
33
34#[cfg(not(feature = "unstable"))]
35unsafe impl<'a, T: 'a> ToBoxedDyn<dyn Any + 'a> for T {
36    fn to_boxed_unsize(value: Self) -> Box<dyn Any + 'a> {
37        Box::new(value)
38    }
39}
40
41#[cfg(not(feature = "unstable"))]
42unsafe impl<'a, T: Send + 'a> ToBoxedDyn<dyn Send + 'a> for T {
43    fn to_boxed_unsize(value: Self) -> Box<dyn Send + 'a> {
44        Box::new(value)
45    }
46}
47
48#[cfg(not(feature = "unstable"))]
49unsafe impl<'a, T: Sync + 'a> ToBoxedDyn<dyn Sync + 'a> for T {
50    fn to_boxed_unsize(value: Self) -> Box<dyn Sync + 'a> {
51        Box::new(value)
52    }
53}
54
55#[cfg(not(feature = "unstable"))]
56unsafe impl<'a, T: Send + Sync + 'a> ToBoxedDyn<dyn Send + Sync + 'a> for T {
57    fn to_boxed_unsize(value: Self) -> Box<dyn Send + Sync + 'a> {
58        Box::new(value)
59    }
60}
61
62#[cfg(feature = "unstable")]
63// SAFETY:
64// - we restrict T to be a `dyn Trait`, not just any DST,
65// - the `Unsize` impl guarantees implementation of `T` by `U`
66unsafe impl<T: ?Sized, U: core::marker::Unsize<T>> ToBoxedDyn<T> for U
67where
68    T: core::ptr::Pointee<Metadata = core::ptr::DynMetadata<T>>,
69{
70    fn to_boxed_unsize(value: Self) -> Box<T> {
71        Box::<U>::new(value)
72    }
73}
74
75/// Trait implemented by unsafe function pointer types of up to 12 arguments.
76///
77/// Allows introspection of the function's calling convention, arguments, return type, and provides
78/// a `call` method for invoking the function.
79///
80/// # Limitations
81/// The trait cannot be automatically implemented for higher-kinded (i.e. `for <'a> fn`) bare
82/// functions. For these, use the [`bare_hrtb!`](crate::bare_hrtb) macro to create a transparent
83/// wrapper type which implements the trait. Furthermore, the trait cannot be implemented *at all*
84/// for higher-kinded bare functions which have more than 3 independent lifetimes.
85///
86/// # Safety
87/// - The trait *must not* be implemented on a type that is not `#[repr(transparent)]` with a
88///   function pointer, i.e. has a different size/alignment.
89///
90/// - When implemented on a non-function pointer type that is `#[repr(transparent)]` to a function
91///   pointer, all associated types ([`CC`][`FnPtr::CC`], [`Args`](FnPtr::Args) and
92///   [`Ret`](FnPtr::Ret)) must be consistent with the function pointer.
93pub unsafe trait FnPtr: Sized + Copy + Send + Sync {
94    /// Marker type for the bare function's calling convention.
95    ///
96    /// This is *required* to be a ZST; in particular it must be safe to create an
97    /// instance via [`core::mem::zeroed`] or a reference via [`core::ptr::dangling`].
98    type CC: Default + Copy + Send + Sync;
99
100    #[cfg(all(not(doc), feature = "tuple_trait"))]
101    /// The arguments of the function, as a tuple.
102    ///
103    /// This is a GAT with 3 independent lifetimes to support most higher-kinded bare functions.
104    type Args<'a, 'b, 'c>: core::marker::Tuple;
105
106    #[cfg(any(doc, not(feature = "tuple_trait")))]
107    #[cfg_attr(docsrs, doc(cfg(all())))]
108    /// The arguments of the function, as a tuple.
109    ///
110    /// This is a GAT with 3 independent lifetimes to support most higher-kinded bare functions.
111    ///
112    /// When the `tuple_trait` crate feature is enabled, this associated type has a
113    /// [`core::marker::Tuple`] bound. Note that this also requires the `tuple_trait` nightly
114    /// feature.
115    type Args<'a, 'b, 'c>;
116
117    /// The return type of the function.
118    ///
119    /// This is a GAT with 3 independent lifetimes to support most higher-kinded bare functions.
120    type Ret<'a, 'b, 'c>;
121
122    /// Calls self.
123    ///
124    /// # Safety
125    /// The same function-specific safety invariants must be upheld as when calling it directly.
126    unsafe fn call<'a, 'b, 'c>(self, args: Self::Args<'a, 'b, 'c>) -> Self::Ret<'a, 'b, 'c>;
127
128    /// Creates `Self` from an untyped pointer.
129    ///
130    /// # Safety
131    /// The untyped pointer must point to a valid instance of `Self`.
132    unsafe fn from_ptr(ptr: *const ()) -> Self;
133
134    /// Casts `self` to an untyped pointer.
135    fn to_ptr(self) -> *const ();
136
137    /// Creates a [`FnOnceThunk`] implementation from a closure taking the same arguments as this
138    /// function pointer.
139    fn make_once_thunk<F>(fun: F) -> impl FnOnceThunk<Self>
140    where
141        F: for<'a, 'b, 'c> PackedFnOnce<'a, 'b, 'c, Self>;
142
143    /// Creates a [`FnMutThunk`] implementation from a closure taking the same arguments as this
144    /// function pointer.
145    fn make_mut_thunk<F>(fun: F) -> impl FnMutThunk<Self>
146    where
147        F: for<'a, 'b, 'c> PackedFnMut<'a, 'b, 'c, Self>;
148
149    /// Creates a [`FnThunk`] implementation from a closure taking the same arguments as this
150    /// function pointer.
151    fn make_thunk<F>(fun: F) -> impl FnThunk<Self>
152    where
153        F: for<'a, 'b, 'c> PackedFn<'a, 'b, 'c, Self>;
154}
155
156/// Trait implemented by (`CC`, [`FnOnce`]) tuples used to generate a bare function thunk template,
157/// where `CC` is a calling convention marker type.
158///
159/// # Safety
160/// This trait is internal to the library and is not meant to be directly implemented by downstream
161/// crates.
162///
163/// # Why implement on tuples?
164/// Implementing on (calling-convention, closure) tuples instead of only the closure is done for two
165/// reasons:
166/// - It allows type-inferring `B` from the calling convention and a closure with annotated
167///   parameters, which is highly desirable for the constructor API of [`BareFn`](crate::BareFn) and
168///   friends.
169/// - The [`bare_hrtb`](crate::bare_hrtb) macro can be used by downstream crates to generate
170///   implementations of this trait for specific higher-ranked bare functions. This is only possible
171///   if a local type is present in both the trait generic parameters and the implementor. By
172///   implementing on tuples, we can thus use a local type for the calling convention.
173pub unsafe trait FnOnceThunk<B: FnPtr>: Sized {
174    /// Type-erased bare function thunk template calling `self` by move. Internal to the library.
175    const THUNK_TEMPLATE_ONCE: *const u8;
176
177    /// Calls the closure making up this [`FnOnceThunk`] by value.
178    ///
179    /// # Safety
180    /// The same function-specific safety invariants must be upheld as when calling the underlying
181    /// closure directly.
182    unsafe fn call_once<'a, 'b, 'c>(self, args: B::Args<'a, 'b, 'c>) -> B::Ret<'a, 'b, 'c>;
183}
184
185/// Trait implemented by (`CC`, [`FnMut`]) tuples used to generate a bare function thunk template,
186/// where `CC` is a calling convention marker type.
187///
188/// We include `CC` in the type parameters even though it can be fetched from `B` has it enables
189/// much richer type inference in the construction API of [`BareFn`](crate::BareFn) and friends.
190///
191/// # Safety
192/// This trait is internal to the library and is not meant to be directly implemented by downstream
193/// crates.
194///
195/// # Why implement on tuples?
196/// Implementing on (calling-convention, closure) tuples instead of only the closure is done for two
197/// reasons:
198/// - It allows type-inferring `B` from the calling convention and a closure with annotated
199///   parameters, which is highly desirable for the constructor API of [`BareFn`](crate::BareFn) and
200///   friends.
201/// - The [`bare_hrtb`](crate::bare_hrtb) macro can be used by downstream crates to generate
202///   implementations of this trait for specific higher-ranked bare functions. This is only possible
203///   if a local type is present in both the trait generic parameters and the implementor. By
204///   implementing on tuples, we can thus use a local type for the calling convention.
205pub unsafe trait FnMutThunk<B: FnPtr>: FnOnceThunk<B> {
206    /// Type-erased bare function thunk template calling `self` by mutable reference. Internal to
207    /// the library.
208    const THUNK_TEMPLATE_MUT: *const u8;
209
210    /// Calls the closure making up this [`FnMutThunk`] by mutable reference.    
211    ///
212    /// # Safety
213    /// The same function-specific safety invariants must be upheld as when calling the underlying
214    /// closure directly.
215    unsafe fn call_mut<'a, 'b, 'c>(&mut self, args: B::Args<'a, 'b, 'c>) -> B::Ret<'a, 'b, 'c>;
216}
217
218/// Trait implemented by (`CC`, [`Fn`]) tuples used to generate a bare function thunk template,
219/// where `CC` is a calling convention marker type.
220///
221/// We include `CC` in the type parameters even though it can be fetched from `B` has it enables
222/// much richer type inference in the construction API of [`BareFn`](crate::BareFn) and friends.
223///
224/// # Safety
225/// This trait is internal to the library and is not meant to be directly implemented by downstream
226/// crates.
227///
228/// # Why implement on tuples?
229/// Implementing on (calling-convention, closure) tuples instead of only the closure is done for two
230/// reasons:
231/// - It allows type-inferring `B` from the calling convention and a closure with annotated
232///   parameters, which is highly desirable for the constructor API of [`BareFn`](crate::BareFn) and
233///   friends.
234/// - The [`bare_hrtb`](crate::bare_hrtb) macro can be used by downstream crates to generate
235///   implementations of this trait for specific higher-ranked bare functions. This is only possible
236///   if a local type is present in both the trait generic parameters and the implementor. By
237///   implementing on tuples, we can thus use a local type for the calling convention.
238pub unsafe trait FnThunk<B: FnPtr>: FnMutThunk<B> {
239    /// Type-erased bare function thunk template calling `self` by immutable reference. Internal to
240    /// the library.
241    const THUNK_TEMPLATE: *const u8;
242
243    /// Calls the closure making up this [`FnThunk`] by value.
244    ///
245    /// # Safety
246    /// The same function-specific safety invariants must be upheld as when calling the underlying
247    /// closure directly.
248    unsafe fn call<'a, 'b, 'c>(&self, args: B::Args<'a, 'b, 'c>) -> B::Ret<'a, 'b, 'c>;
249}
250
251/// Trait alias for [`FnOnce(B::Args<'a, 'b, 'c>) -> B::Ret<'a, 'b, 'c>`](FnOnce).
252///
253/// This is necessary to express the return type of [`FnPtr::make_once_thunk`].
254pub trait PackedFnOnce<'a, 'b, 'c, B: FnPtr>:
255    FnOnce(B::Args<'a, 'b, 'c>) -> B::Ret<'a, 'b, 'c>
256{
257}
258
259impl<'a, 'b, 'c, B: FnPtr, F> PackedFnOnce<'a, 'b, 'c, B> for F where
260    F: FnOnce(B::Args<'a, 'b, 'c>) -> B::Ret<'a, 'b, 'c>
261{
262}
263
264/// Trait alias for [`FnMut(B::Args<'a, 'b, 'c>) -> B::Ret<'a, 'b, 'c>`](FnMut).
265///
266/// This is necessary to express the return type of [`FnPtr::make_mut_thunk`].
267pub trait PackedFnMut<'a, 'b, 'c, B: FnPtr>:
268    FnMut(B::Args<'a, 'b, 'c>) -> B::Ret<'a, 'b, 'c>
269{
270}
271
272impl<'a, 'b, 'c, B: FnPtr, F> PackedFnMut<'a, 'b, 'c, B> for F where
273    F: FnMut(B::Args<'a, 'b, 'c>) -> B::Ret<'a, 'b, 'c>
274{
275}
276
277/// Trait alias for [`Fn(B::Args<'a, 'b, 'c>) -> B::Ret<'a, 'b, 'c>`](Fn).
278///
279/// This is necessary to express the return type of [`FnPtr::make_thunk`].
280pub trait PackedFn<'a, 'b, 'c, B: FnPtr>: Fn(B::Args<'a, 'b, 'c>) -> B::Ret<'a, 'b, 'c> {}
281
282impl<'a, 'b, 'c, B: FnPtr, F> PackedFn<'a, 'b, 'c, B> for F where
283    F: Fn(B::Args<'a, 'b, 'c>) -> B::Ret<'a, 'b, 'c>
284{
285}