wasmtime/runtime/component/
get_host.rs

1/// An "alias trait" used for [`bindgen!`](super::bindgen)-generated
2/// `add_to_linker_get_host`-style functions.
3///
4/// This trait is used as a trait bound for closures that "project" from a
5/// store's `&mut T` internals to `U` where `U` is allowed to close over the
6/// lifetime of `&mut T`. This is a somewhat tricky operation to write down in a
7/// trait bound which requires a somewhat special definition of this trait.
8///
9/// This trait has a supertrait of `Fn(T) -> U` where `U` here is specified as
10/// an associated type `Host` for this trait. There is then additionally a
11/// blanket implementation for all `Fn(T) -> U` closures as well meaning no
12/// embedders should need to implement this trait manually.
13///
14/// Note that this trait additionally requires that closures are `Send + Sync +
15/// Copy + 'static` which means they effectively need to behave like function
16/// pointers.
17///
18/// Also note that using this trait requires type-annotations at this time.
19/// Refer to the example below for more information.
20///
21/// # Examples
22///
23/// Embedders should generally not need to write `GetHost` bounds themselves but
24/// they will need to interact with functions that have a parameter bounded by
25/// `GetHost` generated by [`bindgen!`](super::bindgen).
26///
27/// ```
28/// use wasmtime::component::{Linker, GetHost};
29///
30/// // generated by `bindgen!`
31/// trait Host { /* ... */ }
32/// // generated by `bindgen!`
33/// impl<'a, T: ?Sized + Host> Host for &'a mut T { /* ... */ }
34///
35/// // generated by `bindgen!`
36/// fn add_to_linker_get_host<T, G>(linker: &mut Linker<T>, get_host: G)
37///     where G: for<'a> GetHost<&'a mut T, Host: Host>,
38/// {
39///     // ...
40/// # let _ = (linker, get_host);
41/// }
42///
43/// // In some cases you'll implement `Host` for the `T` in the store directly.
44/// struct MyType;
45///
46/// impl Host for MyType {
47///     // ...
48/// }
49///
50/// fn my_add_to_linker(linker: &mut Linker<MyType>) {
51///     let get_host = type_annotate(|x| x);
52///     add_to_linker_get_host(linker, get_host);
53///
54///     // Type annotating a closure is not the most intuitive thing to do in
55///     // Rust, but that's all this function is doing. This is taking a `F`
56///     // and then simply returning it, but the purpose of this function is to
57///     // synthetically place a bound on `F` here with a `where` clause. This
58///     // `where` clause is what annotates the type of `F` manually and is how
59///     // we accurately describe the lifetimes associated with this closure.
60///     fn type_annotate<F>(f: F) -> F
61///         where F: Fn(&mut MyType) -> &mut MyType
62///     {
63///         f
64///     }
65/// }
66///
67/// // In other cases you might store the structure implementing `Host`
68/// // elsewhere in the store
69/// struct MyContainerType {
70///     the_impl: MyType,
71/// }
72///
73/// fn my_add_to_linker_with_container(linker: &mut Linker<MyContainerType>) {
74///     let get_host = type_annotate(|x| &mut x.the_impl);
75///     add_to_linker_get_host(linker, get_host);
76///
77///     fn type_annotate<F>(f: F) -> F
78///         where F: Fn(&mut MyContainerType) -> &mut MyType
79///     {
80///         f
81///     }
82/// }
83///
84/// // And in some cases you might want to combine pieces of state within a `T`
85/// // of a `Store` into one type that implements this state. This is, for
86/// // example, how WASI impls work in Wasmtime.
87/// struct MyStoreState {
88///     the_table: MyTable,
89///     the_impl: MyType,
90/// }
91///
92/// struct MyTable { /* ... */ }
93///
94/// struct MyBorrowedState<'a> {
95///     the_table: &'a mut MyTable,
96///     the_impl: &'a mut MyType,
97/// }
98///
99/// impl Host for MyBorrowedState<'_> {
100///     // ...
101/// }
102///
103/// fn my_add_to_linker_with_more_lifetimes(linker: &mut Linker<MyStoreState>) {
104///     let get_host = type_annotate(|x| MyBorrowedState {
105///         the_table: &mut x.the_table,
106///         the_impl: &mut x.the_impl,
107///     });
108///     add_to_linker_get_host(linker, get_host);
109///
110///     fn type_annotate<F>(f: F) -> F
111///         where F: Fn(&mut MyStoreState) -> MyBorrowedState<'_>
112///     {
113///         f
114///     }
115/// }
116/// ```
117///
118/// # Too Much Detail
119///
120/// The general idea behind this trait is that it expresses the ability to take
121/// a closure as a parameter which projects from a store's state, `T`, to a `U`
122/// which implements the bindgen-generated traits. The actual operation is
123/// provided a `&'a mut T` at runtime and `U` must then also be able to close over
124/// the `'a` too.
125///
126/// This is surprisingly subtle to do in Rust and there are many variations of
127/// writing this down which don't achieve the desired result. For example the
128/// most naive way to possibly write this does not work.
129///
130/// ```compile_fail
131/// use wasmtime::component::Linker;
132///
133/// # trait Host { /* ... */ }
134/// # impl<'a, T: ?Sized + Host> Host for &'a mut T { /* ... */ }
135/// // Naively let's just take `F: FnMut...`
136/// fn add_to_linker_get_host<F, T, U>(linker: &mut Linker<T>, get_host: F)
137///     where F: FnMut(&mut T) -> U,
138/// {
139///     // ...
140/// # let _ = (linker, get_host);
141/// }
142///
143/// struct MyStoreType { the_impl: MyType, }
144/// struct MyType { /* ... */ }
145/// impl Host for MyType { /* ... */ }
146///
147/// fn my_add_to_linker(linker: &mut Linker<MyType>) {
148///     let get_host = type_annotate(|x| x);
149///     add_to_linker_get_host(linker, get_host);
150///     //~^ ERROR: one type is more general than the other
151///
152///     fn type_annotate<F>(f: F) -> F
153///         where F: Fn(&mut MyType) -> &mut MyType
154///     {
155///         f
156///     }
157/// }
158/// ```
159///
160/// The problem with this version is that the exact definition of the trait
161/// bound is: `where F: for<'a> FnMut(&'a mut T) -> U`, and `U` doesn't have
162/// access to the lifetime `'a` that's only defined under the trait bound of `F`
163/// itself. So this doesn't work but how about lifting the lifetime up?
164///
165/// ```compile_fail
166/// use wasmtime::component::Linker;
167///
168/// # trait Host { /* ... */ }
169/// # impl<'a, T: ?Sized + Host> Host for &'a mut T { /* ... */ }
170/// fn add_to_linker_get_host<'a, F, T: 'a, U>(linker: &mut Linker<T>, get_host: F)
171///     where F: FnMut(&'a mut T) -> U + Send + Sync + 'static,
172/// {
173///     linker.root().func_wrap("f", move |mut store, ()| {
174///         let mut data = store.data_mut();
175///         let the_u = get_host(&mut data);
176///         //~^ ERROR: borrowed data escapes outside of closure
177///         Ok(())
178///     });
179/// }
180/// ```
181///
182/// The problem with this invocation is the meaning is still wrong. While the
183/// above example will compile with `'a` defined here the actual usage of
184/// `get_host` doesn't work. The root of the issue is that the lifetime can't
185/// actually be named when `add_to_linker_get_host` is called, instead it *must*
186/// be part of the `for<'a>` part.
187///
188/// Rust doesn't have higher-ranked definitions such as `for<'a, U> Fn(&'a mut
189/// T) -> U` where `U` would have access to the `'a` lifetime here, meaning that
190/// at this point we've exhausted the various possibilities of using `Fn` trait
191/// bounds directly. They all mean subtly different things than the original
192/// problem we're trying to solve here.
193///
194/// This trait definition exists to accurately express in the trait system what
195/// we're trying to solve which is that the return value of a closure is allowed
196/// to close over its arguments. This is achieved where the trait here is
197/// defined with just `T`, notably not `&'a mut T`, meaning that whatever is in
198/// scope for `T` is also in-scope for the returned value from the closure.
199/// Usage of this trait then looks like `G: for<'a> GetHost<&'a mut T>` meaning
200/// that the `G::Host` associated type has access to `'a`.
201///
202/// This then gives rise to the second issue of this trait which is actually
203/// defining a closure that implements this trait. Ideally what we want to write
204/// is something that looks like this:
205///
206/// ```ignore
207/// # struct MyStoreType { the_impl: MyType, }
208/// # struct MyType { /* ... */ }
209/// let my_closure = for<'a> |x: &'a mut MyStoreType| -> &'a mut MyType {
210///     &mut x.the_impl
211/// };
212/// ```
213///
214/// This syntax technically compiles but [is
215/// unstable](https://github.com/rust-lang/rust/issues/97362). Alternatively one
216/// might want to write:
217///
218/// ```ignore
219/// # struct MyStoreType { the_impl: MyType, }
220/// # struct MyType { /* ... */ }
221/// let my_closure: impl FnMut(&mut MyStoreType) -> &mut MyType = |x| {
222///     &mut x.the_impl
223/// };
224/// ```
225///
226/// but this syntax is [also
227/// unstable](https://github.com/rust-lang/rust/issues/63065). Thus what we're
228/// left with is the sort of kludge workaround in the examples above:
229///
230/// ```
231/// # struct MyStoreType { the_impl: MyType, }
232/// # struct MyType { /* ... */ }
233/// let my_closure = type_annotate(|x| &mut x.the_impl);
234///
235/// fn type_annotate<F>(f: F) -> F
236///     where F: Fn(&mut MyStoreType) -> &mut MyType
237/// {
238///     f
239/// }
240/// ```
241///
242/// Our hope is that this can get more ergonomic over time, but this is
243/// hopefully at least illuminating how we have ended up here.
244pub trait GetHost<T>: Fn(T) -> <Self as GetHost<T>>::Host + Send + Sync + Copy + 'static {
245    /// The type that this accessor returns. Notably this has access to the
246    /// lifetimes of `T`.
247    type Host;
248}
249
250impl<F, T, U> GetHost<T> for F
251where
252    F: Fn(T) -> U + Send + Sync + Copy + 'static,
253{
254    type Host = U;
255}