luoluoyuyu opened issue #12558:
Description
I am building a plugin system where the Guest components are compiled using TinyGo. Since TinyGo's runtime initialization relies heavily on WASI P2, my custom world must include
include wasi:cli/imports@0.2.0;. Otherwise, the TinyGo component fails to initialize.However, the current developer experience for this specific (and very common) use case is quite painful. Even with the
withmapping in thebindgen!macro and implementingWasiViewfor myHostState, I am still forced to manually implement all the generated traits forwasi:*interfaces just to "delegate" them back to thewasmtime-wasiimplementation.The Problem
If I have a minimalist WIT like this:
package test:pkg@0.1.0; interface data { resource store { constructor(name: string); } } world processor { // Required for TinyGo support include wasi:cli/imports@0.2.0; import data; export process: func(data: list<u8>) -> result<_, string>; }Even though
wasmtime-wasialready provides a complete implementation for every WASI interface included above, I find myself writing dozens of lines of repetitive boilerplate just to bridge the gap in Rust:// This feels like unnecessary boilerplate impl test::pkg::processor::wasi::cli::stdout::Host for MyHost { fn get_stdout(&mut self) -> anyhow::Result<Resource<OutputStream>> { // I have to manually call the provided implementation wasmtime_wasi::bindings::cli::stdout::Host::get_stdout(self) } } // ... and so on for every other WASI interface TinyGo needs (clocks, streams, etc.)Is there a more "automated" way to handle this? That is, when the Host has already provided WasiCtx and ResourceTable, bindgen! or Linker should be able to automatically identify and fulfill the requirements of these standard WASI imports without the developer having to write a large amount of repetitive boilerplate code.
luoluoyuyu edited issue #12558:
Description
I am building a plugin system where the Guest components are compiled using TinyGo. Since TinyGo's runtime initialization relies heavily on WASI P2, my custom world must include
include wasi:cli/imports@0.2.0;. Otherwise, the TinyGo component fails to initialize.However, the current developer experience for this specific (and very common) use case is quite painful. Even with the
withmapping in thebindgen!macro and implementingWasiViewfor myHostState, I am still forced to manually implement all the generated traits forwasi:*interfaces just to "delegate" them back to thewasmtime-wasiimplementation.The Problem
If I have a WIT like this:
package test:pkg@0.1.0; interface data { resource store { constructor(name: string); } } world processor { // Required for TinyGo support include wasi:cli/imports@0.2.0; import data; export process: func(data: list<u8>) -> result<_, string>; }Even though
wasmtime-wasialready provides a complete implementation for every WASI interface included above, I find myself writing dozens of lines of repetitive boilerplate just to bridge the gap in Rust:// This feels like unnecessary boilerplate impl test::pkg::processor::wasi::cli::stdout::Host for MyHost { fn get_stdout(&mut self) -> anyhow::Result<Resource<OutputStream>> { // I have to manually call the provided implementation wasmtime_wasi::bindings::cli::stdout::Host::get_stdout(self) } } // ... and so on for every other WASI interface TinyGo needs (clocks, streams, etc.)Is there a more "automated" way to handle this? That is, when the Host has already provided WasiCtx and ResourceTable, bindgen! or Linker should be able to automatically identify and fulfill the requirements of these standard WASI imports without the developer having to write a large amount of repetitive boilerplate code.
alexcrichton commented on issue #12558:
What I'd recommend here is to have a
worldthat focuses on just your embedding, for example thedatainterface import and theprocessexport. Wasmtime bindings would be generated using thatworld, and then there'd be a second world whichincludes this world and also has the WASI imports. This second world would be used for guest bindings generation, for example.This is also something we could improve in Wasmtime by souping up the
withoption, but that can get a bit gnarly sometimes. Would theworldsplit work for your use case?
luoluoyuyu commented on issue #12558:
What I'd recommend here is to have a
worldthat focuses on just your embedding, for example thedatainterface import and theprocessexport. Wasmtime bindings would be generated using thatworld, and then there'd be a second world whichincludes this world and also has the WASI imports. This second world would be used for guest bindings generation, for example.This is also something we could improve in Wasmtime by souping up the
withoption, but that can get a bit gnarly sometimes. Would theworldsplit work for your use case?Thank you for your answer, this solution can solve my problem very well.
luoluoyuyu closed issue #12558:
Description
I am building a plugin system where the Guest components are compiled using TinyGo. Since TinyGo's runtime initialization relies heavily on WASI P2, my custom world must include
include wasi:cli/imports@0.2.0;. Otherwise, the TinyGo component fails to initialize.However, the current developer experience for this specific (and very common) use case is quite painful. Even with the
withmapping in thebindgen!macro and implementingWasiViewfor myHostState, I am still forced to manually implement all the generated traits forwasi:*interfaces just to "delegate" them back to thewasmtime-wasiimplementation.The Problem
If I have a WIT like this:
package test:pkg@0.1.0; interface data { resource store { constructor(name: string); } } world processor { // Required for TinyGo support include wasi:cli/imports@0.2.0; import data; export process: func(data: list<u8>) -> result<_, string>; }Even though
wasmtime-wasialready provides a complete implementation for every WASI interface included above, I find myself writing dozens of lines of repetitive boilerplate just to bridge the gap in Rust:// This feels like unnecessary boilerplate impl test::pkg::processor::wasi::cli::stdout::Host for MyHost { fn get_stdout(&mut self) -> anyhow::Result<Resource<OutputStream>> { // I have to manually call the provided implementation wasmtime_wasi::bindings::cli::stdout::Host::get_stdout(self) } } // ... and so on for every other WASI interface TinyGo needs (clocks, streams, etc.)Is there a more "automated" way to handle this? That is, when the Host has already provided WasiCtx and ResourceTable, bindgen! or Linker should be able to automatically identify and fulfill the requirements of these standard WASI imports without the developer having to write a large amount of repetitive boilerplate code.
Last updated: Feb 24 2026 at 04:36 UTC