From eb15c5eb8b17b3ed042a1c25ea87656ff35f4043 Mon Sep 17 00:00:00 2001 From: Victor Adossi Date: Tue, 25 Mar 2025 01:00:30 +0900 Subject: [PATCH 1/5] fix(lang/rust): link to old WIT, prose & interface use example Signed-off-by: Victor Adossi --- component-model/src/language-support/rust.md | 54 ++++++++++++++++---- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/component-model/src/language-support/rust.md b/component-model/src/language-support/rust.md index 28b87dea..b822d8de 100644 --- a/component-model/src/language-support/rust.md +++ b/component-model/src/language-support/rust.md @@ -17,19 +17,19 @@ cargo install cargo-component ## 2. Scaffold a Component with `cargo component` -Create a Rust library that implements the `add` function in the [`adder`world][adder-wit]. +Create a Rust library that implements the `add` function in the [`adder` world][adder-wit]. First scaffold a project: ```sh -$ cargo component new add --lib && cd add +$ cargo component new adder --lib && cd adder ``` Note that `cargo component` generates the necessary bindings as a module called `bindings`. ## 3. Add the WIT world the Component will implement -Next, update `wit/world.wit` to match `add.wit`: +Next, update `wit/world.wit` to match the [`adder` world][adder-wit]: ``` package docs:adder@0.1.0; @@ -124,13 +124,24 @@ $ cargo run --release -- 1 2 ../add/target/wasm32-wasip1/release/add.wasm ## Exporting an interface with `cargo component` -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: +While it is possible to export a raw function, prefer exporting an interface, similar to the [sample `adder` world][add-wit]. +This often makes it easier to comply with an existing specification or to capture a set of functions and types +that tend to go together. + +For example, consider the following changes to the `add` interface in the `adder` world: ```wit package docs:adder@0.1.0; + interface add { - add: func(x: u32, y: u32) -> u32; + variant operand { + unsigned32(u32) + signed32(s32) + zero, + } + + add: func(x: operand, y: operand) -> result; } world adder { @@ -138,23 +149,46 @@ world adder { } ``` -you would write the following Rust code: +This would be implemented with the following Rust code: ```rust +#[allow(warnings)] mod bindings; -// Separating out the interface puts it in a sub-module -use bindings::exports::docs::adder::add::Guest; +use bindings::exports::docs::adder::add::{Guest, Operand}; struct Component; impl Guest for Component { - fn add(x: u32, y: u32) -> u32 { - x + y + fn add(x: Operand, y: Operand) -> Result { + let x = convert_operand(x); + let y = convert_operand(y); + match x + y { + v if v == 0 => Ok(Operand::Zero), + v if v < 0 => i32::try_from(v) + .map_err(|e| format!("unexpectedly invalid u32: {e}")) + .map(Operand::Signed32), + v => u32::try_from(v) + .map_err(|e| format!("unexpectedly invalid u32: {e}")) + .map(Operand::Unsigned32), + } + } +} + +fn convert_operand(operand: Operand) -> i64 { + match operand { + Operand::Unsigned32(v) => v as i64, + Operand::Signed32(v) => v as i64, + Operand::Zero => 0, } } + +bindings::export!(Component with_types_in bindings); ``` +While the code above is unlikely to appear in real interfaces, but it shows the more common case of an interface +including types that are meant to be used *with* the interface in question. + ## Importing an interface with `cargo component` The world file (`wit/world.wit`) generated for you by `cargo component new --lib` doesn't specify any imports. From ec6b327c3ca539dc1cf4ef8a324defb460bcaf0d Mon Sep 17 00:00:00 2001 From: Victor Adossi <123968127+vados-cosmonic@users.noreply.github.com> Date: Tue, 25 Mar 2025 13:10:47 +0900 Subject: [PATCH 2/5] fix(lang/rust): prose Co-authored-by: Kate Goldenring --- component-model/src/language-support/rust.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/component-model/src/language-support/rust.md b/component-model/src/language-support/rust.md index b822d8de..70ab3e29 100644 --- a/component-model/src/language-support/rust.md +++ b/component-model/src/language-support/rust.md @@ -186,7 +186,7 @@ fn convert_operand(operand: Operand) -> i64 { bindings::export!(Component with_types_in bindings); ``` -While the code above is unlikely to appear in real interfaces, but it shows the more common case of an interface +The code above is unlikely to appear in real interfaces; however, it shows the more common case of an interface including types that are meant to be used *with* the interface in question. ## Importing an interface with `cargo component` From 266e9f371cf8bc0944a9eaad9b7ea7fc456dd231 Mon Sep 17 00:00:00 2001 From: Victor Adossi <123968127+vados-cosmonic@users.noreply.github.com> Date: Tue, 25 Mar 2025 13:10:57 +0900 Subject: [PATCH 3/5] fix(lang/rust): prose Co-authored-by: Kate Goldenring --- component-model/src/language-support/rust.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/component-model/src/language-support/rust.md b/component-model/src/language-support/rust.md index 70ab3e29..a7bbda0a 100644 --- a/component-model/src/language-support/rust.md +++ b/component-model/src/language-support/rust.md @@ -124,7 +124,7 @@ $ cargo run --release -- 1 2 ../add/target/wasm32-wasip1/release/add.wasm ## Exporting an interface with `cargo component` -While it is possible to export a raw function, prefer exporting an interface, similar to the [sample `adder` world][add-wit]. +While it is possible to export a raw function, it is a best practice to export an interface, similar to the [sample `adder` world][add-wit]. This often makes it easier to comply with an existing specification or to capture a set of functions and types that tend to go together. From 803be65b9b7d978fc5be9044cf76d7b0c0afe50e Mon Sep 17 00:00:00 2001 From: Victor Adossi Date: Thu, 27 Mar 2025 22:42:31 +0900 Subject: [PATCH 4/5] fix(lang/rust): remove more advanced interface example Signed-off-by: Victor Adossi --- component-model/src/language-support/rust.md | 67 -------------------- 1 file changed, 67 deletions(-) diff --git a/component-model/src/language-support/rust.md b/component-model/src/language-support/rust.md index a7bbda0a..b3b03b14 100644 --- a/component-model/src/language-support/rust.md +++ b/component-model/src/language-support/rust.md @@ -122,73 +122,6 @@ $ cargo run --release -- 1 2 ../add/target/wasm32-wasip1/release/add.wasm 1 + 2 = 3 ``` -## Exporting an interface with `cargo component` - -While it is possible to export a raw function, it is a best practice to export an interface, similar to the [sample `adder` world][add-wit]. -This often makes it easier to comply with an existing specification or to capture a set of functions and types -that tend to go together. - -For example, consider the following changes to the `add` interface in the `adder` world: - -```wit -package docs:adder@0.1.0; - - -interface add { - variant operand { - unsigned32(u32) - signed32(s32) - zero, - } - - add: func(x: operand, y: operand) -> result; -} - -world adder { - export add; -} -``` - -This would be implemented with the following Rust code: - -```rust -#[allow(warnings)] -mod bindings; - -use bindings::exports::docs::adder::add::{Guest, Operand}; - -struct Component; - -impl Guest for Component { - fn add(x: Operand, y: Operand) -> Result { - let x = convert_operand(x); - let y = convert_operand(y); - match x + y { - v if v == 0 => Ok(Operand::Zero), - v if v < 0 => i32::try_from(v) - .map_err(|e| format!("unexpectedly invalid u32: {e}")) - .map(Operand::Signed32), - v => u32::try_from(v) - .map_err(|e| format!("unexpectedly invalid u32: {e}")) - .map(Operand::Unsigned32), - } - } -} - -fn convert_operand(operand: Operand) -> i64 { - match operand { - Operand::Unsigned32(v) => v as i64, - Operand::Signed32(v) => v as i64, - Operand::Zero => 0, - } -} - -bindings::export!(Component with_types_in bindings); -``` - -The code above is unlikely to appear in real interfaces; however, it shows the more common case of an interface -including types that are meant to be used *with* the interface in question. - ## Importing an interface with `cargo component` The world file (`wit/world.wit`) generated for you by `cargo component new --lib` doesn't specify any imports. From 534c3ea504d2898e590f08bc6e1b8fc98bd69db9 Mon Sep 17 00:00:00 2001 From: Victor Adossi Date: Thu, 27 Mar 2025 22:44:32 +0900 Subject: [PATCH 5/5] fix(lang/rust): naming of adder.wasm Signed-off-by: Victor Adossi --- component-model/src/language-support/rust.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/component-model/src/language-support/rust.md b/component-model/src/language-support/rust.md index b3b03b14..fbe6947a 100644 --- a/component-model/src/language-support/rust.md +++ b/component-model/src/language-support/rust.md @@ -95,7 +95,7 @@ cargo component build --release You can use `wasm-tools component wit` to output the WIT package of the component: ``` -$ wasm-tools component wit target/wasm32-wasip1/release/add.wasm +$ wasm-tools component wit target/wasm32-wasip1/release/adder.wasm package root:component; world root { @@ -118,7 +118,7 @@ Rust bindings, bring in WASI worlds, and execute the component. ```sh $ cd examples/example-host -$ cargo run --release -- 1 2 ../add/target/wasm32-wasip1/release/add.wasm +$ cargo run --release -- 1 2 ../add/target/wasm32-wasip1/release/adder.wasm 1 + 2 = 3 ``` @@ -201,7 +201,8 @@ world root { } ``` -As the import is unfulfilled, the `calculator.wasm` component could not run by itself in its current form. To fulfill the `add` import, so that only `calculate` is exported, you would need to [compose the `calculator.wasm` with some `exports-add.wasm` into a single, self-contained component](../creating-and-consuming/composing.md). +As the import is unfulfilled, the `calculator.wasm` component could not run by itself in its current form. To fulfill the `add` import, so that +only `calculate` is exported, you would need to [compose the `calculator.wasm` with some `adder.wasm` into a single, self-contained component](../creating-and-consuming/composing.md). ## Creating a command component with `cargo component`