Skip to content

Commit 2e207e4

Browse files
committed
initial prereqs commit
1 parent bdaab9b commit 2e207e4

File tree

2 files changed

+86
-44
lines changed

2 files changed

+86
-44
lines changed

component-model/src/language-support/javascript.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ With `jco transpile` any WebAssembly binary (compiled from any language) can be
216216

217217
Reactor components are WebAssembly components that are long running and meant to be called repeatedly over time. They're analogous to libraries of functionality rather than an executable (a "command" component).
218218

219-
Components expose their interfaces via [WebAssembly Interface Types][docs-wit], hand-in-hand with the [Component Model][docs-component-model] which enables components to use higher level types interchangably.
219+
Components expose their interfaces via [WebAssembly Interface Types][docs-wit], hand-in-hand with the [Component Model][docs-component-model] which enables components to use higher level types interchangeably.
220220

221221

222222
[docs-wit]: ../design/wit.md
@@ -312,7 +312,7 @@ You should see output like the following:
312312
OK Successfully written string-reverse.wasm.
313313
```
314314

315-
Now that we have a WebAssembly binary, we can *also* use `jco` to run it in a native JavaScript context by *transpiling* the WebAsssembly binary (which could have come from anywhere!) to a JavaScript module.
315+
Now that we have a WebAssembly binary, we can *also* use `jco` to run it in a native JavaScript context by *transpiling* the WebAssembly binary (which could have come from anywhere!) to a JavaScript module.
316316

317317
```console
318318
npx jco transpile string-reverse.wasm -o dist/transpiled

component-model/src/language-support/rust.md

+84-42
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,106 @@
11
# Components in Rust
22

