wasmtime::component

Macro bindgen

source
bindgen!() { /* proc-macro */ }
Available on crate features runtime and component-model only.
Expand description

Generate bindings for a WIT world.

This macro ingests a WIT world and will generate all the necessary bindings for instantiating components that ascribe to the world. This provides a higher-level representation of working with a component than the raw Instance type which must be manually-type-checked and manually have its imports provided via the Linker type.

§Examples

Examples for this macro can be found in the bindgen_examples module documentation. That module has a submodule-per-example which includes the source code, with WIT, used to generate the structures along with the generated code itself in documentation.

§Debugging and Exploring

If you need to debug the output of bindgen! you can try using the WASMTIME_DEBUG_BINDGEN=1 environment variable. This will write the generated code to a file on disk so rustc can produce better error messages against the actual generated source instead of the macro invocation itself. This additionally can enable opening up the generated code in an editor and exploring it (through an error message).

The generated bindings can additionally be explored with cargo doc to see what’s generated. It’s also recommended to browse the bindgen_examples for example generated structures and example generated code.

§Syntax

This procedural macro accepts a few different syntaxes. The primary purpose of this macro is to locate a WIT package, parse it, and then extract a world from the parsed package. There are then codegen-specific options to the bindings themselves which can additionally be specified.

Usage of this macro looks like:

// Parse the `wit/` folder adjacent to this crate's `Cargo.toml` and look
// for a single `world` in it. There must be exactly one for this to
// succeed.
bindgen!();

// Parse the `wit/` folder adjacent to this crate's `Cargo.toml` and look
// for the world `foo` contained in it.
bindgen!("foo");

// Parse the folder `other/wit/folder` adjacent to `Cargo.toml`.
bindgen!(in "other/wit/folder");
bindgen!("foo" in "other/wit/folder");

// Parse the file `foo.wit` as a single-file WIT package with no
// dependencies.
bindgen!("foo" in "foo.wit");

// Specify a suite of options to the bindings generation, documented below
bindgen!({
    world: "foo",
    path: "other/path/to/wit",
    // ...
});

§Options Reference

This is an example listing of all options that this macro supports along with documentation for each option and example syntax for each option.

