Trait HasData

pub trait HasData: 'static {
    type Data<'a>;
}
Expand description

A trait used as part of bindgen! to indicate a Data<'_> payload that implements some host bindings traits.

The purpose of the bindgen! macro is to define Rust traits that the host can implement to fulfill WIT functions imported from the host into a component. The bindgen! macro then additionally generates a function which takes a Linker and an implementation of the traits and fills out the Linker. This trait, HasData, is used in this process of filling out the Linker for some WIT interfaces.

Wasmtime’s Store<T> type is the home for all per-instance state. Notably the T here is generic (the Wasmtime library allows any type to be placed here) and it’s also instance-specific as a Store<T> is typically allocated one-per-instance. Implementations of host APIs, however, often want to live in a library and not be tied to any particular T. For example Wasmtime provides the wasmtime-wasi crates as an implementation of standard WASI APIs as a library, but they don’t want to fix a particular T in Store<T> as embedders should be able to fill out their own T for their needs. The purpose of this trait is to enable this situation.

This trait is used in add_to_linker functions generated by bindgen! in conjunction with a function pointer. It looks something along the lines of:

use wasmtime::component::{Linker, HasData};

// generated by bindgen!
trait Host {
    // ..
}

fn add_to_linker<T, D>(linker: &mut Linker<T>, getter: fn(&mut T) -> D::Data<'_>)
    where D: HasData,
          for<'a> D::Data<'a>: Host,
{
    // ...
}

Here the D type parameter, bounded by HasData, is used to specify the return type of the getter function provided here. The getter “projects” from &mut T to D::Data<'_>, notably enabling it to capture the lifetime of the &mut T passed in as well.

The Data associated type here is further bounded in add_to_linker above as it must implement the traits generated by bindgen!. This means that linker is filled out with functions that, when called, first getter is invoked and then the actual function delegates to the Host trait implementation in this case.

The D type parameter here isn’t actually a runtime value, nor is it stored anywhere. It’s purely used as a means of projecting a “generic associated type”, here where <'a> is the generic argument, a lifetime. This means that the choice of D is disconnected from both T and D::Data<'_> and can be whatever you like. Sometimes you might need to define an empty struct in your project to use this, but Wasmtime also provides a convenience HasSelf type to avoid the need for this in some common use cases.

§Example: Host for T using Store<T>

Let’s say you wanted to invoke the above add_to_linker function where the T in Store<T> directly implements the Host trait itself:

use wasmtime::component::{Linker, HasSelf};

struct MyStoreState { /* ... */ }

impl Host for MyStoreState {
    // ..
}

fn fill_out_my_linker(linker: &mut Linker<MyStoreState>) {
    add_to_linker::<_, HasSelf<_>>(linker, |x| x)
}

Here the add_to_linker invocation is annotated with <_, HasSelf<_>>. The first argument gets inferred to MyStoreState, and the second argument gets inferred to HasSelf<MyStoreState> This means that the projection function in this case, here the identity |x| x, is typed as fn(&mut MyStoreState) -> &mut MyStoreState. This is because the HasData implementation for HasSelf<T> means that we have type Data<'a> = &'a mut T.

§Example: Host for MyLibraryState using Store<T>

Let’s say though that you instead are writing a library like WASI where you don’t know the T of Store<T> ahead of time. In such a case you might hand-write your own add_to_linker wrapper that looks like this:

use wasmtime::component::{Linker, HasData};

// publicly exposed per-instance state for your library, users will
// construct this and store it within the `T` in `Store<T>`
pub struct MyLibraryState { /* ... */ }

impl Host for MyLibraryState {
    // ..
}

// hand-written publicly exposed convenience function to add this crate's
// component functionality to the provided linker.
pub fn add_my_library_to_linker<T>(
    linker: &mut Linker<T>,
    f: fn(&mut T) -> &mut MyLibraryState,
) {
    // invoke the bindgen!-generated `add_to_linker`
    add_to_linker::<_, MyLibrary>(linker, f);
}

// Note this need not be publicly exposed, it's just a private internal
// detail.
struct MyLibrary;

impl HasData for MyLibrary {
    type Data<'a> = &'a mut MyLibraryState;
}

Here the MyLibrary type, private to this crate, has a HasData implementation which indicates that implementations of the bindgen!-generated APIs are done in terms of MyLibraryState specifically. The add_my_library_to_linker takes an externally-provided f closure which projects from &mut T, whatever data the store is using, to MyLibraryState which must be stored within the store itself.

§Example: Host for MyLibraryState<'_> using Store<T>

Let’s say you’re like the above scenario where you’re writing a library but instead of being able to wrap up all your state for each trait implementation in a structure it’s spread across a few structures. These structures may be stored in different locations inside of Store<T> which makes it difficult to wrap up in a single type and return that. Here you can make use of “view” types to collect a number of disjoint borrows into one structure:

use wasmtime::component::{Linker, HasData};

// Like before, this is publicly exposed, and this is a "bag of pointers" to
// all the pieces of state necessary to implement `Host` below.
pub struct MyLibraryState<'a> {
    pub state_a: &'a mut StateA,
    pub state_b: &'a mut StateB,
}

