closure_ffi/
traits.rs

1//! Traits that `closure-ffi` uses to power its functionality.
2
3use crate::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    /// Calling convention of the bare function, as a ZST marker type.
95    type CC: Default;
96
97    #[cfg(all(not(doc), feature = "tuple_trait"))]
98    /// The arguments of the function, as a tuple.
99    ///
100    /// This is a GAT with 3 independent lifetimes to support most higher-kinded bare functions.
101    type Args<'a, 'b, 'c>: core::marker::Tuple;
102
103    #[cfg(any(doc, not(feature = "tuple_trait")))]
104    #[cfg_attr(docsrs, doc(cfg(all())))]
105    /// The arguments of the function, as a tuple.
106    ///
107    /// This is a GAT with 3 independent lifetimes to support most higher-kinded bare functions.
108    ///
109    /// When the `tuple_trait` crate feature is enabled, this associated type has a
110    /// [`core::marker::Tuple`] bound. Note that this also requires the `tuple_trait` nightly
111    /// feature.
112    type Args<'a, 'b, 'c>;
113
114    /// The return type of the function.
115    ///
116    /// This is a GAT with 3 independent lifetimes to support most higher-kinded bare functions.
117    type Ret<'a, 'b, 'c>;
118
119    /// Calls self.
120    ///
121    /// # Safety
122    /// The same function-specific safety invariants must be upheld as when calling it directly.
123    unsafe fn call<'a, 'b, 'c>(self, args: Self::Args<'a, 'b, 'c>) -> Self::Ret<'a, 'b, 'c>;
124
125    /// Creates `Self` from an untyped pointer.
126    ///
127    /// # Safety
128    /// The untyped pointer must point to a valid instance of `Self`.
129    unsafe fn from_ptr(ptr: *const ()) -> Self;
130
131    /// Casts `self` to an untyped pointer.
132    fn to_ptr(self) -> *const ();
133
134    /// Creates a [`FnOnceThunk`] implementation from a closure taking the same arguments as this
135    /// function pointer.
136    fn make_once_thunk<F>(fun: F) -> impl FnOnceThunk<Self>
137    where
138        F: for<'a, 'b, 'c> PackedFnOnce<'a, 'b, 'c, Self>;
139
140    /// Creates a [`FnMutThunk`] implementation from a closure taking the same arguments as this
141    /// function pointer.
142    fn make_mut_thunk<F>(fun: F) -> impl FnMutThunk<Self>
143    where
144        F: for<'a, 'b, 'c> PackedFnMut<'a, 'b, 'c, Self>;
145
146    /// Creates a [`FnThunk`] implementation from a closure taking the same arguments as this
147    /// function pointer.
148    fn make_thunk<F>(fun: F) -> impl FnThunk<Self>
149    where
150        F: for<'a, 'b, 'c> PackedFn<'a, 'b, 'c, Self>;
151}
152
153/// Trait implemented by (`CC`, [`FnOnce`]) tuples used to generate a bare function thunk template,
154/// where `CC` is a calling convention marker type.
155///
156/// # Safety
157/// This trait is internal to the library and is not meant to be directly implemented by downstream
158/// crates.
159///
160/// # Why implement on tuples?
161/// Implenting on (calling-convention, closure) tuples instead of only the closure is done for two
162/// reasons:
163/// - It allows type-infering `B` from the calling convention and a closure with annotated
164///   parameters, which is highly desirable for the constructor API of [`BareFn`](crate::BareFn) and
165///   friends.
166/// - The [`bare_hrtb`](crate::bare_hrtb) macro can be used by downstream crates to generate
167///   implementations of this trait for specific higher-ranked bare functions. This is only possible
168///   if a local type is present in both the trait generic parameters and the implementor. By
169///   implementing on tuples, we can thus use a local type for the calling convention.
170pub unsafe trait FnOnceThunk<B: FnPtr>: Sized {
171    /// Type-erased bare function thunk template calling `self` by move. Internal to the library.
172    const THUNK_TEMPLATE_ONCE: *const u8;
173
174    /// Calls the closure making up this [`FnOnceThunk`] by value.
175    ///
176    /// # Safety
177    /// The same function-specific safety invariants must be upheld as when calling the underlying
178    /// closure directly.
179    unsafe fn call_once<'a, 'b, 'c>(self, args: B::Args<'a, 'b, 'c>) -> B::Ret<'a, 'b, 'c>;
180}
181
182/// Trait implemented by (`CC`, [`FnMut`]) tuples used to generate a bare function thunk template,
183/// where `CC` is a calling convention marker type.
184///
185/// We include `CC` in the type parameters even though it can be fetched from `B` has it enables
186/// much richer type inference in the construction API of [`BareFn`](crate::BareFn) and friends.
187///
188/// # Safety
189/// This trait is internal to the library and is not meant to be directly implemented by downstream
190/// crates.
191///
192/// # Why implement on tuples?
193/// Implenting on (calling-convention, closure) tuples instead of only the closure is done for two
194/// reasons:
195/// - It allows type-infering `B` from the calling convention and a closure with annotated
196///   parameters, which is highly desirable for the constructor API of [`BareFn`](crate::BareFn) and
197///   friends.
198/// - The [`bare_hrtb`](crate::bare_hrtb) macro can be used by downstream crates to generate
199///   implementations of this trait for specific higher-ranked bare functions. This is only possible
200///   if a local type is present in both the trait generic parameters and the implementor. By
201///   implementing on tuples, we can thus use a local type for the calling convention.
202pub unsafe trait FnMutThunk<B: FnPtr>: FnOnceThunk<B> {
203    /// Type-erased bare function thunk template calling `self` by mutable reference. Internal to
204    /// the library.
205    const THUNK_TEMPLATE_MUT: *const u8;
206
207    /// Calls the closure making up this [`FnMutThunk`] by mutable reference.    
208    ///
209    /// # Safety
210    /// The same function-specific safety invariants must be upheld as when calling the underlying
211    /// closure directly.
212    unsafe fn call_mut<'a, 'b, 'c>(&mut self, args: B::Args<'a, 'b, 'c>) -> B::Ret<'a, 'b, 'c>;
213}
214
215/// Trait implemented by (`CC`, [`Fn`]) tuples used to generate a bare function thunk template,
216/// where `CC` is a calling convention marker type.
217///
218/// We include `CC` in the type parameters even though it can be fetched from `B` has it enables
219/// much richer type inference in the construction API of [`BareFn`](crate::BareFn) and friends.
220///
221/// # Safety
222/// This trait is internal to the library and is not meant to be directly implemented by downstream
223/// crates.
224///
225/// # Why implement on tuples?
226/// Implenting on (calling-convention, closure) tuples instead of only the closure is done for two
227/// reasons:
228/// - It allows type-infering `B` from the calling convention and a closure with annotated
229///   parameters, which is highly desirable for the constructor API of [`BareFn`](crate::BareFn) and
230///   friends.
231/// - The [`bare_hrtb`](crate::bare_hrtb) macro can be used by downstream crates to generate
232///   implementations of this trait for specific higher-ranked bare functions. This is only possible
233///   if a local type is present in both the trait generic parameters and the implementor. By
234///   implementing on tuples, we can thus use a local type for the calling convention.
235pub unsafe trait FnThunk<B: FnPtr>: FnMutThunk<B> {
236    /// Type-erased bare function thunk template calling `self` by immutable reference. Internal to
237    /// the library.
238    const THUNK_TEMPLATE: *const u8;
239
240    /// Calls the closure making up this [`FnThunk`] by value.
241    ///
242    /// # Safety
243    /// The same function-specific safety invariants must be upheld as when calling the underlying
244    /// closure directly.
245    unsafe fn call<'a, 'b, 'c>(&self, args: B::Args<'a, 'b, 'c>) -> B::Ret<'a, 'b, 'c>;
246}
247
248/// Trait alias for [`FnOnce(B::Args<'a, 'b, 'c>) -> B::Ret<'a, 'b, 'c>`](FnOnce).
249///
250/// This is necessary to express the return type of [`FnPtr::make_once_thunk`].
251pub trait PackedFnOnce<'a, 'b, 'c, B: FnPtr>:
252    FnOnce(B::Args<'a, 'b, 'c>) -> B::Ret<'a, 'b, 'c>
253{
254}
255
256impl<'a, 'b, 'c, B: FnPtr, F> PackedFnOnce<'a, 'b, 'c, B> for F where
257    F: FnOnce(B::Args<'a, 'b, 'c>) -> B::Ret<'a, 'b, 'c>
258{
259}
260
261/// Trait alias for [`FnMut(B::Args<'a, 'b, 'c>) -> B::Ret<'a, 'b, 'c>`](FnMut).
262///
263/// This is necessary to express the return type of [`FnPtr::make_mut_thunk`].
264pub trait PackedFnMut<'a, 'b, 'c, B: FnPtr>:
265    FnMut(B::Args<'a, 'b, 'c>) -> B::Ret<'a, 'b, 'c>
266{
267}
268
269impl<'a, 'b, 'c, B: FnPtr, F> PackedFnMut<'a, 'b, 'c, B> for F where
270    F: FnMut(B::Args<'a, 'b, 'c>) -> B::Ret<'a, 'b, 'c>
271{
272}
273
274/// Trait alias for [`Fn(B::Args<'a, 'b, 'c>) -> B::Ret<'a, 'b, 'c>`](Fn).
275///
276/// This is necessary to express the return type of [`FnPtr::make_thunk`].
277pub trait PackedFn<'a, 'b, 'c, B: FnPtr>: Fn(B::Args<'a, 'b, 'c>) -> B::Ret<'a, 'b, 'c> {}
278
279impl<'a, 'b, 'c, B: FnPtr, F> PackedFn<'a, 'b, 'c, B> for F where
280    F: Fn(B::Args<'a, 'b, 'c>) -> B::Ret<'a, 'b, 'c>
281{
282}