Skip to content

Commit 7fd75d1

Browse files
Merge pull request #192 from vados-cosmonic/fix=use-adder-interface-for-host
fix: use adder interface for host
2 parents 24d7eb9 + 980c0f7 commit 7fd75d1

File tree

23 files changed

+815
-320
lines changed

23 files changed

+815
-320
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ This repository also makes use of mdBook plugins. To install mdBook and the plug
1515
```console
1616
cargo install --version 0.4.21 mdbook
1717
cargo install --version 0.6.7 mdbook-alerts
18+
cargo install --version 0.7.7 mdbook-linkcheck
1819
```
1920

2021
[cargo]: https://doc.rust-lang.org/cargo

component-model/book.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ edit-url-template = "https://github.com/bytecodealliance/component-docs/tree/mai
1111
additional-css = ["theme/head.hbs"]
1212

1313
[preprocessor.alerts]
14+
15+
[output.linkcheck]

component-model/examples/example-host/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22
name = "example-host"
33
version = "0.1.0"
44
edition = "2021"
5+
description = """
6+
Example Rust-based WebAssembly host that executes WebAssembly components
7+
"""
58

69
[dependencies]
10+
anyhow = "1.0.72"
711
async-std = { version = "1.13", features = ["attributes"] }
812
clap = { version = "4", features = ["derive"] }
913
wasmtime = "27.0"
1014
wasmtime-wasi = "27.0"
11-
anyhow = "1.0.72"
Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,47 @@
11
# Rust Host Application for Example Components
22

3-
This is a native Rust CLI application that can run components of the following
4-
`example` world, which simply defines an add function that takes in two
5-
parameters.
3+
This is a native Rust CLI application that can run [WebAssembly Components][wasm-components] of the `adder` world,
4+
defined in [`examples/tutorial/wit/adder/world.wit`][adder-wit], using [WebAssembly Interface Types ("WIT")][wit].
5+
6+
The `adder` world exports an interface called `add` which defines an function that takes two unsigned and adds them:
67

78
```wit
8-
package example:component;
9+
package docs:[email protected];
10+
11+
interface add {
12+
add: func(x: u32, y: u32) -> u32;
13+
}
914
10-
world example {
11-
export add: func(x: s32, y: s32) -> s32;
15+
world adder {
16+
export add;
1217
}
1318
```
1419

