Skip to content

Commit 33c3ac7

Browse files
Merge pull request #218 from mkatychev/docs/prereqs-rust
docs: Clarify setup for "Rust Components" tutorial
2 parents c53901b + 9102bc9 commit 33c3ac7

File tree

5 files changed

+98
-79
lines changed

5 files changed

+98
-79
lines changed

component-model/examples/example-host/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ $ cargo run --release -- 1 2 add.wasm
3535
```
3636

3737
> [!NOTE]
38-
> `add.wasm` is available in thsi folder, but can be replaced with your own built WebAssembly component
38+
> `add.wasm` is available in this folder, but can be replaced with your own built WebAssembly component
3939
> at any time (written in any language that supports WebAssembly Components), given that it satisfies
4040
> the `adder` world described above.
4141

component-model/examples/tutorial/adder/src/bindings.rs

+16-11
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
// Generated by `wit-bindgen` 0.36.0. DO NOT EDIT!
1+
// Generated by `wit-bindgen` 0.41.0. DO NOT EDIT!
22
// Options used:
33
// * runtime_path: "wit_bindgen_rt"
44
#[rustfmt::skip]
55
#[allow(dead_code, clippy::all)]
66
pub mod exports {
77
pub mod docs {
88
pub mod adder {
9-
#[allow(dead_code, clippy::all)]
9+
#[allow(dead_code, async_fn_in_trait, unused_imports, clippy::all)]
1010
pub mod add {
1111
#[used]
1212
#[doc(hidden)]
@@ -25,9 +25,10 @@ pub mod exports {
2525
#[doc(hidden)]
2626
macro_rules! __export_docs_adder_add_0_1_0_cabi {
2727
($ty:ident with_types_in $($path_to_types:tt)*) => {
28-
const _ : () = { #[export_name = "docs:adder/[email protected]#add"]
29-
unsafe extern "C" fn export_add(arg0 : i32, arg1 : i32,) -> i32 {
30-
$($path_to_types)*:: _export_add_cabi::<$ty > (arg0, arg1) } };
28+
const _ : () = { #[unsafe (export_name =
29+
"docs:adder/[email protected]#add")] unsafe extern "C" fn export_add(arg0
30+
: i32, arg1 : i32,) -> i32 { unsafe { $($path_to_types)*::
31+
_export_add_cabi::<$ty > (arg0, arg1) } } };
3132
};
3233
}
3334
#[doc(hidden)]
@@ -38,6 +39,7 @@ pub mod exports {
3839
}
3940
#[rustfmt::skip]
4041
mod _rt {
42+
#![allow(dead_code, clippy::all)]
4143
#[cfg(target_arch = "wasm32")]
4244
pub fn run_ctors_once() {
4345
wit_bindgen_rt::run_ctors_once();
@@ -102,8 +104,8 @@ mod _rt {
102104
}
103105
}
104106
}
105-
/// Generates `#[no_mangle]` functions to export the specified type as the
106-
/// root implementation of all generated traits.
107+
/// Generates `#[unsafe(no_mangle)]` functions to export the specified type as
108+
/// the root implementation of all generated traits.
107109
///
108110
/// For more information see the documentation of `wit_bindgen::generate!`.
109111
///
@@ -133,14 +135,17 @@ macro_rules! __export_adder_impl {
133135
#[doc(inline)]
134136
pub(crate) use __export_adder_impl as export;
135137
#[cfg(target_arch = "wasm32")]
136-
#[link_section = "component-type:wit-bindgen:0.36.0:docs:[email protected]:adder:encoded world"]
138+
#[unsafe(
139+
link_section = "component-type:wit-bindgen:0.41.0:docs:[email protected]:adder:encoded world"
140+
)]
137141
#[doc(hidden)]
142+
#[allow(clippy::octal_escapes)]
138143
pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 203] = *b"\
139144
\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07P\x01A\x02\x01A\x02\x01\
140-
B\x02\x01@\x02\x01ay\x01by\0y\x04\0\x03add\x01\0\x04\0\x14docs:adder/[email protected]\x05\
145+
B\x02\x01@\x02\x01xy\x01yy\0y\x04\0\x03add\x01\0\x04\0\x14docs:adder/[email protected]\x05\
141146
\0\x04\0\x16docs:adder/[email protected]\x04\0\x0b\x0b\x01\0\x05adder\x03\0\0\0G\x09pr\
142-
oducers\x01\x0cprocessed-by\x02\x0dwit-component\x070.220.0\x10wit-bindgen-rust\x06\
143-
0.36.0";
147+
oducers\x01\x0cprocessed-by\x02\x0dwit-component\x070.227.1\x10wit-bindgen-rust\x06\
148+
0.41.0";
144149
#[inline(never)]
145150
#[doc(hidden)]
146151
pub fn __link_custom_section_describing_imports() {

component-model/examples/tutorial/adder/src/lib.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
#[allow(warnings)]
22
mod bindings;
33

4+
// The comments that follow the `use` declaration below
5+
// correlate the rust module path segments with their
6+
// `world.wit` counterparts:
47
use bindings::exports::docs::adder::add::Guest;
8+
// <- items bundled with `export` keyword
9+
// <- package namespace
10+
// <- package
11+
// <- interface name
512

613
struct Component;
714

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

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

219219
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).
220220