impl Host for MyLibraryState<'_> {
    // ..
}

pub fn add_my_library_to_linker<T>(
    linker: &mut Linker<T>,
    f: fn(&mut T) -> MyLibraryState<'_>,
) {
    // invoke the bindgen!-generated `add_to_linker`
    add_to_linker::<_, MyLibrary>(linker, f);
}

struct MyLibrary;

impl HasData for MyLibrary {
    type Data<'a> = MyLibraryState<'a>;
}

This is similar to the above example but shows using a lifetime parameter on a structure instead of using a pointer-with-a-lifetime only. Otherwise though this’ll end up working out the same way.

§Example: Host for U: MyLibrary using Store<T>

Let’s say you’re in a situation where you’re a library which wants to create a “simpler” trait than the Host-generated traits from bindgen! and then you want to implement Host in terms of this trait. This requires a bit more boilerplate as well as a new custom structure, but doing so looks like this:

use wasmtime::component::{Linker, HasData};

// This is your public trait which external users need to implement. This
// can encapsulate any "core" functionality needed to implement
// bindgen!-generated traits such as `Host` below.
pub trait MyLibraryTrait {
    // ...
}

// You'll need to provide a "forwarding" implementation of this trait from
// `&mut T` to `T` to get the below implementation to compile.
impl<T: MyLibraryTrait + ?Sized> MyLibraryTrait for &mut T {
    // ...
}

// This is a bit of a "hack" and an unfortunate workaround, but is currently
// used to work within the confines of orphan rules and such. This is
// publicly exposed as the function provided below must provide access to
// this.
pub struct MyLibraryImpl<T>(pub T);

// Here you'd implement all of `Host` in terms of `MyLibraryTrait`.
// Functions with `&mut self` would use `self.0` to access the functionality
// in `MyLibraryTrait`.
impl<T: MyLibraryTrait> Host for MyLibraryImpl<T> {
    // ..
}

// optional: this avoids the need for `self.0` accessors in `Host` above,
// but this otherwise isn't required.
impl<T: MyLibraryTrait> MyLibraryTrait for MyLibraryImpl<T> {
    // ..
}

// Note the second type parameter on this method, `U`, which is the user's
// implementation of `MyLibraryTrait`. Note that this additionally must
// be bounded with `'static` here.
pub fn add_my_library_to_linker<T, U>(
    linker: &mut Linker<T>,
    f: fn(&mut T) -> MyLibraryImpl<&mut U>,
)
    where U: MyLibraryTrait + 'static,
{
    add_to_linker::<_, MyLibrary<U>>(linker, f);
}

// An adjusted definition of `MyLibrary` relative to the previous example,
// still private, which hooks up all the types used here.
struct MyLibrary<U>(U);

impl<U: 'static> HasData for MyLibrary<U> {
    type Data<'a> = MyLibraryImpl<&'a mut U>;
}

This iteration of implementing component-interfaces-as-a-library is unfortunately relatively verbose and unintuitive at this time. We’re always keen on improving this though, so if you’ve got ideas of how to improve this please let us know!

Required Associated Types§

type Data<'a>

The data associated with this trait implementation, chiefly used as a generic associated type to allow plumbing the 'a lifetime into the definition here.

See the trait documentation for more examples.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§

§

impl<T> HasData for HasSelf<T>
where T: 'static + ?Sized,

§

type Data<'a> = &'a mut T