15-
The application uses [`wasmtime`](https://github.com/bytecodealliance/wasmtime)
16-
crates to generate Rust bindings, bring in WASI worlds, and executes the `add`
17-
function of the component.
20+
The application uses WebAssembly ecosystem crates (e.g. [`wasmtime`][wasmtime]) to generate Rust bindings, instantiate WASI worlds, and
21+
executes the exported `add` function (`docs:adder/add.add`) of a provided component.
22+
23+
This host binary takes in two unsigned 32bit integers (`u32`) operands and a path to a component. This host then:
1824

19-
It takes in two operands and a path to a component. It passes the operands to
20-
the component and prints the result generated by the component.
25+
1. Loads the component from the given path
26+
2. Instantiates it as an implementer of the `adder` world
27+
3. Executes the `add` function exported by the component
28+
4. Prints the result
2129

22-
```sh
30+
If running with [`cargo`][cargo] (part of the [Rust toolchain][rust-toolchain]), then you should see output like the following:
31+
32+
```
2333
$ cargo run --release -- 1 2 add.wasm
2434
1 + 2 = 3
2535
```
36+
37+
> [!NOTE]
38+
> `add.wasm` is available in thsi folder, but can be replaced with your own built WebAssembly component
39+
> at any time (written in any language that supports WebAssembly Components), given that it satisfies
40+
> the `adder` world described above.
41+
42+
[wasmtime]: https://github.com/bytecodealliance/wasmtime
43+
[wasm-components]: https://component-model.bytecodealliance.org/design/components.html
44+
[adder-wit]: https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/tutorial/wit/adder/world.wit
45+
[wit]: https://component-model.bytecodealliance.org/design/wit.html
46+
[cargo]: https://doc.rust-lang.org/cargo/
47+
[rust-toolchain]: https://www.rust-lang.org/tools/install

component-model/examples/example-host/add.wit

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,61 @@
1-
use anyhow::Context;
21
use std::path::PathBuf;
3-
use wasmtime::component::*;
2+
3+
use anyhow::Context;
4+
use wasmtime::component::{Component, Linker};
45
use wasmtime::{Config, Engine, Store};
6+
57
use crate::state::States;
68

7-
bindgen!({
8-
path: "add.wit",
9-
world: "example",
10-
async: true
11-
});
9+
mod bindings {
10+
//! Generated code for the
11+
wasmtime::component::bindgen!({
12+
path: "../tutorial/wit/adder/world.wit",
13+
world: "adder",
14+
async: true
15+
});
16+
}
1217

13-
pub async fn add(path: PathBuf, x: i32, y: i32) -> wasmtime::Result<i32> {
18+
/// Perform the add operation for a given WebAssembly component
19+
///
20+
/// This operation asynchronously (as opposed to synchronously
21+
/// without an async runtime like `tokio` or `async-std`).
22+
///
23+
/// # Arguments
24+
///
25+
/// * `path` - Path to the Wasm component bytes
26+
/// * `x` - The left hand side of the addition
27+
/// * `y` - The right hand side of the addition
28+
///
29+
pub async fn add(path: PathBuf, x: u32, y: u32) -> wasmtime::Result<u32> {
1430
// Construct engine
1531
let mut config = Config::default();
1632
config.async_support(true);
1733
let engine = Engine::new(&config)?;
34+
1835
// Construct component
1936
let component = Component::from_file(&engine, path).context("Component file not found")?;
37+
2038
// Construct store for storing running states of the component
2139
let wasi_view = States::new();
2240
let mut store = Store::new(&engine, wasi_view);
41+
2342
// Construct linker for linking interfaces.
24-
// For this simple adder component, no need to manually link additional interfaces.
2543
let mut linker = Linker::new(&engine);
26-
// Add wasi exports to linker to support io interfaces
44+
45+
// Add wasi exports to linker to support I/O (as in `wasi:io`) interfaces
46+
// see: https://github.com/WebAssembly/wasi-io
2747
wasmtime_wasi::add_to_linker_async(&mut linker)?;
28-
let instance = Example::instantiate_async(&mut store, &component, &linker)
48+
49+
// Instantiate the component as an instance of the `adder` world,
50+
// with the generated bindings
51+
let instance = bindings::Adder::instantiate_async(&mut store, &component, &linker)
2952
.await
3053
.context("Failed to instantiate the example world")?;
54+
55+
// Call the add function on instance
3156
instance
57+
.docs_adder_add()
3258
.call_add(&mut store, x, y)
3359
.await
34-
.context("Failed to call add function")
35-
}
60+
.context("calling add function")
61+
}

component-model/examples/example-host/src/main.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
mod async_add;
2-
mod sync_add;
3-
mod state;
4-
51
use clap::Parser;
62
use std::path::PathBuf;
73

4+
mod async_add;
5+
mod state;
6+
mod sync_add;
7+
88
/// A CLI for executing WebAssembly components that
99
/// implement the `example` world.
1010
#[derive(Parser)]
1111
#[clap(name = "add-host", version = env!("CARGO_PKG_VERSION"))]
1212
struct AddApp {
1313
/// The first operand
14-
x: i32,
14+
x: u32,
1515
/// The second operand
16-
y: i32,
16+
y: u32,
1717
/// The path to the component.
1818
#[clap(value_name = "COMPONENT_PATH")]
1919
component: PathBuf,

component-model/examples/example-host/src/state.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ impl WasiView for States {
2222
fn ctx(&mut self) -> &mut WasiCtx {
2323
&mut self.ctx
2424
}
25-
}
25+
}
Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,57 @@
1-
use crate::state::States;
2-
use anyhow::Context;
31
use std::path::PathBuf;
4-
use wasmtime::component::{bindgen, Component, Linker};
2+
3+
use anyhow::Context;
4+
use wasmtime::component::{Component, Linker};
55
use wasmtime::{Engine, Store};
66
use wasmtime_wasi;
77

8-
bindgen!({
9-
path: "add.wit",
10-
world: "example",
11-
async: false
12-
});
8+
use crate::state::States;
9+
10+
mod bindings {
11+
wasmtime::component::bindgen!({
12+
path: "../tutorial/wit/adder/world.wit",
13+
world: "adder",
14+
async: false
15+
});
16+
}
1317

14-
pub fn add(path: PathBuf, x: i32, y: i32) -> wasmtime::Result<i32> {
18+
/// Perform a add operation for a given WebAssembly component
19+
///
20+
/// This operation happens synchronously (as opposed to asynchronously
21+
/// powered by an async runtime like `tokio` or `async-std`).
22+
///
23+
/// # Arguments
24+
///
25+
/// * `path` - Path to the Wasm component bytes
26+
/// * `x` - The left hand side of the addition
27+
/// * `y` - The right hand side of the addition
28+
///
29+
pub fn add(path: PathBuf, x: u32, y: u32) -> wasmtime::Result<u32> {
1530
// Construct engine
1631
let engine = Engine::default();
32+
1733
// Construct component
1834
let component = Component::from_file(&engine, path).context("Component file not found")?;
35+
1936
// Construct store for storing running states of the component
2037
let wasi_view = States::new();
2138
let mut store = Store::new(&engine, wasi_view);
39+
2240
// Construct linker for linking interfaces.
23-
// For this simple adder component, no need to manually link additional interfaces.
2441
let mut linker = Linker::new(&engine);
25-
// Add wasi exports to linker to support io interfaces
42+
43+
// Add wasi exports to linker to support I/O (as in `wasi:io`) interfaces
44+
// see: https://github.com/WebAssembly/wasi-io
2645
wasmtime_wasi::add_to_linker_sync(&mut linker).expect("Could not add wasi to linker");
27-
let instance = Example::instantiate(&mut store, &component, &linker)
46+
47+
// Instantiate the component as an instance of the `adder` world,
48+
// with the generated bindings
49+
let instance = bindings::Adder::instantiate(&mut store, &component, &linker)
2850
.context("Failed to instantiate the example world")?;
51+
52+
// Call the add function on instance
2953
instance
54+
.docs_adder_add()
3055
.call_add(&mut store, x, y)
31-
.context("Failed to call add function")
32-
}
56+
.context("calling add function")
57+
}

component-model/examples/tutorial/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ package docs:[email protected];
1010
1111
1212
interface add {
13-
add: func(a: u32, b: u32) -> u32;
13+
add: func(x: u32, y: u32) -> u32;
1414
}
1515
1616
world adder {

0 commit comments

Comments
 (0)