Skip to content
This repository was archived by the owner on Sep 8, 2025. It is now read-only.

Commit 30b47e2

Browse files
committed
Document the HasData trait.
1 parent 473a29b commit 30b47e2

1 file changed

Lines changed: 297 additions & 3 deletions

File tree

crates/wasmtime/src/runtime/component/has_data.rs

Lines changed: 297 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,304 @@
1-
/// A
1+
/// A trait used as part of [`bindgen!`] to indicate a `Data<'_>` payload that
2+
/// implements some host bindings traits.
3+
///
4+
/// The purpose of the [`bindgen!`] macro is to define Rust traits that the host
5+
/// can implement to fulfill WIT functions imported from the host into a
6+
/// component. The [`bindgen!`] macro then additionally generates a function
7+
/// which takes a [`Linker`] and an implementation of the traits and fills out
8+
/// the [`Linker`]. This trait, [`HasData`], is used in this process of filling
9+
/// out the [`Linker`] for some WIT interfaces.
10+
///
11+
/// Wasmtime's [`Store<T>`] type is the home for all per-instance state.
12+
/// Notably the `T` here is generic (the Wasmtime library allows any type to be
13+
/// placed here) and it's also instance-specific as a [`Store<T>`] is typically
14+
/// allocated one-per-instance. Implementations of host APIs, however, often
15+
/// want to live in a library and not be tied to any particular `T`. For example
16+
/// Wasmtime provides the `wasmtime-wasi` crates as an implementation of
17+
/// standard WASI APIs as a library, but they don't want to fix a particular `T`
18+
/// in [`Store<T>`] as embedders should be able to fill out their own `T` for
19+
/// their needs. The purpose of this trait is to enable this situation.
20+
///
21+
/// This trait is used in `add_to_linker` functions generated by [`bindgen!`] in
22+
/// conjunction with a function pointer. It looks something along the lines of:
23+
///
24+
/// ```
25+
/// use wasmtime::component::{Linker, HasData};
26+
///
27+
/// // generated by bindgen!
28+
/// trait Host {
29+
/// // ..
30+
/// }
31+
///
32+
/// fn add_to_linker<T, D>(linker: &mut Linker<T>, getter: fn(&mut T) -> D::Data<'_>)
33+
/// where D: HasData,
34+
/// for<'a> D::Data<'a>: Host,
35+
/// {
36+
/// // ...
37+
/// # let _ = (linker, getter);
38+
/// }
39+
/// ```
40+
///
41+
/// Here the `D` type parameter, bounded by [`HasData`], is an used to specify
42+
/// the return type of the `getter` function provided here. The `getter`
43+
/// "projects" from `&mut T` to `D::Data<'_>`, notably enabling it to capture
44+
/// the lifetime of the `&mut T` passed in as well.
45+
///
46+
/// The `Data` associated type here is further bounded in `add_to_linker` above
47+
/// as it must implement the traits generated by [`bindgen!`]. This means that
48+
/// `linker` is filled out with functions that, when called, first `getter` is
49+
/// invoked and then the actual function delegates to the `Host` trait
50+
/// implementation in this case.
51+
///
52+
/// The `D` type parameter here isn't actually a runtime value, nor is it stored
53+
/// anywhere. It's purely used as a means of projecting a "generic associated
54+
/// type", here where `<'a>` is the generic argument, a lifetime. This means
55+
/// that the choice of `D` is disconnected from both `T` and `D::Data<'_>` and
56+
/// can be whatever you like. Sometimes you might need to define an empty struct
57+
/// in your project to use this, but Wasmtime also provides a convenience
58+
/// [`HasSelf`] type to avoid the need for this in some common use cases.
59+
///
60+
/// For example, let's say you wanted to invoke the above `add_to_linker`
61+
/// function where the `T` in [`Store<T>`] directly implements the `Host` trait
62+
/// itself:
63+
///
64+
/// # Example: `Host for T` using `Store<T>`
65+
///
66+
/// ```
67+
/// use wasmtime::component::{Linker, HasSelf};
68+
/// # use wasmtime::component::HasData;
69+
/// #
70+
/// # trait Host { }
71+
/// # impl<T: Host + ?Sized> Host for &mut T {}
72+
/// #
73+
/// # fn add_to_linker<T, D>(linker: &mut Linker<T>, getter: fn(&mut T) -> D::Data<'_>)
74+
/// # where D: HasData,
75+
/// # for<'a> D::Data<'a>: Host,
76+
/// # {
77+
/// # let _ = (linker, getter);
78+
/// # }
79+
///
80+
/// struct MyStoreState { /* ... */ }
81+
///
82+
/// impl Host for MyStoreState {
83+
/// // ..
84+
/// }
85+
///
86+
/// fn fill_out_my_linker(linker: &mut Linker<MyStoreState>) {
87+
/// add_to_linker::<_, HasSelf<_>>(linker, |x| x)
88+
/// }
89+
/// ```
90+
///
91+
/// Here the `add_to_linker` invocation is annotated with `<_, HasSelf<_>>`. The
92+
/// first argument gets inferred to `MyStoreState`, and the second argument gets
93+
/// inferred to `HasSelf<MyStoreState>` This means that the projection function
94+
/// in this case, here the identity `|x| x`, is typed as
95+
/// `fn(&mut MyStoreState) -> &mut MyStoreState`. This is because the `HasData`
96+
/// implementation for `HasSelf<T>` means that we have
97+
/// `type Data<'a> = &'a mut T`.
98+
///
99+
/// # Example: `Host for MyLibraryState` using `Store<T>`
100+
///
101+
/// Let's say though that you instead are writing a library like WASI where you
102+
/// don't know the `T` of [`Store<T>`] ahead of time. In such a case you might
103+
/// hand-write your own `add_to_linker` wrapper that looks like this:
104+
///
105+
/// ```
106+
/// use wasmtime::component::{Linker, HasData};
107+
/// #
108+
/// # trait Host { }
109+
/// # impl<T: Host + ?Sized> Host for &mut T {}
110+
/// #
111+
/// # fn add_to_linker<T, D>(linker: &mut Linker<T>, getter: fn(&mut T) -> D::Data<'_>)
112+
/// # where D: HasData,
113+
/// # for<'a> D::Data<'a>: Host,
114+
/// # {
115+
/// # let _ = (linker, getter);
116+
/// # }
117+
///
118+
/// // publicly exposed per-instance state for your library, users will
119+
/// // construct this and store it within the `T` in `Store<T>`
120+
/// pub struct MyLibraryState { /* ... */ }
121+
///
122+
/// impl Host for MyLibraryState {
123+
/// // ..
124+
/// }
125+
///
126+
/// // hand-written publicly exposed convenience function to add this crate's
127+
/// // component functionality to the provided linker.
128+
/// pub fn add_my_library_to_linker<T>(
129+
/// linker: &mut Linker<T>,
130+
/// f: fn(&mut T) -> &mut MyLibraryState,
131+
/// ) {
132+
/// // invoke the bindgen!-generated `add_to_linker`
133+
/// add_to_linker::<_, MyLibrary>(linker, f);
134+
/// }
135+
///
136+
/// // Note this need not be publicly exposed, it's just a private internal
137+
/// // detail.
138+
/// struct MyLibrary;
139+
///
140+
/// impl HasData for MyLibrary {
141+
/// type Data<'a> = &'a mut MyLibraryState;
142+
/// }
143+
/// ```
144+
///
145+
/// Here the `MyLibrary` type, private to this crate, has a `HasData`
146+
/// implementation which indicates that implementations of the
147+
/// `bindgen!`-generated APIs are done in terms of `MyLibraryState`
148+
/// specifically. The `add_my_library_to_linker` takes an externally-provided
149+
/// `f` closure which projects from `&mut T`, whatever data the store is using,
150+
/// to `MyLibraryState` which must be stored within the store itself.
151+
///
152+
/// # Example: `Host for MyLibraryState<'_>` using `Store<T>`
153+
///
154+
/// Let's say you're like the above scenario where you're writing a library but
155+
/// instead of being able to wrap up all your state for each trait
156+
/// implementation in a structure it's spread across a few structures. These
157+
/// structures may be stored in different locations inside of `Store<T>` which
158+
/// makes it difficult to wrap up in a single type and return that. Here you can
159+
/// make use of "view" types to collect a number of disjoint borrows into one
160+
/// structure:
161+
///
162+
/// ```
163+
/// use wasmtime::component::{Linker, HasData};
164+
/// #
165+
/// # trait Host { }
166+
/// # impl<T: Host + ?Sized> Host for &mut T {}
167+
/// #
168+
/// # fn add_to_linker<T, D>(linker: &mut Linker<T>, getter: fn(&mut T) -> D::Data<'_>)
169+
/// # where D: HasData,
170+
/// # for<'a> D::Data<'a>: Host,
171+
/// # {
172+
/// # let _ = (linker, getter);
173+
/// # }
174+
/// # struct StateA;
175+
/// # struct StateB;
176+
///
177+
/// // Like before, this is publicly exposed, and this is a "bag of pointers" to
178+
/// // all the pieces of state necessary to implement `Host` below.
179+
/// pub struct MyLibraryState<'a> {
180+
/// pub state_a: &'a mut StateA,
181+
/// pub state_b: &'a mut StateB,
182+
/// }
183+
///
184+
/// impl Host for MyLibraryState<'_> {
185+
/// // ..
186+
/// }
187+
///
188+
/// pub fn add_my_library_to_linker<T>(
189+
/// linker: &mut Linker<T>,
190+
/// f: fn(&mut T) -> MyLibraryState<'_>,
191+
/// ) {
192+
/// // invoke the bindgen!-generated `add_to_linker`
193+
/// add_to_linker::<_, MyLibrary>(linker, f);
194+
/// }
195+
///
196+
/// struct MyLibrary;
197+
///
198+
/// impl HasData for MyLibrary {
199+
/// type Data<'a> = MyLibraryState<'a>;
200+
/// }
201+
/// ```
202+
///
203+
/// This is similar to the above example but shows using a lifetime parameter on
204+
/// a structure instead of using a pointer-with-a-lifetime only. Otherwise
205+
/// though this'll end up working out the same way.
206+
///
207+
/// # Example: `Host for U: MyLibrary` using `Store<T>`
208+
///
209+
/// Let's say you're in a situation where you're a library which wants to create
210+
/// a "simpler" trait than the `Host`-generated traits from [`bindgen!`] and
211+
/// then you want to implement `Host` in terms of this trait. This requires a
212+
/// bit more boilerplate as well as a new custom structure, but doing so looks
213+
/// like this:
214+
///
215+
/// ```
216+
/// use wasmtime::component::{Linker, HasData};
217+
/// #
218+
/// # trait Host { }
219+
/// # impl<T: Host + ?Sized> Host for &mut T {}
220+
/// #
221+
/// # fn add_to_linker<T, D>(linker: &mut Linker<T>, getter: fn(&mut T) -> D::Data<'_>)
222+
/// # where D: HasData,
223+
/// # for<'a> D::Data<'a>: Host,
224+
/// # {
225+
/// # let _ = (linker, getter);
226+
/// # }
227+
///
228+
/// // This is your public trait which external users need to implement. This
229+
/// // can encapsulate any "core" functionality needed to implement
230+
/// // bindgen!-generated traits such as `Host` below.
231+
/// pub trait MyLibraryTrait {
232+
/// // ...
233+
/// }
234+
///
235+
/// // You'll need to provide a "forwarding" implementation of this trait from
236+
/// // `&mut T` to `T` to get the below implementation to compile.
237+
/// impl<T: MyLibraryTrait + ?Sized> MyLibraryTrait for &mut T {
238+
/// // ...
239+
/// }
240+
///
241+
/// // This is a bit of a "hack" and an unfortunate workaround, but is currently
242+
/// // used to work within the confines of orphan rules and such. This is
243+
/// // publicly exposed as the function provided below must provide access to
244+
/// // this.
245+
/// pub struct MyLibraryImpl<T>(pub T);
246+
///
247+
/// // Here you'd implement all of `Host` in terms of `MyLibraryTrait`.
248+
/// // Functions with `&mut self` would use `self.0` to access the functionality
249+
/// // in `MyLibraryTrait`.
250+
/// impl<T: MyLibraryTrait> Host for MyLibraryImpl<T> {
251+
/// // ..
252+
/// }
253+
///
254+
/// // optional: this avoids the need for `self.0` accessors in `Host` above,
255+
/// // but this otherwise isn't required.
256+
/// impl<T: MyLibraryTrait> MyLibraryTrait for MyLibraryImpl<T> {
257+
/// // ..
258+
/// }
259+
///
260+
/// // Note the second type parameter on this method, `U`, which is the user's
261+
/// // implementation of `MyLibraryTrait`. Note that this additionally must
262+
/// // be bounded with `'static` here.
263+
/// pub fn add_my_library_to_linker<T, U>(
264+
/// linker: &mut Linker<T>,
265+
/// f: fn(&mut T) -> MyLibraryImpl<&mut U>,
266+
/// )
267+
/// where U: MyLibraryTrait + 'static,
268+
/// {
269+
/// add_to_linker::<_, MyLibrary<U>>(linker, f);
270+
/// }
271+
///
272+
/// // An adjusted definition of `MyLibrary` relative to the previous example,
273+
/// // still private, which hooks up all the types used here.
274+
/// struct MyLibrary<U>(U);
275+
///
276+
/// impl<U: 'static> HasData for MyLibrary<U> {
277+
/// type Data<'a> = MyLibraryImpl<&'a mut U>;
278+
/// }
279+
/// ```
280+
///
281+
/// This iteration of implementing component-interfaces-as-a-library is
282+
/// unfortunately relatively verbose an unintuitive at this time. We're always
283+
/// keen on improving this though, so if you've got ideas of how to improve this
284+
/// please let us know!
285+
///
286+
/// [`bindgen!`]: super::bindgen
287+
/// [`Linker`]: super::Linker
288+
/// [`Store<T>`]: crate::Store
2289
pub trait HasData: 'static {
3-
/// TODO
290+
/// The data associated with this trait implementation, chiefly used as a
291+
/// generic associated type to allow plumbing the `'a` lifetime into the
292+
/// definition here.
293+
///
294+
/// See the trait documentation for more examples.
4295
type Data<'a>;
5296
}
6297

7-
/// TODO
298+
/// A convenience implementation of the [`HasData`] trait when the data
299+
/// associated with an implementation is `&mut T`.
300+
///
301+
/// For more examples on using this see the [`HasData`] trait.
8302
pub struct HasSelf<T: ?Sized>(core::marker::PhantomData<T>);
9303

10304
impl<T: ?Sized + 'static> HasData for HasSelf<T> {

0 commit comments

Comments
 (0)