3-
Rust has first-class support for the component model via [the `cargo component` tool](https://github.com/bytecodealliance/cargo-component). It is a `cargo` subcommand for
4-
creating WebAssembly components using Rust as the component's implementation language.
3+
Rust has first-class support for the component model via the [`cargo-component`
4+
tool](https://github.com/bytecodealliance/cargo-component). We will be using
5+
the `cargo component` subcommand to create WebAssembly components using Rust as
6+
the component's implementation language.
57

6-
## Installing `cargo component`
8+
> [!NOTE]
9+
> You can find more details about `cargo-component` on [crates.io](https://crates.io/crates/cargo-component).
710
8-
To install `cargo component`, run:
11+
## Prerequisites
912

13+
Install [`cargo-component`](https://github.com/bytecodealliance/cargo-component#installation):
1014
```sh
11-
cargo install cargo-component
15+
cargo install --locked cargo-component
16+
```
17+
Install [`wasm-tools`](https://github.com/bytecodealliance/wasm-tools#installation):
18+
```sh
19+
cargo install --locked wasm-tools
20+
```
21+
Install [`wasmtime`](https://github.com/bytecodealliance/wasmtime#installation):
22+
```sh
23+
curl https://wasmtime.dev/install.sh -sSf | bash
24+
```
25+
Clone the [component-docs](https://github.com/bytecodealliance/component-docs) repo:
26+
```sh
27+
git clone https://github.com/bytecodealliance/component-docs
1228
```
13-
14-
> You can find more details about `cargo component` in its [crates.io page](https://crates.io/crates/cargo-component).
1529

1630
## Building a Component with `cargo component`
1731

18-
Create a Rust library that implements the `add` function in the [`example`
19-
world](https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/example-host/add.wit). First scaffold a project:
32+
We will create a component in Rust that implements the `add` function exported
33+
by the [`example:component/example`][example-component] world in the
34+
`example:component`
35+
[package](https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md#package-names).
2036

37+
First `cd` into the `tutorial` directory found in the repo we just cloned:
38+
```sh
39+
cd component-docs/component-model/examples/tutorial
40+
```
41+
42+
Now create a new WebAssembly component package called `add`:
2143
```sh
2244
$ cargo component new add --lib && cd add
2345
```
2446

25-
Note that `cargo component` generates the necessary bindings as a module called `bindings`.
47+
> [!NOTE]
48+
> `cargo-component` generates the necessary bindings for us in a module called `bindings` found in `src/bindings.rs`.
49+
50+
Next change our generated `wit/world.wit` to match `example:component`:
51+
```wit
52+
{{#include ../../examples/example-host/add.wit}}
53+
```
2654

27-
Next, update `wit/world.wit` to match `add.wit` and modify the component package reference to change the
28-
package name to `example:component`. The `component` section of `Cargo.toml` should look like the following:
55+
Since our WIT file changed names (from `component:add` to
56+
`example:component`) this needs to be reflected in our `Cargo.toml`,
57+
let's change the `package.metadata.component.package` string to `"example:component"`:
2958

3059
```toml
3160
[package.metadata.component]
3261
package = "example:component"
3362
```
3463

35-
`cargo component` will generate bindings for the world specified in a package's `Cargo.toml`. In particular, it will create a `Guest` trait that a component should implement. Since our `example` world has no interfaces, the trait lives directly under the bindings module. Implement the `Guest` trait in `add/src/lib.rs` such that it satisfies the `example` world, adding an `add` function:
64+
`cargo component` will generate bindings for the
65+
`example:component/example` world we specified `Cargo.toml`, it will also
66+
create a `Guest` trait that a component can implement.
67+
Since our `example:component/example` world has no interfaces, our
68+
generated `Guest` trait lives at the top of the `bindings` module.
69+
70+
Implementing the `Guest` trait for our `Component` struct requires us
71+
to match the structure specified by `example:component/example`, we do this by
72+
implementing the `add` method with the equivalent function signature. Our
73+
`src/lib.rs` should look similar to the following:
3674

3775
```rs
76+
mod bindings;
77+
3878
struct Component;
3979

4080
impl Guest for Component {
4181
fn add(x: i32, y: i32) -> i32 {
4282
x + y
4383
}
4484
}
85+
86+
bindings::export!(Component with_types_in bindings);
4587
```
4688

47-
Now, use `cargo component` to build the component, being sure to optimize with a release build.
89+
Now, let's build our component with release optimizations:
4890

4991
```sh
50-
$ cargo component build --release
92+
cargo component build --release
5193
```
5294

53-
You can use `wasm-tools component wit` to output the WIT package of the component:
95+
You can use `wasm-tools` to inspect the WIT package generated by `cargo-component`:
5496

5597
```sh
56-
$ wasm-tools component wit target/wasm32-wasip1/release/add.wasm
98+
wasm-tools component wit target/wasm32-wasip1/release/add.wasm
99+
```
100+
101+
The command above should produce the output below:
102+
103+
```wit
57104
package root:component;
58105
59106
world root {
@@ -64,7 +111,7 @@ world root {
64111
### Running a Component from Rust Applications
65112

66113
To verify that our component works, lets run it from a Rust application that knows how to run a
67-
component targeting the [`example` world](https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/example-host/add.wit).
114+
component targeting the [`example:component/example` world](#example-component).
68115

69116
The application uses [`wasmtime`](https://github.com/bytecodealliance/wasmtime) crates to generate
70117
Rust bindings, bring in WASI worlds, and execute the component.
@@ -77,41 +124,30 @@ $ cargo run --release -- 1 2 ../add/target/wasm32-wasip1/release/add.wasm
77124

78125
## Exporting an interface with `cargo component`
79126

80-
The [sample `add.wit` file](https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/example-host/add.wit) exports a function. However, you'll often prefer to export an interface, either to comply with an existing specification or to capture a set of functions and types that tend to go together. For example, to implement the following world:
127+
Notice how our `example` world currently exports `add` as a function. It's
128+
often preferable to export an interface rather than a function, either to
129+
comply with an existing specification or to capture several functions and types
130+
at once.
131+
For example, to implement the [`docs:adder/adder`][docs-adder] world:
81132

82133
```wit
83-
package docs:[email protected];
84-
85-
interface add {
86-
add: func(a: u32, b: u32) -> u32;
87-
}
88-
89-
world adder {
90-
export add;
91-
}
134+
{{#include ../../examples/tutorial/wit/adder/world.wit}}
92135
```
93136

94137
you would write the following Rust code:
95138

96139
```rust
97-
mod bindings;
98-
// Separating out the interface puts it in a sub-module
99-
use bindings::exports::docs::adder::add::Guest;
100-
101-
struct Component;
102-
103-
impl Guest for Component {
104-
fn add(a: u32, b: u32) -> u32 {
105-
a + b
106-
}
107-
}
140+
{{#include ../../examples/tutorial/adder/src/lib.rs}}
108141
```
109142

110143
## Importing an interface with `cargo component`
111144

112145
The world file (`wit/world.wit`) generated for you by `cargo component new --lib` doesn't specify any imports.
113146

114-
> `cargo component build`, by default, uses the Rust `wasm32-wasi` target, and therefore automatically imports any required WASI interfaces - no action is needed from you to import these. This section is about importing custom WIT interfaces from library components.
147+
> [!NOTE]
148+
> This section is about importing custom WIT interfaces from library components.
149+
> By default, `cargo component build` imports any required [WASI interfaces](https://wasi.dev/interfaces)
150+
> for us without needing to explicitly declare them.
115151
116152
If your component consumes other components, you can edit the `world.wit` file to import their interfaces.
117153

@@ -139,10 +175,13 @@ Because the `docs:adder` package is in a different project, we must first tell `
139175

140176
```toml
141177
[package.metadata.component.target.dependencies]
142-
"docs:adder" = { path = "../adder/wit" } # directory containing the WIT package
178+
"docs:adder" = { path = "../wit/adder" } # directory containing the WIT package
143179
```
144180

145-
Note that the path is to the adder project's WIT _directory_, not to the `world.wit` file. A WIT package may be spread across multiple files in the same directory; `cargo component` will look at all the files.
181+
> [!NOTE]
182+
> The path for `docs:adder` is relative to the `wit` _directory_, not to the `world.wit` file.
183+
>
184+
> A WIT package may be spread across multiple files in the same directory; `cargo component` will search them all.
146185
147186
### Calling the import from Rust
148187

@@ -534,3 +573,6 @@ If you are hosting a Wasm runtime, you can export a resource from your host for
534573
// etc.
535574
}
536575
```
576+
577+
[example-component]: https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/example-host/add.wit
578+
[docs-adder]: https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/tutorial/wit/adder/world.wit

0 commit comments

Comments
 (0)