bindgen!({
    world: "foo", // not needed if `path` has one `world`

    // same as in `bindgen!(in "other/wit/folder")
    path: "other/wit/folder",

    // Instead of `path` the WIT document can be provided inline if
    // desired.
    inline: "
        package my:inline;

        world foo {
            // ...
        }
    ",

    // Add calls to `tracing::span!` before each import or export is called
    // to log most arguments and return values. By default values
    // containing lists are excluded; enable `verbose_tracing` to include
    // them.
    //
    // This option defaults to `false`.
    tracing: true,

    // Include all arguments and return values in the tracing output,
    // including values containing lists, which may be very large.
    //
    // This option defaults to `false`.
    verbose_tracing: false,

    // Imports will be async functions through #[async_trait] and exports
    // are also invoked as async functions. Requires `Config::async_support`
    // to be `true`.
    //
    // Note that this is only async for the host as the guest will still
    // appear as if it's invoking blocking functions.
    //
    // This option defaults to `false`.
    async: true,

    // Alternative mode of async configuration where this still implies
    // async instantiation happens, for example, but more control is
    // provided over which imports are async and which aren't.
    //
    // Note that in this mode all exports are still async.
    async: {
        // All imports are async except for functions with these names
        except_imports: ["foo", "bar"],

        // All imports are synchronous except for functions with these names
        //
        // Note that this key cannot be specified with `except_imports`,
        // only one or the other is accepted.
        only_imports: ["foo", "bar"],
    },

    // This option is used to indicate whether imports can trap.
    //
    // Imports that may trap have their return types wrapped in
    // `wasmtime::Result<T>` where the `Err` variant indicates that a
    // trap will be raised in the guest.
    //
    // By default imports cannot trap and the return value is the return
    // value from the WIT bindings itself. This value can be set to `true`
    // to indicate that any import can trap. This value can also be set to
    // an array-of-strings to indicate that only a set list of imports
    // can trap.
    trappable_imports: false,             // no imports can trap (default)
    // trappable_imports: true,           // all imports can trap
    // trappable_imports: ["foo", "bar"], // only these can trap

    // This can be used to translate WIT return values of the form
    // `result<T, error-type>` into `Result<T, RustErrorType>` in Rust.
    // Users must define `RustErrorType` and the `Host` trait for the
    // interface which defines `error-type` will have a method
    // called `convert_error_type` which converts `RustErrorType`
    // into `wasmtime::Result<ErrorType>`. This conversion can either
    // return the raw WIT error (`ErrorType` here) or a trap.
    //
    // By default this option is not specified. This option only takes
    // effect when `trappable_imports` is set for some imports.
    trappable_error_type: {
        "wasi:io/streams/stream-error" => RustErrorType,
    },

    // All generated bindgen types are "owned" meaning types like `String`
    // are used instead of `&str`, for example. This is the default and
    // ensures that the same type used in both imports and exports uses the
    // same generated type.
    ownership: Owning,

    // Alternative to `Owning` above where borrowed types attempt to be used
    // instead. The `duplicate_if_necessary` configures whether duplicate
    // Rust types will be generated for the same WIT type if necessary, for
    // example when a type is used both as an import and an export.
    ownership: Borrowing {
        duplicate_if_necessary: true
    },

    // Restrict the code generated to what's needed for the interface
    // imports in the inlined WIT document fragment.
    interfaces: "
        import wasi:cli/command;
    ",

    // Remap imported interfaces or resources to types defined in Rust
    // elsewhere. Using this option will prevent any code from being
    // generated for interfaces mentioned here. Resources named here will
    // not have a type generated to represent the resource.
    //
    // Interfaces mapped with this option should be previously generated
    // with an invocation of this macro. Resources need to be mapped to a
    // Rust type name.
    with: {
        // This can be used to indicate that entire interfaces have
        // bindings generated elsewhere with a path pointing to the
        // bindinges-generated module.
        "wasi:random/random": wasmtime_wasi::bindings::random::random,

        // Similarly entire packages can also be specified.
        "wasi:cli": wasmtime_wasi::bindings::cli,

        // Or, if applicable, entire namespaces can additionally be mapped.
        "wasi": wasmtime_wasi::bindings,

        // Versions are supported if multiple versions are in play:
        "wasi:http/types@0.2.0": wasmtime_wasi_http::bindings::http::types,
        "wasi:http@0.2.0": wasmtime_wasi_http::bindings::http,

        // The `with` key can also be used to specify the `T` used in
        // import bindings of `Resource<T>`. This can be done to configure
        // which typed resource shows up in generated bindings and can be
        // useful when working with the typed methods of `ResourceTable`.
        "wasi:filesystem/types/descriptor": MyDescriptorType,
    },

    // Additional derive attributes to include on generated types (structs or enums).
    //
    // These are deduplicated and attached in a deterministic order.
    additional_derives: [
        Hash,
        serde::Deserialize,
        serde::Serialize,
    ],

    // A list of WIT "features" to enable when parsing the WIT document that
    // this bindgen macro matches. WIT features are all disabled by default
    // and must be opted-in-to if source level features are used.
    //
    // This option defaults to an empty array.
    features: ["foo", "bar", "baz"],

    // An niche configuration option to require that the `T` in `Store<T>`
    // is always `Send` in the generated bindings. Typically not needed
    // but if synchronous bindings depend on asynchronous bindings using
    // the `with` key then this may be required.
    require_store_data_send: false,

    // If the `wasmtime` crate is depended on at a nonstandard location
    // or is renamed then this is the path to the root of the `wasmtime`
    // crate. Much of the generated code needs to refer to `wasmtime` so
    // this should be used if the `wasmtime` name is not wasmtime itself.
    //
    // By default this is `wasmtime`.
    wasmtime_crate: path::to::wasmtime,

    // This is an in-source alternative to using `WASMTIME_DEBUG_BINDGEN`.
    //
    // Note that if this option is specified then the compiler will always
    // recompile your bindings. Cargo records the start time of when rustc
    // is spawned by this will write a file during compilation. To Cargo
    // that looks like a file was modified after `rustc` was spawned,
    // so Cargo will always think your project is "dirty" and thus always
    // recompile it. Recompiling will then overwrite the file again,
    // starting the cycle anew. This is only recommended for debugging.
    //
    // This option defaults to false.
    include_generated_code_from_file: false,
});