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}