Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 31 additions & 2 deletions docs/examples-rust-wasi.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,22 @@ WebAssembly module.
[`wasmtime-wasi`]: https://crates.io/crates/wasmtime-wasi
[`Linker`]: https://docs.rs/wasmtime/*/wasmtime/struct.Linker.html

## Wasm Source code
### WebAssembly module source code

For this WASI example, this Hello World program is compiled to a WebAssembly module using the WASI Preview 1 API.

`wasi.rs`
```rust
{{#include ../examples/wasi/wasm/wasi.rs}}
```

## `wasi.rs`
Building this program generates `target/wasm32-wasi/debug/wasi.wasm`, used below.

### Invoke the WASM module

This example shows adding and configuring the WASI imports to invoke the above WASM module.

`main.rs`
```rust,ignore
{{#include ../examples/wasi/main.rs}}
```
Expand Down Expand Up @@ -70,3 +78,24 @@ fn main() -> Result<()> {
Ok(())
}
```

## WASI Preview 2

An experimental implementation of the WASI Preview 2 API is also available, along with an adapter layer for WASI Preview 1 WebAssembly modules. In future this `preview2` API will become the default. There are some features which are currently only accessible through the `preview2` API such as async support and overriding the clock and random implementations.

### Async example

This [async example code][code2] shows how to use the [wasmtime-wasi::preview2][`preview2`] module to
execute the same WASI Preview 1 WebAssembly module from the example above. This example requires the `wasmtime` crate `async` feature to be enabled.

This does not require any change to the WebAssembly module, it's just the WASI API host functions which are implemented to be async. See [wasmtime async support](https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.async_support).

[code2]: https://github.com/bytecodealliance/wasmtime/blob/main/examples/wasi-async/main.rs
[`preview2`]: https://docs.rs/wasmtime-wasi/latest/wasmtime_wasi/preview2/index.html

```rust,ignore
{{#include ../examples/wasi-async/main.rs}}
```

You can also [browse this source code online][code2] and clone the wasmtime
repository to run the example locally.
83 changes: 83 additions & 0 deletions examples/wasi-async/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
//! Example of instantiating a wasm module which uses WASI preview1 imports
//! implemented through the async preview2 WASI implementation.

/*
You can execute this example with:
cmake examples/
cargo run --example wasi-async
*/

use anyhow::Result;
use wasmtime::{Config, Engine, Linker, Module, Store};
use wasmtime_wasi::preview2;

struct WasiHostCtx {
preview2_ctx: preview2::WasiCtx,
preview2_table: wasmtime::component::ResourceTable,
preview1_adapter: preview2::preview1::WasiPreview1Adapter,
}

impl preview2::WasiView for WasiHostCtx {
fn table(&self) -> &wasmtime::component::ResourceTable {
&self.preview2_table
}

fn table_mut(&mut self) -> &mut wasmtime::component::ResourceTable {
&mut self.preview2_table
}

fn ctx(&self) -> &preview2::WasiCtx {
&self.preview2_ctx
}

fn ctx_mut(&mut self) -> &mut preview2::WasiCtx {
&mut self.preview2_ctx
}
}

impl preview2::preview1::WasiPreview1View for WasiHostCtx {
fn adapter(&self) -> &preview2::preview1::WasiPreview1Adapter {
&self.preview1_adapter
}

fn adapter_mut(&mut self) -> &mut preview2::preview1::WasiPreview1Adapter {
&mut self.preview1_adapter
}
}

#[tokio::main]
async fn main() -> Result<()> {
// Construct the wasm engine with async support enabled.
let mut config = Config::new();
config.async_support(true);
let engine = Engine::new(&config)?;

// Add the WASI preview1 API to the linker (will be implemented in terms of
// the preview2 API)
let mut linker: Linker<WasiHostCtx> = Linker::new(&engine);
preview2::preview1::add_to_linker_async(&mut linker)?;

// Add capabilities (e.g. filesystem access) to the WASI preview2 context here.
let wasi_ctx = preview2::WasiCtxBuilder::new().inherit_stdio().build();

let host_ctx = WasiHostCtx {
preview2_ctx: wasi_ctx,
preview2_table: preview2::ResourceTable::new(),
preview1_adapter: preview2::preview1::WasiPreview1Adapter::new(),
};
let mut store: Store<WasiHostCtx> = Store::new(&engine, host_ctx);

// Instantiate our 'Hello World' wasm module.
// Note: This is a module built against the preview1 WASI API.
let module = Module::from_file(&engine, "target/wasm32-wasi/debug/wasi.wasm")?;
let func = linker
.module_async(&mut store, "", &module)
.await?
.get_default(&mut store, "")?
.typed::<(), ()>(&store)?;

// Invoke the WASI program default function.
func.call_async(&mut store, ()).await?;

Ok(())
}