221-
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.
221+
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.
222222

223223

224224
[docs-wit]: ../design/wit.md
@@ -314,7 +314,7 @@ You should see output like the following:
314314
OK Successfully written string-reverse.wasm.
315315
```
316316

317-
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.
317+
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.
318318

319319
```console
320320
npx jco transpile string-reverse.wasm -o dist/transpiled

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

+72-65
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,99 @@
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).
3+
Rust has first-class support for the component model via the [`cargo-component` tool][cargo-component].
4+
We will be using the `cargo component` subcommand to create WebAssembly components using Rust as
5+
the component's implementation language.
46

5-
`cargo component` is is a `cargo` subcommand for creating WebAssembly components
6-
using Rust as the component's implementation language.
7+
> [!NOTE]
8+
> You can find more details about `cargo-component` on [crates.io](https://crates.io/crates/cargo-component).
79
8-
## 1. Installing `cargo component`
9-
10-
To install `cargo component`, run:
10+
## 1. Setup
1111

12+
Install [`cargo-component`][cargo-component-install]:
1213
```sh
13-
cargo install cargo-component
14+
cargo install --locked cargo-component
1415
```
15-
16-
> You can find more details about `cargo component` in its [crates.io page](https://crates.io/crates/cargo-component).
17-
18-
## 2. Scaffold a Component with `cargo component`
19-
20-
Create a Rust library that implements the `add` function in the [`adder` world][adder-wit].
21-
22-
First scaffold a project:
23-
16+
Install [`wasm-tools`](https://github.com/bytecodealliance/wasm-tools#installation):
2417
```sh
25-
$ cargo component new adder --lib && cd adder
18+
cargo install --locked wasm-tools
19+
```
20+
Install [`wasmtime`](https://github.com/bytecodealliance/wasmtime#installation):
21+
```sh
22+
curl https://wasmtime.dev/install.sh -sSf | bash
2623
```
2724

28-
Note that `cargo component` generates the necessary bindings as a module called `bindings`.
29-
30-
## 3. Add the WIT world the Component will implement
25+
## 2. Scaffolding a Component
3126

32-
Next, update `wit/world.wit` to match the [`adder` world][adder-wit]:
27+
We will create a component in Rust that implements the `add` function exported
28+
by the [`adder` world][docs-adder] world in the `docs:adder`
29+
[package](https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md#package-names).
3330

31+
First, we will create a new WebAssembly component package called `add`:
32+
```sh
33+
cargo component new add --lib && cd add
3434
```
35-
package docs:[email protected];
3635

37-
interface add {
38-
add: func(x: u32, y: u32) -> u32;
39-
}
36+
## 3. Adding the WIT world
4037

41-
world adder {
42-
export add;
43-
}
38+
We now need to change our generated `wit/world.wit` to match `docs:adder`:
39+
```wit
40+
{{#include ../../examples/tutorial/wit/adder/world.wit}}
4441
```
4542

46-
The `component` section of `Cargo.toml` should look like the following:
43+
The `package.metadata.component` section of our `Cargo.toml` should be changed
44+
to the following:
4745

4846
```toml
4947
[package.metadata.component]
5048
package = "docs:adder"
5149
```
5250

53-
## 4. Generate bindings for our component
51+
## 4. Generating bindings
5452

55-
After performing these changes, we can re-generate bindings with `cargo component bindings`:
53+
Now that we've updated our `world.wit` and `Cargo.toml`, we can re-generate
54+
bindings with the command below:
5655

57-
```console
56+
```sh
5857
cargo component bindings
5958
```
6059

61-
`cargo component bindings` will generate bindings for the world specified in a package's `Cargo.toml`. In particular,
62-
`cargo component` will create a `Guest` trait that a component should implement.
60+
`cargo-component` will generate bindings for our
61+
world and create a `Guest` trait that a component should
62+
implement.
6363

64-
## 5. Implement the generated `Guest` trait
64+
## 5. Implementing the `Guest` trait
6565

6666
Implement the `Guest` trait in `src/lib.rs`, using the scaffolded code. Your code should look something like the following:
6767

6868
```rs
69-
#[allow(warnings)]
70-
mod bindings;
71-
72-
use bindings::exports::docs::adder::add::Guest;
73-
74-
struct Component;
75-
76-
impl Guest for Component {
77-
fn add(x: u32, y: u32) -> u32 {
78-
return x + y;
79-
}
80-
}
81-
82-
bindings::export!(Component with_types_in bindings);
69+
{{#include ../../examples/tutorial/adder/src/lib.rs}}
8370
```
8471

85-
## 6. Build the component
72+
## 6. Building a Component
8673

87-
Now, use `cargo component` to build the component, being sure to optimize with a release build.
74+
Now, let's build our component, being sure to optimize with a release build:
8875

89-
```console
76+
```sh
9077
cargo component build --release
9178
```
9279

93-
> **WARNING:** Building with `--release` removes all debug-related information from the resulting .wasm file. When prototyping or testing locally, you might want to avoid `--release` to obtain useful backtraces in case of errors (for example, with `wasmtime::WasmBacktraceDetails::Enable`). Note: the resulting .wasm file will be considerably larger (likely 4MB+).
80+
> [!WARNING]
81+
> Building with `--release` removes all debug-related information from the resulting `.wasm` file.
82+
>
83+
> When prototyping or testing locally, you might want to avoid `--release` to
84+
> obtain useful backtraces in case of errors (for example, with
85+
> [`wasmtime::WasmBacktraceDetails::Enable`](https://docs.rs/wasmtime/latest/wasmtime/enum.WasmBacktraceDetails.html#variant.Enable)).
86+
> Note: the resulting `.wasm` file will be considerably larger (likely 4MB+).
9487
95-
You can use `wasm-tools component wit` to output the WIT package of the component:
88+
You can use `wasm-tools` to output the WIT package of the component:
9689

90+
```sh
91+
wasm-tools component wit target/wasm32-wasip1/release/add.wasm
9792
```
98-
$ wasm-tools component wit target/wasm32-wasip1/release/adder.wasm
93+
94+
The command above should produce the output below:
95+
96+
```wit
9997
package root:component;
10098
10199
world root {
@@ -108,27 +106,31 @@ package docs:[email protected] {
108106
}
109107
```
110108

111-
### Running a Component from Rust Applications
109+
110+
### Running a Component
112111

113112
To verify that our component works, lets run it from a Rust application that knows how to run a
114-
component targeting the [`adder` world][adder-wit].
113+
component targeting the [`adder` world](#adding-the-wit-world).
115114

116115
The application uses [`wasmtime`](https://github.com/bytecodealliance/wasmtime) crates to generate
117116
Rust bindings, bring in WASI worlds, and execute the component.
118117

119-
```sh
118+
```console
120119
$ cd examples/example-host
121120
$ cargo run --release -- 1 2 ../add/target/wasm32-wasip1/release/adder.wasm
122121
1 + 2 = 3
123122
```
124123

125-
## Importing an interface with `cargo component`
124+
## Importing an interface
126125

127-
The world file (`wit/world.wit`) generated for you by `cargo component new --lib` doesn't specify any imports.
126+
The world file (`wit/world.wit`) we generated doesn't specify any imports.
127+
If your component consumes other components, you can edit the `world.wit` file to import their interfaces.
128128

129-
> `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.
129+
> [!NOTE]
130+
> This section is about importing custom WIT interfaces from library components.
131+
> By default, `cargo-component` imports any required [WASI interfaces](https://wasi.dev/interfaces)
132+
> for us without needing to explicitly declare them.
130133
131-
If your component consumes other components, you can edit the `world.wit` file to import their interfaces.
132134

133135
For example, suppose you have created and built an adder component as explained in the [exporting an interface section](#exporting-an-interface-with-cargo-component) and want to use that component in a calculator component. Here is a partial example world for a calculator that imports the add interface:
134136

@@ -157,7 +159,10 @@ Because the `docs:adder` package is in a different project, we must first tell `
157159
"docs:adder" = { path = "../adder/wit" } # directory containing the WIT package
158160
```
159161

160-
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.
162+
> [!NOTE]
163+
> The path for `docs:adder` is relative to the `wit` _directory_, not to the `world.wit` file.
164+
>
165+
> A WIT package may be spread across multiple files in the same directory; `cargo component` will search them all.
161166
162167
### Calling the import from Rust
163168

@@ -283,7 +288,7 @@ As mentioned above, `cargo component build` doesn't generate a WIT file for a co
283288
284289
6. Run the composed component:
285290
286-
```sh
291+
```console
287292
$ wasmtime run ./my-composed-command.wasm
288293
1 + 1 = 579 # might need to go back and do some work on the calculator implementation
289294
```
@@ -551,4 +556,6 @@ If you are hosting a Wasm runtime, you can export a resource from your host for
551556
}
552557
```
553558

554-
[adder-wit]: https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/tutorial/wit/adder/world.wit
559+
[cargo-component]: https://github.com/bytecodealliance/cargo-component
560+
[cargo-component-install]: https://github.com/bytecodealliance/cargo-component#install
561+
[docs-adder]: https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/tutorial/wit/adder/world.wit

0 commit comments

Comments
 (0)