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 {
            // ...
        }
    ",

    // Further configuration of imported functions. This can be used to add
    // functionality per-function or by default for all imports. Note that
    // exports are also supported via the `exports` key below.
    //
    // Functions in this list are specified as their interface first then
    // the raw wasm name of the function. Interface versions can be
    // optionally omitted and prefixes are also supported to configure
    // entire interfaces at once for example. Only the first matching item
    // in this list is used to configure a function.
    //
    // Configuration for a function is a set of flags which can be added
    // per-function. Each flag's meaning is documented below and the final
    // set of flags for a function are calculated by the first matching
    // rule below unioned with the default flags inferred from the WIT
    // signature itself (unless below configures the `ignore_wit` flag).
    //
    // Specifically the defaults for a normal WIT function are empty,
    // meaning all flags below are disabled. For a WIT `async` function the
    // `async | store` flags are enabled by default, but all others are
    // still disabled.
    //
    // Note that unused keys in this map are a compile-time error. All
    // keys are required to be used and consulted.
    imports: {
        // The `async` flag is used to indicate that a Rust-level `async`
        // function is used on the host. This means that the host is allowed
        // to do async I/O. Note though that to WebAssembly itself the
        // function will still be blocking. This requires
        // `Config::async_support` to be `true` as well.
        "wasi:io/poll/poll": async,

        // The `store` flag means that the host function will have access
        // to the store during its execution. By default host functions take
        // `&mut self` which only has access to the data in question
        // implementing the generated traits from `bindgen!`. This
        // configuration means that in addition to `Self` the entire store
        // will be accessible if necessary.
        //
        // Functions that have access to a `store` are generated in a
        // `HostWithStore` trait. Functions without a `store` are generated
        // in a `Host` trait.
        //
        // > Note: this is not yet implemented for non-async functions. This
        // > will result in bindgen errors right now and is intended to be
        // > implemented in the near future.
        "wasi:clocks/monotonic-clock/now": store,

        // This is an example of combining flags where the `async` and
        // `store` flags are combined. This means that the generated
        // host function is both `async` and additionally has access to
        // the `store`. Note though that this configuration is not necessary
        // as the WIT function is itself already marked as `async`. That
        // means that this is the default already applied meaning that
        // specifying it here would be redundant.
        //
        // "wasi:clocks/monotonic-clock/[async]wait-until": async | store,

        // The `tracing` flag indicates that `tracing!` will be used to log
        // entries and exits into this host API. This can assist with
        // debugging or just generally be used to provide logs for the host.
        //
        // By default values are traced unless they contain lists, but
        // tracing of lists can be enabled with `verbose_tracing` below.
        "my:local/api/foo": tracing,

        // The `verbose_tracing` flag indicates that when combined with
        // `tracing` the values of parameters/results are added to logs.
        // This may include lists which may be very large.
        "my:local/api/other-function": tracing | verbose_tracing,

        // The `trappable` flag indicates that this import is allowed to
        // generate a 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.
        //
        // Note that the `trappable` configuration can be combined with the
        // `trappable_error_type` configuration below to avoid having a
        // host function return `wasmtime::Result<Result<WitOk, WitErr>>`
        // for example and instead return `Result<WitOk, RustErrorType>`.
        "my:local/api/fallible": trappable,

        // The `ignore_wit` flag discards the WIT-level defaults of a
        // function. For example this `async` WIT function will be ignored
        // and a synchronous function will be generated on the host.
        "my:local/api/[async]wait": ignore_wit,

        // The `exact` flag ensures that the filter, here "f", only matches
        // functions exactly. For example "f" here would only refer to
        // `import f: func()` in a world. Without this flag then "f"
        // would also configure any package `f:*/*/*` for example.
        "f": exact,

        // This is used to configure the defaults of all functions if no
        // other key above matches a function. Note that if specific
        // functions mentioned above want these flags too then the flags
        // must be added there too because only one matching rule in this
        // map is used per-function.
        default: async | trappable,
    },

    // Same as `imports` above, but applies to exported functions.
    exports: { /* ... */ },

    // 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::p2::bindings::random::random,

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

        // Or, if applicable, entire namespaces can additionally be mapped.
        "wasi": wasmtime_wasi::p2::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,
    ],

    // 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,
});