From 9b447846e27dc5fc8ca72957bf4ab1e37c2a83af Mon Sep 17 00:00:00 2001 From: Daniel Macovei Date: Mon, 22 Apr 2024 14:35:00 -0500 Subject: [PATCH 1/3] initial ideas --- component-model/examples/tutorial/README.md | 2 +- .../examples/tutorial/adder/Cargo.toml | 2 +- .../examples/tutorial/adder/src/bindings.rs | 8 +- .../examples/tutorial/adder/src/lib.rs | 2 +- .../examples/tutorial/calculator/Cargo.toml | 2 +- .../tutorial/calculator/src/bindings.rs | 12 +-- .../examples/tutorial/calculator/src/lib.rs | 4 +- .../examples/tutorial/command/Cargo.toml | 2 +- .../examples/tutorial/command/src/bindings.rs | 6 +- .../examples/tutorial/command/src/main.rs | 2 +- .../examples/tutorial/wit/calculator.wit | 2 +- .../src/creating-and-consuming/composing.md | 53 ++++++++++--- .../creating-and-consuming/distributing.md | 12 ++- component-model/src/language-support/go.md | 6 +- component-model/src/language-support/rust.md | 77 +++++++++++++++---- component-model/src/tutorial.md | 19 ++++- 16 files changed, 154 insertions(+), 57 deletions(-) diff --git a/component-model/examples/tutorial/README.md b/component-model/examples/tutorial/README.md index c5c1d1b5..e0b71c38 100644 --- a/component-model/examples/tutorial/README.md +++ b/component-model/examples/tutorial/README.md @@ -6,7 +6,7 @@ add an `op` enum that delineates each operator. The following example interface has an `add` operation: ```wit -package docs:calculator@0.1.0; +package bytecode-alliance:calculator@0.1.0; interface calculate { enum op { diff --git a/component-model/examples/tutorial/adder/Cargo.toml b/component-model/examples/tutorial/adder/Cargo.toml index a7d91dd1..4f9ad4d9 100644 --- a/component-model/examples/tutorial/adder/Cargo.toml +++ b/component-model/examples/tutorial/adder/Cargo.toml @@ -11,7 +11,7 @@ wit-bindgen-rt = "0.20.0" crate-type = ["cdylib"] [package.metadata.component] -package = "docs:calculator" +package = "bytecode-alliance:calculator" [package.metadata.component.target] path = "../wit/calculator.wit" diff --git a/component-model/examples/tutorial/adder/src/bindings.rs b/component-model/examples/tutorial/adder/src/bindings.rs index bc59a35f..b4ebe064 100644 --- a/component-model/examples/tutorial/adder/src/bindings.rs +++ b/component-model/examples/tutorial/adder/src/bindings.rs @@ -25,7 +25,7 @@ pub mod exports { macro_rules! __export_docs_calculator_add_0_1_0_cabi{ ($ty:ident with_types_in $($path_to_types:tt)*) => (const _: () = { - #[export_name = "docs:calculator/add@0.1.0#add"] + #[export_name = "bytecode_alliance:calculator/add@0.1.0#add"] unsafe extern "C" fn export_add(arg0: i32,arg1: i32,) -> i32 { $($path_to_types)*::_export_add_cabi::<$ty>(arg0, arg1) } @@ -132,7 +132,7 @@ mod _rt { macro_rules! __export_adder_impl { ($ty:ident) => (self::export!($ty with_types_in self);); ($ty:ident with_types_in $($path_to_types_root:tt)*) => ( - $($path_to_types_root)*::exports::docs::calculator::add::__export_docs_calculator_add_0_1_0_cabi!($ty with_types_in $($path_to_types_root)*::exports::docs::calculator::add); + $($path_to_types_root)*::exports::bytecode_alliance::calculator::add::__export_docs_calculator_add_0_1_0_cabi!($ty with_types_in $($path_to_types_root)*::exports::bytecode_alliance::calculator::add); ) } #[doc(inline)] @@ -143,8 +143,8 @@ pub(crate) use __export_adder_impl as export; #[doc(hidden)] pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 213] = *b"\ \0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07Z\x01A\x02\x01A\x02\x01\ -B\x02\x01@\x02\x01ay\x01by\0y\x04\0\x03add\x01\0\x04\x01\x19docs:calculator/add@\ -0.1.0\x05\0\x04\x01\x1bdocs:calculator/adder@0.1.0\x04\0\x0b\x0b\x01\0\x05adder\x03\ +B\x02\x01@\x02\x01ay\x01by\0y\x04\0\x03add\x01\0\x04\x01\x19bytecode_alliance:calculator/add@\ +0.1.0\x05\0\x04\x01\x1bbytecode_alliance:calculator/adder@0.1.0\x04\0\x0b\x0b\x01\0\x05adder\x03\ \0\0\0G\x09producers\x01\x0cprocessed-by\x02\x0dwit-component\x070.201.0\x10wit-\ bindgen-rust\x060.21.0"; diff --git a/component-model/examples/tutorial/adder/src/lib.rs b/component-model/examples/tutorial/adder/src/lib.rs index 0afc22d8..6e1464fd 100644 --- a/component-model/examples/tutorial/adder/src/lib.rs +++ b/component-model/examples/tutorial/adder/src/lib.rs @@ -1,6 +1,6 @@ mod bindings; -use crate::bindings::exports::docs::calculator::add::Guest; +use crate::bindings::exports::bytecode_alliance::calculator::add::Guest; struct Component; diff --git a/component-model/examples/tutorial/calculator/Cargo.toml b/component-model/examples/tutorial/calculator/Cargo.toml index 0d412b0f..87403ed4 100644 --- a/component-model/examples/tutorial/calculator/Cargo.toml +++ b/component-model/examples/tutorial/calculator/Cargo.toml @@ -11,7 +11,7 @@ wit-bindgen-rt = "0.20.0" crate-type = ["cdylib"] [package.metadata.component] -package = "docs:calculator" +package = "bytecode-alliance:calculator" [package.metadata.component.target] path = "../wit/calculator.wit" diff --git a/component-model/examples/tutorial/calculator/src/bindings.rs b/component-model/examples/tutorial/calculator/src/bindings.rs index c17b39f2..8cafca7a 100644 --- a/component-model/examples/tutorial/calculator/src/bindings.rs +++ b/component-model/examples/tutorial/calculator/src/bindings.rs @@ -14,7 +14,7 @@ pub mod docs { pub fn add(a: u32, b: u32) -> u32 { unsafe { #[cfg(target_arch = "wasm32")] - #[link(wasm_import_module = "docs:calculator/add@0.1.0")] + #[link(wasm_import_module = "bytecode_alliance:calculator/add@0.1.0")] extern "C" { #[link_name = "add"] fn wit_import(_: i32, _: i32) -> i32; @@ -88,7 +88,7 @@ pub mod exports { macro_rules! __export_docs_calculator_calculate_0_1_0_cabi{ ($ty:ident with_types_in $($path_to_types:tt)*) => (const _: () = { - #[export_name = "docs:calculator/calculate@0.1.0#eval-expression"] + #[export_name = "bytecode_alliance:calculator/calculate@0.1.0#eval-expression"] unsafe extern "C" fn export_eval_expression(arg0: i32,arg1: i32,arg2: i32,) -> i32 { $($path_to_types)*::_export_eval_expression_cabi::<$ty>(arg0, arg1, arg2) } @@ -195,7 +195,7 @@ mod _rt { macro_rules! __export_calculator_impl { ($ty:ident) => (self::export!($ty with_types_in self);); ($ty:ident with_types_in $($path_to_types_root:tt)*) => ( - $($path_to_types_root)*::exports::docs::calculator::calculate::__export_docs_calculator_calculate_0_1_0_cabi!($ty with_types_in $($path_to_types_root)*::exports::docs::calculator::calculate); + $($path_to_types_root)*::exports::bytecode_alliance::calculator::calculate::__export_docs_calculator_calculate_0_1_0_cabi!($ty with_types_in $($path_to_types_root)*::exports::bytecode_alliance::calculator::calculate); ) } #[doc(inline)] @@ -206,10 +206,10 @@ pub(crate) use __export_calculator_impl as export; #[doc(hidden)] pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 313] = *b"\ \0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xb8\x01\x01A\x02\x01\ -A\x04\x01B\x02\x01@\x02\x01ay\x01by\0y\x04\0\x03add\x01\0\x03\x01\x19docs:calcul\ +A\x04\x01B\x02\x01@\x02\x01ay\x01by\0y\x04\0\x03add\x01\0\x03\x01\x19bytecode_alliance:calcul\ ator/add@0.1.0\x05\0\x01B\x04\x01m\x01\x03add\x04\0\x02op\x03\0\0\x01@\x03\x02op\ -\x01\x01xy\x01yy\0y\x04\0\x0feval-expression\x01\x02\x04\x01\x1fdocs:calculator/\ -calculate@0.1.0\x05\x01\x04\x01\x20docs:calculator/calculator@0.1.0\x04\0\x0b\x10\ +\x01\x01xy\x01yy\0y\x04\0\x0feval-expression\x01\x02\x04\x01\x1fbytecode_alliance:calculator/\ +calculate@0.1.0\x05\x01\x04\x01\x20bytecode_alliance:calculator/calculator@0.1.0\x04\0\x0b\x10\ \x01\0\x0acalculator\x03\0\0\0G\x09producers\x01\x0cprocessed-by\x02\x0dwit-comp\ onent\x070.201.0\x10wit-bindgen-rust\x060.21.0"; diff --git a/component-model/examples/tutorial/calculator/src/lib.rs b/component-model/examples/tutorial/calculator/src/lib.rs index 5eb86f14..00f9679f 100644 --- a/component-model/examples/tutorial/calculator/src/lib.rs +++ b/component-model/examples/tutorial/calculator/src/lib.rs @@ -1,9 +1,9 @@ mod bindings; -use bindings::exports::docs::calculator::calculate::{Guest, Op}; +use bindings::exports::bytecode_alliance::calculator::calculate::{Guest, Op}; // Bring the imported add function into scope -use bindings::docs::calculator::add::add; +use bindings::bytecode_alliance::calculator::add::add; struct Component; diff --git a/component-model/examples/tutorial/command/Cargo.toml b/component-model/examples/tutorial/command/Cargo.toml index dbc3dd5f..5c13a824 100644 --- a/component-model/examples/tutorial/command/Cargo.toml +++ b/component-model/examples/tutorial/command/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [package.metadata.component] -package = "docs:calculator" +package = "bytecode-alliance:calculator" [package.metadata.component.target] path = "../wit/calculator.wit" diff --git a/component-model/examples/tutorial/command/src/bindings.rs b/component-model/examples/tutorial/command/src/bindings.rs index d006fc95..fdc8b130 100644 --- a/component-model/examples/tutorial/command/src/bindings.rs +++ b/component-model/examples/tutorial/command/src/bindings.rs @@ -41,7 +41,7 @@ pub mod docs { pub fn eval_expression(op: Op, x: u32, y: u32) -> u32 { unsafe { #[cfg(target_arch = "wasm32")] - #[link(wasm_import_module = "docs:calculator/calculate@0.1.0")] + #[link(wasm_import_module = "bytecode_alliance:calculator/calculate@0.1.0")] extern "C" { #[link_name = "eval-expression"] fn wit_import(_: i32, _: i32, _: i32) -> i32; @@ -137,8 +137,8 @@ mod _rt { pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 246] = *b"\ \0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07}\x01A\x02\x01A\x02\x01\ B\x04\x01m\x01\x03add\x04\0\x02op\x03\0\0\x01@\x03\x02op\x01\x01xy\x01yy\0y\x04\0\ -\x0feval-expression\x01\x02\x03\x01\x1fdocs:calculator/calculate@0.1.0\x05\0\x04\ -\x01\x19docs:calculator/app@0.1.0\x04\0\x0b\x09\x01\0\x03app\x03\0\0\0G\x09produ\ +\x0feval-expression\x01\x02\x03\x01\x1fbytecode_alliance:calculator/calculate@0.1.0\x05\0\x04\ +\x01\x19bytecode_alliance:calculator/app@0.1.0\x04\0\x0b\x09\x01\0\x03app\x03\0\0\0G\x09produ\ cers\x01\x0cprocessed-by\x02\x0dwit-component\x070.201.0\x10wit-bindgen-rust\x06\ 0.21.0"; diff --git a/component-model/examples/tutorial/command/src/main.rs b/component-model/examples/tutorial/command/src/main.rs index 055fffbe..7a3a5464 100644 --- a/component-model/examples/tutorial/command/src/main.rs +++ b/component-model/examples/tutorial/command/src/main.rs @@ -3,7 +3,7 @@ mod bindings; use clap::Parser; use std::fmt; -use bindings::docs::calculator::{calculate, calculate::Op}; +use bindings::bytecode_alliance::calculator::{calculate, calculate::Op}; fn parse_operator(op: &str) -> anyhow::Result { match op { diff --git a/component-model/examples/tutorial/wit/calculator.wit b/component-model/examples/tutorial/wit/calculator.wit index ebfd2344..6586f9a6 100644 --- a/component-model/examples/tutorial/wit/calculator.wit +++ b/component-model/examples/tutorial/wit/calculator.wit @@ -1,4 +1,4 @@ -package docs:calculator@0.1.0; +package bytecode-alliance:calculator@0.1.0; interface calculate { enum op { diff --git a/component-model/src/creating-and-consuming/composing.md b/component-model/src/creating-and-consuming/composing.md index 5d7365a8..e7d59f95 100644 --- a/component-model/src/creating-and-consuming/composing.md +++ b/component-model/src/creating-and-consuming/composing.md @@ -14,34 +14,38 @@ When you compose components, you wire up the imports of one "primary" component * The new component _imports_ any imports of the primary component imports that the dependencies didn't satisfy * If several components import the same interface, the new component imports that interface - it doesn't "remember" that the import was declared in several different places -For example, consider two components with the following worlds: +For example, consider the following WIT packages and components ```wit -// component `validator` -package docs:validator@0.1.0; +// component `bytecode-alliance:validator-impl` +package bytecode-alliance:validator@0.1.0; -interface validator { +interface validation { validate-text: func(text: string) -> string; } -world { +world validator-world { export validator; - import docs:regex/match@0.1.0; + import bytecode-alliance:regex/match@0.1.0; } -// component 'regex' -package docs:regex@0.1.0; +// component 'bytecode-alliance:regex-impl' +package bytecode-alliance:regex@0.1.0; interface match { first-match: func(regex: string, text: string) -> string; } -world { +world regex-world { export match; } ``` -If we compose `validator` with `regex`, `validator`'s import of `docs:regex/match@0.1.0` is wired up to `regex`'s export of `match`. The net result is that the composed component exports `docs:validator/validator@0.1.0` and has no imports. The composed component does _not_ export `docs:regex/match@0.1.0` - that has become an internal implementation detail of the composed component. +Here we have two WIT packages, `bytecode-alliance:validator` and `bytecode-alliance:regex`. The component `bytecode-alliance:validator-impl` implements the world `bytecode-alliance:validator/validator-world` and the component `bytecode-alliance:regex-impl` implements the world `bytecode-alliance:regex/regex-world`, each of which could have been written in any guest language that targets the component model. + +When we compose components together, we are specifying which *instance* of an imported interface we want our components to use. + +If we compose `bytecode-alliance:validator-impl` with `bytecode-alliance:regex-impl`, `bytecode-alliance:validator-impl`'s import of the `bytecode-alliance:regex/match@0.1.0` interface is wired up to `bytecode-alliance:regex-impl`'s export of `match`. The net result is that the composed component exports an instance of the `bytecode-alliance:validator/validation@0.1.0` interface, and has no imports. The composed component does _not_ export `bytecode-alliance:regex/match@0.1.0` - that has become an internal implementation detail of the composed component. Component composition tools are in their early stages right now. Here are some tips to avoid or diagnose errors: @@ -78,3 +82,32 @@ You can compose components visually using the builder app at https://wasmbuilder 4. To fulfil one of the primary component's imports with a dependency's export, drag from the "I" icon next to the export to the "I" item next to the import. (Again, the clickable area is quite small - wait for the cursor to change from a hand to a cross.) 5. When you have connected all the imports and exports that you want, click the Download Component button to download the composed component as a `.wasm` file. + +## Composing components with the wac CLI + +You can use the [wac](https://github.com/bytecodealliance/wac) CLI as well to create your composition. + +The example composition described above could be created with the `wac` file below + +``` +//composition.wac +package bytecode-alliance:composition; + +let regex = new bytecode-alliance:regex-impl { ... }; +let validator = new bytecode-alliance:validator-impl { "bytecode-alliance:regex/match": regex.match, ... }; + +export validator...; +``` + +The `new` keyword here is used to create an instance of a component, namely `bytecode-alliance:regex-impl` and `bytecode-alliance:validator-impl` are instantiated (with instance names`regex` and `validator`) that target the `bytecode-alliance:validator/validator-world` and `bytecode-alliance:regex/regex-world` worlds respectively. + +When we instantiate the component `bytecode-alliance:validator-impl`, since its world targets `bytecode-alliance:validotor/validator-world` which imports the `bytecode-alliance:regex/match` interface, we need to specify which instance of that interface we want. We can use the syntax `regex.match` here to say we want the one from the `regex` instance we got from instantiating `bytecodealliance:regex-impl`. + +One of the nice features of composing this way, is that if you had two components that share a dependency on another component, but you don't want them to depend on the same instance, then you could create two separate instances for each of them to depend on. + +You may also be wondering what's up with the `...` syntax. It's common for components to import functionality from their host/runtime, like `wasi:filesystem` or `wasi:http` for example. The `...` syntax is how we pass that functionality along to all of the components that comprise the composition we're authoring. + +The components that you use in your composition can either be referenced from a registry or from a local file system. There are a few ways to configure where you want your dependencies to live in a local setup, which are described in the [wac repo](https://github.com/bytecodealliance/wac#dependencies). + +With all that, we can just run `wac encode composition.wac -o composition.wasm` and it will spit out a component that is runnable. + diff --git a/component-model/src/creating-and-consuming/distributing.md b/component-model/src/creating-and-consuming/distributing.md index 3abdc3c9..f9296c70 100644 --- a/component-model/src/creating-and-consuming/distributing.md +++ b/component-model/src/creating-and-consuming/distributing.md @@ -2,6 +2,14 @@ Modern applications rely extensively on third-party packages - so extensively that distributing packages is almost an industry in itself. Traditionally, these have been specific to a language. For example, JavaScript developers are used to using packages from NPM, and Rust developers use `crates.io`. Some runtimes support binary distribution and linking, enabling limited cross-language interop; for example, Maven packages can be written in any language that targets the Java runtime. Services like this are variously referred to as "package managers" or "registries." -Publishing and distribution are not defined by the core component model, but will form an important part of the component ecosystem. For example, if you're writing JavaScript, and want to pull in a highly optimised machine learning algorithm written in C and compiled to Wasm, you should be able to invoke it from a registry, just as easily as you would add a NPM package from the NPM registry. +Today, the primary way to distribute components is via [OCI](https://opencontainers.org/) and Warg registries. The Warg registry protocol, developed as a Bytecode Alliance project, was designed specifically for Wasm components. You can learn more about the project and codebase [here](https://github.com/bytecodealliance/registry). If you'd like to start publishing and exploring components with Warg, visit wa.dev. -Publishing and distribution is a work in progress. The proposed registry protocol is [warg](https://warg.io/), but this is still in development, and there are no public warg registries as yet. You can find more information about the development of the registry protocol [here](https://github.com/bytecodealliance/governance/blob/main/SIGs/SIG-Registries/proposal.md). +## Using Warg registries for WIT packages with the `wit` CLI + +One of the primary use cases of a Warg registry is publishing and downloading WIT packages. The easiest way to create and use WIT packages is with the [wit](https://github.com/bytecodealliance/cargo-component/tree/main/crates/wit) CLI. After installing the CLI, you can start a project by simply typing `wit init`, and then writing any valid WIT file. If you want your WIT package to reference an interface defined in another WIT package, simply use `wit add :/`. You can produce a binary whenever you're finished authoring your package, via `wit build`, and can publish to a registry via `wit publish`. + +## Using Warg registries to author and distribute rust components +Another tool that is set up to interact with warg registries is `cargo-component`. You can read about how to build and use published packages in your rust projects in the [rust](../language-support/rust.md) section. + +## Using Warg registries in your component compositions +The `wac` CLI is yet another tool with warg registry integration. Learn more about how to use registries and wac in the [composition](./composing.md#composing-components-with-the-wac-cli) section. diff --git a/component-model/src/language-support/go.md b/component-model/src/language-support/go.md index 26dd3eb3..4f2b7a10 100644 --- a/component-model/src/language-support/go.md +++ b/component-model/src/language-support/go.md @@ -152,7 +152,7 @@ world](https://github.com/bytecodealliance/component-docs/tree/main/component-mo For this example, we will use the following world, which moves the add function behind an `add` interface: ```wit -package docs:adder@0.1.0; +package bytecode-alliance:adder@0.1.0; interface add { add: func(a: u32, b: u32) -> u32; @@ -201,7 +201,7 @@ gen ``` The `adder.go` file defines an `ExportsDocsAdder0_1_0_Add` interface that matches the structure of our `add` -interface. The name of the interface is taken from the WIT package name (`docs:adder@0.1.0`) combined with the interface name (`add`). In our Go module, first implement the `ExportsDocsAdder0_1_0_Add` interface by defining the `Add` function. +interface. The name of the interface is taken from the WIT package name (`bytecode-alliance:adder@0.1.0`) combined with the interface name (`add`). In our Go module, first implement the `ExportsDocsAdder0_1_0_Add` interface by defining the `Add` function. ```go package main @@ -283,6 +283,6 @@ world root { import wasi:filesystem/types@0.2.0; import wasi:filesystem/preopens@0.2.0; - export docs:adder/add@0.1.0; + export bytecode-alliance:adder/add@0.1.0; } ``` diff --git a/component-model/src/language-support/rust.md b/component-model/src/language-support/rust.md index fcdff582..1c30a53c 100644 --- a/component-model/src/language-support/rust.md +++ b/component-model/src/language-support/rust.md @@ -84,7 +84,7 @@ $ cargo run --release -- 1 2 ../add/target/wasm32-wasi/release/add.wasm The [sample `add.wit` file](https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/example-host/add.wit) exports a function. However, to use your component from another component, it must export an interface. This results in slightly fiddlier bindings. For example, to implement the following world: ```wit -package docs:adder@0.1.0; +package bytecode-alliance:adder@0.1.0; interface add { add: func(a: u32, b: u32) -> u32; @@ -100,7 +100,7 @@ you would write the following Rust code: ```rust mod bindings; // Separating out the interface puts it in a sub-module -use bindings::exports::docs::calculator::add::Guest; +use bindings::exports::bytecode-alliance::calculator::add::Guest; struct Component; @@ -125,7 +125,7 @@ For example, suppose you have created and built an adder component as explained // in the 'calculator' project // wit/world.wit -package docs:calculator; +package bytecode-alliance:calculator; interface calculate { eval-expression: func(expr: string) -> u32; @@ -133,21 +133,41 @@ interface calculate { world calculator { export calculate; - import docs:adder/add@0.1.0; + import bytecode-alliance:adder/add@0.1.0; } ``` ### Referencing the package to import -Because the `docs:adder` package is in a different project, we must first tell `cargo component` how to find it. To do this, add the following to the `Cargo.toml` file: +Because the `bytecode-alliance:adder` package is in a different project, we must first tell `cargo component` how to find it. To do this, add the following to the `Cargo.toml` file: ```toml [package.metadata.component.target.dependencies] -"docs:adder" = { path = "../adder/wit" } # directory containing the WIT package +"bytecode-alliance:adder" = { path = "../adder/wit" } # directory containing the WIT package ``` 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. +### Using published WIT packages in a registry + +Since `cargo component` is integrated with the Warg protocol, you can also interact with WIT packages that have been published to a [Warg registry](/../creating-and-consuming/distributing.md). + +To create a component that targets a world in a WIT package, simply run + +``` +cargo component new --lib --target :/ path/to/library +``` + +Both the [calculator](https://preview.wa.dev/bytecode-alliance:calculator) and [adder](https://preview.wa.dev/bytecode-alliance:adder) packages have been published to wa.dev, so the following commands will create rust projects with the needed implementations for the WIT packages scaffolded out for you. + + +``` +cargo component new --lib --target bytecode-alliance:calculator/calculator calculator +cargo component new --lib --target bytecode-alliance:adder/adder adder +``` + +Since this flow uses WIT packages from a registry, this approach doesn't need the prior step for pointing to a local WIT package. + ### Calling the import from Rust Now the declaration of `add` in the adder's WIT file is visible to the `calculator` project. To invoke the imported `add` interface from the `calculate` implementation: @@ -156,10 +176,10 @@ Now the declaration of `add` in the adder's WIT file is visible to the `calculat // src/lib.rs mod bindings; -use bindings::exports::docs::calculator::calculate::Guest; +use bindings::exports::bytecode_alliance::calculator::calculate::Guest; // Bring the imported add function into scope -use bindings::docs::calculator::add::add; +use bindings::bytecode_alliance::calculator::add::add; struct Component; @@ -184,13 +204,29 @@ $ wasm-tools component wit ./target/wasm32-wasi/release/calculator.wasm package root:component; world root { - import docs:adder/add@0.1.0; + import bytecode-alliance:adder/add@0.1.0; - export docs:calculator/calculate@0.1.0; + export bytecode-alliance:calculator/calculate@0.1.0; } ``` -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 `exports-add.wasm` into a single, self-contained component](../creating-and-consuming/composing.md), or use the [wac CLI](../creating-and-consuming/composing.md#composing-components-with-the-wac-cli). + +If you use the wac CLI, the following wac file would grab the bytecode alliance components ([adder-component](https://preview.wa.dev/bytecode-alliance:adder-component) and [calculator-component](https://preview.wa.dev/bytecode-alliance:calculator-component)) that implement each of the WIT interfaces ([adder](https://preview.wa.dev/bytecode-alliance:adder) and [calculator](https://preview.wa.dev/bytecode-alliance:calculator)). + +``` +// composition.wac +package bytecode-alliance:composition; + +let adder = new bytecode-alliance:adder-component{ ... }; +let calc = new bytecode-alliance:calculator-component { "bytecode-alliance:adder/add@0.1.0": adder.add, ... }; + +export calc...; +``` + +Just run `wac encode composition.wac -o composition.wasm` and you'll have a runnable component that you can use. + +You can also run `cargo component publish` in your own implementations and replace the components in the wac file with the ones that you authored instead, or the supported [local dependencies](https://github.com/bytecodealliance/wac#dependencies) to point to the binaries on your machine. ## Creating a command component with `cargo component` @@ -228,14 +264,14 @@ As mentioned above, `cargo component build` doesn't generate a WIT file for a co 1. Add a `wit/world.wit` to your project, and write a WIT world that imports the interface(s) you want to use. For example: ```wit -package docs:app; +package bytecode-alliance:app; world app { - import docs:calculator/calculate@0.1.0; + import bytecode-alliance:calculator/calculate@0.1.0; } ``` -> `cargo component` sometimes fails to find packages if versions are not set explicitly. For example, if the calculator WIT declares `package docs:calculator` rather than `docs:calculator@0.1.0`, then you may get an error even though `cargo component build` automatically versions the binary export. +> `cargo component` sometimes fails to find packages if versions are not set explicitly. For example, if the calculator WIT declares `package bytecode-alliance:calculator` rather than `bytecode-alliance:calculator@0.1.0`, then you may get an error even though `cargo component build` automatically versions the binary export. 2. Edit `Cargo.toml` to tell `cargo component` about the new WIT file: @@ -250,16 +286,23 @@ path = "wit" ```toml [package.metadata.component.target.dependencies] -"docs:calculator" = { path = "../calculator/wit" } -"docs:adder" = { path = "../adder/wit" } +"bytecode-alliance:calculator" = { path = "../calculator/wit" } +"bytecode-alliance:adder" = { path = "../adder/wit" } ``` +Alternatively, if you're using the registry packages, you can use the latest versions published instead of a path. You can find the versions on the registry pages, ([calculator](https://preview.wa.dev/bytecode-alliance:calculator) and [adder](https://preview.wa.dev/bytecode-alliance:adder)) + +```toml +[package.metadata.component.target.dependencies] +"bytecode-alliance:calculator" = "x.x.x" +"bytecode-alliance:adder" = "x.x.x" +``` > If the external package refers to other packages, you need to provide the paths to them as well. 4. Use the imported interface in your Rust code: ```rust -use bindings::docs::calculator::calculate::eval_expression; +use bindings::bytecode-alliance::calculator::calculate::eval_expression; fn main() { let result = eval_expression("1 + 1"); diff --git a/component-model/src/tutorial.md b/component-model/src/tutorial.md index 819c7655..8d0eaef8 100644 --- a/component-model/src/tutorial.md +++ b/component-model/src/tutorial.md @@ -35,7 +35,7 @@ For tutorial purposes, we are going to define all our interfaces in one WIT pack ```wit // calculator.wit -package docs:calculator@0.1.0; +package bytecode-alliance:calculator@0.1.0; interface calculate { enum op { @@ -63,12 +63,14 @@ world app { ``` +If you're using rust and you want to learn how to use a registry instead, you can use the WIT packages that have been published for this tutorial ([calculator](https://preview.wa.dev/bytecode-alliance:calculator) and [adder](https://preview.wa.dev/bytecode-alliance:adder)) or publish the same packages on your own namespace using the [wit CLI](./creating-and-consuming/distributing.md#using-warg-registries-for-wit-packages-with-the-wit-cli) + ## Create an `add` component Reference the [language guide](language-support.md) and [authoring components documentation](creating-and-consuming/authoring.md) to create a component that implements the `adder` world of `calculator.wit`. For reference, see the completed -[example](https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/tutorial/adder/). +[example](https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/tutorial/adder/). If using the registry, this will use the [adder](https://preview.wa.dev/bytecode-alliance:adder) WIT package. ## Create a `calculator` component @@ -88,7 +90,7 @@ with a `main` function to a component with `wasi:cli/run` exported. Scaffold a n with a `command` component: ```sh -cargo component new command --command +cargo component new ``` This component will implement the [`app`](https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/tutorial/wit/calculator.wit) world, which @@ -101,6 +103,14 @@ path = "../path/to/calculator.wit" world = "app" ``` +If you're using the registry, you can specify the import. +``` +[package.metadata.component.target.dependencies] +"bytecode-alliance:calculator" = "x.x.x" +``` + +Check [calculator](https://preview.wa.dev/bytecode-alliance:calculator) for the latest version to use. + Now, implement a command line application that: 1. takes in three arguments: two operands and the name of an operator ("1 2 add") @@ -122,6 +132,9 @@ wasm-tools compose calculator.wasm -d adder.wasm -o composed.wasm wasm-tools compose command.wasm -d composed.wasm -o final.wasm ``` +You can also use the [wac](https://github.com/bytecodealliance/wac) CLI to compose these components together. +Check out the [docs](./creating-and-consuming/composing.md#composing-components-with-the-wac-cli) for information on how. + > If you'd prefer to take a more visual approach to composing components, see the [documentation on > composing components with > wasmbuilder.app](creating-and-consuming/composing.md#composing-components-with-a-visual-interface). From ddcf6486030d05cb9ac90de8fbb2b483abf7f062 Mon Sep 17 00:00:00 2001 From: Daniel Macovei Date: Wed, 15 May 2024 14:39:59 -0500 Subject: [PATCH 2/3] cleanup --- .gitignore | 1 + component-model/examples/tutorial/README.md | 35 +++++--- .../examples/tutorial/adder/Cargo.toml | 4 +- .../examples/tutorial/adder/src/bindings.rs | 24 +++--- .../examples/tutorial/adder/src/lib.rs | 2 +- .../examples/tutorial/calculator/Cargo.toml | 10 +-- .../tutorial/calculator/src/bindings.rs | 32 +++---- .../examples/tutorial/calculator/src/lib.rs | 4 +- .../examples/tutorial/command/Cargo.toml | 7 +- .../examples/tutorial/command/src/bindings.rs | 18 ++-- .../examples/tutorial/command/src/main.rs | 2 +- .../examples/tutorial/wit/adder/adder.wit | 9 ++ .../examples/tutorial/wit/adder/wit.toml | 1 + .../wit/{ => calculator}/calculator.wit | 11 +-- .../examples/tutorial/wit/calculator/wit.lock | 11 +++ .../examples/tutorial/wit/calculator/wit.toml | 4 + .../examples/tutorial/wit/local/adder.wit | 9 ++ .../tutorial/wit/local/calculator.wit | 18 ++++ .../src/creating-and-consuming/composing.md | 38 +++----- .../creating-and-consuming/distributing.md | 8 +- component-model/src/language-support/go.md | 6 +- component-model/src/language-support/rust.md | 86 ++++++++----------- component-model/src/tutorial.md | 76 +++++++++++----- 23 files changed, 247 insertions(+), 169 deletions(-) create mode 100644 component-model/examples/tutorial/wit/adder/adder.wit create mode 100644 component-model/examples/tutorial/wit/adder/wit.toml rename component-model/examples/tutorial/wit/{ => calculator}/calculator.wit (57%) create mode 100644 component-model/examples/tutorial/wit/calculator/wit.lock create mode 100644 component-model/examples/tutorial/wit/calculator/wit.toml create mode 100644 component-model/examples/tutorial/wit/local/adder.wit create mode 100644 component-model/examples/tutorial/wit/local/calculator.wit diff --git a/.gitignore b/.gitignore index 2ac07726..e6b1b2a0 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ # Build artifacts from examples **/jco/bindings **/examples/**/*.wasm +.DS_Store \ No newline at end of file diff --git a/component-model/examples/tutorial/README.md b/component-model/examples/tutorial/README.md index e0b71c38..14db75ce 100644 --- a/component-model/examples/tutorial/README.md +++ b/component-model/examples/tutorial/README.md @@ -1,12 +1,29 @@ # Building a Calculator of Wasm Components This tutorial walks through how to compose a component to build a Wasm calculator. +It is a rich example of using multiple components, targeting distinct worlds described across multiple WIT packages + +The first package consists of addition operations + +```wit +//adder.wit +package component-book:adder@0.1.0; + +interface add { + add: func(a: u32, b: u32) -> u32; +} + +world adder { + export add; +} +``` + The WIT package for the calculator consists of a world for each mathematical operator add an `op` enum that delineates each operator. The following example interface only has an `add` operation: ```wit -package bytecode-alliance:calculator@0.1.0; +package component-book:calculator@0.1.0; interface calculate { enum op { @@ -15,17 +32,9 @@ interface calculate { eval-expression: func(op: op, x: u32, y: u32) -> u32; } -interface add { - add: func(a: u32, b: u32) -> u32; -} - -world adder { - export add; -} - world calculator { export calculate; - import add; + import component-book:adder/add@0.1.0; } ``` @@ -43,6 +52,12 @@ wasm-tools compose calculator/target/wasm32-wasi/release/calculator.wasm -d adde wasm-tools compose command/target/wasm32-wasi/release/command.wasm -d composed.wasm -o command.wasm ``` +You can also use `wac` instead of `wasm-tools compose` if you would like to fetch these components from a registry instead: + +``` +wac plug component-book:calculator-impl --plug component-book:adder-impl -o composed.wasm && wac plug component-book:command-impl --plug ./composed.wasm -o command.wasm +``` + Now, run the component with wasmtime: ```sh diff --git a/component-model/examples/tutorial/adder/Cargo.toml b/component-model/examples/tutorial/adder/Cargo.toml index 6f0b12c7..daa9aead 100644 --- a/component-model/examples/tutorial/adder/Cargo.toml +++ b/component-model/examples/tutorial/adder/Cargo.toml @@ -11,10 +11,10 @@ wit-bindgen-rt = { version = "0.24.0", features = ["bitflags"] } crate-type = ["cdylib"] [package.metadata.component] -package = "bytecode-alliance:calculator" +package = "component-book:calculator" [package.metadata.component.target] -path = "../wit/calculator.wit" +path = "../wit/adder/adder.wit" world = "adder" [package.metadata.component.dependencies] diff --git a/component-model/examples/tutorial/adder/src/bindings.rs b/component-model/examples/tutorial/adder/src/bindings.rs index 3e6cd4a2..12c43ef3 100644 --- a/component-model/examples/tutorial/adder/src/bindings.rs +++ b/component-model/examples/tutorial/adder/src/bindings.rs @@ -3,9 +3,9 @@ #[allow(dead_code)] pub mod exports { #[allow(dead_code)] - pub mod docs { + pub mod component_book { #[allow(dead_code)] - pub mod calculator { + pub mod adder { #[allow(dead_code, clippy::all)] pub mod add { #[used] @@ -27,17 +27,17 @@ pub mod exports { } #[doc(hidden)] - macro_rules! __export_docs_calculator_add_0_1_0_cabi{ + macro_rules! __export_component_book_adder_add_0_1_0_cabi{ ($ty:ident with_types_in $($path_to_types:tt)*) => (const _: () = { - #[export_name = "bytecode_alliance:calculator/add@0.1.0#add"] + #[export_name = "component-book:adder/add@0.1.0#add"] unsafe extern "C" fn export_add(arg0: i32,arg1: i32,) -> i32 { $($path_to_types)*::_export_add_cabi::<$ty>(arg0, arg1) } };); } #[doc(hidden)] - pub(crate) use __export_docs_calculator_add_0_1_0_cabi; + pub(crate) use __export_component_book_adder_add_0_1_0_cabi; } } } @@ -142,7 +142,7 @@ mod _rt { macro_rules! __export_adder_impl { ($ty:ident) => (self::export!($ty with_types_in self);); ($ty:ident with_types_in $($path_to_types_root:tt)*) => ( - $($path_to_types_root)*::exports::bytecode_alliance::calculator::add::__export_docs_calculator_add_0_1_0_cabi!($ty with_types_in $($path_to_types_root)*::exports::bytecode_alliance::calculator::add); + $($path_to_types_root)*::exports::component_book::adder::add::__export_component_book_adder_add_0_1_0_cabi!($ty with_types_in $($path_to_types_root)*::exports::component_book::adder::add); ) } #[doc(inline)] @@ -151,12 +151,12 @@ pub(crate) use __export_adder_impl as export; #[cfg(target_arch = "wasm32")] #[link_section = "component-type:wit-bindgen:0.24.0:adder:encoded world"] #[doc(hidden)] -pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 213] = *b"\ -\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07Z\x01A\x02\x01A\x02\x01\ -B\x02\x01@\x02\x01ay\x01by\0y\x04\0\x03add\x01\0\x04\x01\x19bytecode_alliance:calculator/add@\ -0.1.0\x05\0\x04\x01\x1bbytecode_alliance:calculator/adder@0.1.0\x04\0\x0b\x0b\x01\0\x05adder\x03\ -\0\0\0G\x09producers\x01\x0cprocessed-by\x02\x0dwit-component\x070.202.0\x10wit-\ -bindgen-rust\x060.24.0"; +pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 223] = *b"\ +\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07d\x01A\x02\x01A\x02\x01\ +B\x02\x01@\x02\x01ay\x01by\0y\x04\0\x03add\x01\0\x04\x01\x1ecomponent-book:adder\ +/add@0.1.0\x05\0\x04\x01\x20component-book:adder/adder@0.1.0\x04\0\x0b\x0b\x01\0\ +\x05adder\x03\0\0\0G\x09producers\x01\x0cprocessed-by\x02\x0dwit-component\x070.\ +202.0\x10wit-bindgen-rust\x060.24.0"; #[inline(never)] #[doc(hidden)] diff --git a/component-model/examples/tutorial/adder/src/lib.rs b/component-model/examples/tutorial/adder/src/lib.rs index 6e1464fd..efadfb82 100644 --- a/component-model/examples/tutorial/adder/src/lib.rs +++ b/component-model/examples/tutorial/adder/src/lib.rs @@ -1,6 +1,6 @@ mod bindings; -use crate::bindings::exports::bytecode_alliance::calculator::add::Guest; +use crate::bindings::exports::component_book::adder::add::Guest; struct Component; diff --git a/component-model/examples/tutorial/calculator/Cargo.toml b/component-model/examples/tutorial/calculator/Cargo.toml index 032a1f14..7fe5ea44 100644 --- a/component-model/examples/tutorial/calculator/Cargo.toml +++ b/component-model/examples/tutorial/calculator/Cargo.toml @@ -9,12 +9,12 @@ wit-bindgen-rt = { version = "0.24.0", features = ["bitflags"] } [lib] crate-type = ["cdylib"] - [package.metadata.component] -package = "bytecode-alliance:calculator" +package = "docs:calculator" + +[package.metadata.component.target.dependencies] +"docs:adder" = { path = "../wit/local/adder.wit" } [package.metadata.component.target] -path = "../wit/calculator.wit" +path = "../wit/local/calculator.wit" world = "calculator" - -[package.metadata.component.dependencies] diff --git a/component-model/examples/tutorial/calculator/src/bindings.rs b/component-model/examples/tutorial/calculator/src/bindings.rs index 0bd400be..82fa688b 100644 --- a/component-model/examples/tutorial/calculator/src/bindings.rs +++ b/component-model/examples/tutorial/calculator/src/bindings.rs @@ -1,9 +1,9 @@ // Generated by `wit-bindgen` 0.24.0. DO NOT EDIT! // Options used: #[allow(dead_code)] -pub mod docs { +pub mod component_book { #[allow(dead_code)] - pub mod calculator { + pub mod adder { #[allow(dead_code, clippy::all)] pub mod add { #[used] @@ -16,7 +16,7 @@ pub mod docs { pub fn add(a: u32, b: u32) -> u32 { unsafe { #[cfg(target_arch = "wasm32")] - #[link(wasm_import_module = "bytecode_alliance:calculator/add@0.1.0")] + #[link(wasm_import_module = "component-book:adder/add@0.1.0")] extern "C" { #[link_name = "add"] fn wit_import(_: i32, _: i32) -> i32; @@ -36,7 +36,7 @@ pub mod docs { #[allow(dead_code)] pub mod exports { #[allow(dead_code)] - pub mod docs { + pub mod component_book { #[allow(dead_code)] pub mod calculator { #[allow(dead_code, clippy::all)] @@ -92,17 +92,17 @@ pub mod exports { } #[doc(hidden)] - macro_rules! __export_docs_calculator_calculate_0_1_0_cabi{ + macro_rules! __export_component_book_calculator_calculate_0_1_0_cabi{ ($ty:ident with_types_in $($path_to_types:tt)*) => (const _: () = { - #[export_name = "bytecode_alliance:calculator/calculate@0.1.0#eval-expression"] + #[export_name = "component-book:calculator/calculate@0.1.0#eval-expression"] unsafe extern "C" fn export_eval_expression(arg0: i32,arg1: i32,arg2: i32,) -> i32 { $($path_to_types)*::_export_eval_expression_cabi::<$ty>(arg0, arg1, arg2) } };); } #[doc(hidden)] - pub(crate) use __export_docs_calculator_calculate_0_1_0_cabi; + pub(crate) use __export_component_book_calculator_calculate_0_1_0_cabi; } } } @@ -207,7 +207,7 @@ mod _rt { macro_rules! __export_calculator_impl { ($ty:ident) => (self::export!($ty with_types_in self);); ($ty:ident with_types_in $($path_to_types_root:tt)*) => ( - $($path_to_types_root)*::exports::bytecode_alliance::calculator::calculate::__export_docs_calculator_calculate_0_1_0_cabi!($ty with_types_in $($path_to_types_root)*::exports::bytecode_alliance::calculator::calculate); + $($path_to_types_root)*::exports::component_book::calculator::calculate::__export_component_book_calculator_calculate_0_1_0_cabi!($ty with_types_in $($path_to_types_root)*::exports::component_book::calculator::calculate); ) } #[doc(inline)] @@ -216,14 +216,14 @@ pub(crate) use __export_calculator_impl as export; #[cfg(target_arch = "wasm32")] #[link_section = "component-type:wit-bindgen:0.24.0:calculator:encoded world"] #[doc(hidden)] -pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 313] = *b"\ -\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xb8\x01\x01A\x02\x01\ -A\x04\x01B\x02\x01@\x02\x01ay\x01by\0y\x04\0\x03add\x01\0\x03\x01\x19bytecode_alliance:calcul\ -ator/add@0.1.0\x05\0\x01B\x04\x01m\x01\x03add\x04\0\x02op\x03\0\0\x01@\x03\x02op\ -\x01\x01xy\x01yy\0y\x04\0\x0feval-expression\x01\x02\x04\x01\x1fbytecode_alliance:calculator/\ -calculate@0.1.0\x05\x01\x04\x01\x20bytecode_alliance:calculator/calculator@0.1.0\x04\0\x0b\x10\ -\x01\0\x0acalculator\x03\0\0\0G\x09producers\x01\x0cprocessed-by\x02\x0dwit-comp\ -onent\x070.202.0\x10wit-bindgen-rust\x060.24.0"; +pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 338] = *b"\ +\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xd1\x01\x01A\x02\x01\ +A\x04\x01B\x02\x01@\x02\x01ay\x01by\0y\x04\0\x03add\x01\0\x03\x01\x1ecomponent-b\ +ook:adder/add@0.1.0\x05\0\x01B\x04\x01m\x01\x03add\x04\0\x02op\x03\0\0\x01@\x03\x02\ +op\x01\x01xy\x01yy\0y\x04\0\x0feval-expression\x01\x02\x04\x01)component-book:ca\ +lculator/calculate@0.1.0\x05\x01\x04\x01*component-book:calculator/calculator@0.\ +1.0\x04\0\x0b\x10\x01\0\x0acalculator\x03\0\0\0G\x09producers\x01\x0cprocessed-b\ +y\x02\x0dwit-component\x070.202.0\x10wit-bindgen-rust\x060.24.0"; #[inline(never)] #[doc(hidden)] diff --git a/component-model/examples/tutorial/calculator/src/lib.rs b/component-model/examples/tutorial/calculator/src/lib.rs index 00f9679f..b0ed92d5 100644 --- a/component-model/examples/tutorial/calculator/src/lib.rs +++ b/component-model/examples/tutorial/calculator/src/lib.rs @@ -1,9 +1,9 @@ mod bindings; -use bindings::exports::bytecode_alliance::calculator::calculate::{Guest, Op}; +use bindings::exports::component_book::calculator::calculate::{Guest, Op}; // Bring the imported add function into scope -use bindings::bytecode_alliance::calculator::add::add; +use bindings::component_book::adder::add::add; struct Component; diff --git a/component-model/examples/tutorial/command/Cargo.toml b/component-model/examples/tutorial/command/Cargo.toml index 16b17986..f2fd8bca 100644 --- a/component-model/examples/tutorial/command/Cargo.toml +++ b/component-model/examples/tutorial/command/Cargo.toml @@ -4,12 +4,15 @@ version = "0.1.0" edition = "2021" [package.metadata.component] -package = "bytecode-alliance:calculator" +package = "component-book:calculator" [package.metadata.component.target] -path = "../wit/calculator.wit" +path = "../wit/local/calculator.wit" world = "app" +[package.metadata.component.target.dependencies] +"docs:adder" = { path = "../wit/local/adder.wit" } + [dependencies] anyhow = "1" clap = { version = "4.3.19", features = ["derive"] } diff --git a/component-model/examples/tutorial/command/src/bindings.rs b/component-model/examples/tutorial/command/src/bindings.rs index 475f0c2f..7b8d98e0 100644 --- a/component-model/examples/tutorial/command/src/bindings.rs +++ b/component-model/examples/tutorial/command/src/bindings.rs @@ -1,7 +1,7 @@ // Generated by `wit-bindgen` 0.24.0. DO NOT EDIT! // Options used: #[allow(dead_code)] -pub mod docs { +pub mod component_book { #[allow(dead_code)] pub mod calculator { #[allow(dead_code, clippy::all)] @@ -43,7 +43,7 @@ pub mod docs { pub fn eval_expression(op: Op, x: u32, y: u32) -> u32 { unsafe { #[cfg(target_arch = "wasm32")] - #[link(wasm_import_module = "bytecode_alliance:calculator/calculate@0.1.0")] + #[link(wasm_import_module = "component-book:calculator/calculate@0.1.0")] extern "C" { #[link_name = "eval-expression"] fn wit_import(_: i32, _: i32, _: i32) -> i32; @@ -136,13 +136,13 @@ mod _rt { #[cfg(target_arch = "wasm32")] #[link_section = "component-type:wit-bindgen:0.24.0:app:encoded world"] #[doc(hidden)] -pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 246] = *b"\ -\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07}\x01A\x02\x01A\x02\x01\ -B\x04\x01m\x01\x03add\x04\0\x02op\x03\0\0\x01@\x03\x02op\x01\x01xy\x01yy\0y\x04\0\ -\x0feval-expression\x01\x02\x03\x01\x1fbytecode_alliance:calculator/calculate@0.1.0\x05\0\x04\ -\x01\bytecode_alliance:calculator/app@0.1.0\x04\0\x0b\x09\x01\0\x03app\x03\0\0\0G\x09produ\ -cers\x01\x0cprocessed-by\x02\x0dwit-component\x070.202.0\x10wit-bindgen-rust\x06\ -0.24.0"; +pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 267] = *b"\ +\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\x91\x01\x01A\x02\x01\ +A\x02\x01B\x04\x01m\x01\x03add\x04\0\x02op\x03\0\0\x01@\x03\x02op\x01\x01xy\x01y\ +y\0y\x04\0\x0feval-expression\x01\x02\x03\x01)component-book:calculator/calculat\ +e@0.1.0\x05\0\x04\x01#component-book:calculator/app@0.1.0\x04\0\x0b\x09\x01\0\x03\ +app\x03\0\0\0G\x09producers\x01\x0cprocessed-by\x02\x0dwit-component\x070.202.0\x10\ +wit-bindgen-rust\x060.24.0"; #[inline(never)] #[doc(hidden)] diff --git a/component-model/examples/tutorial/command/src/main.rs b/component-model/examples/tutorial/command/src/main.rs index 7a3a5464..9e229c3e 100644 --- a/component-model/examples/tutorial/command/src/main.rs +++ b/component-model/examples/tutorial/command/src/main.rs @@ -3,7 +3,7 @@ mod bindings; use clap::Parser; use std::fmt; -use bindings::bytecode_alliance::calculator::{calculate, calculate::Op}; +use bindings::component_book::calculator::{calculate, calculate::Op}; fn parse_operator(op: &str) -> anyhow::Result { match op { diff --git a/component-model/examples/tutorial/wit/adder/adder.wit b/component-model/examples/tutorial/wit/adder/adder.wit new file mode 100644 index 00000000..2696f24e --- /dev/null +++ b/component-model/examples/tutorial/wit/adder/adder.wit @@ -0,0 +1,9 @@ +package component-book:adder@0.1.0; + +interface add { + add: func(a: u32, b: u32) -> u32; +} + +world adder { + export add; +} \ No newline at end of file diff --git a/component-model/examples/tutorial/wit/adder/wit.toml b/component-model/examples/tutorial/wit/adder/wit.toml new file mode 100644 index 00000000..9f7a875c --- /dev/null +++ b/component-model/examples/tutorial/wit/adder/wit.toml @@ -0,0 +1 @@ +version = "0.1.0" diff --git a/component-model/examples/tutorial/wit/calculator.wit b/component-model/examples/tutorial/wit/calculator/calculator.wit similarity index 57% rename from component-model/examples/tutorial/wit/calculator.wit rename to component-model/examples/tutorial/wit/calculator/calculator.wit index 6586f9a6..98dc8d26 100644 --- a/component-model/examples/tutorial/wit/calculator.wit +++ b/component-model/examples/tutorial/wit/calculator/calculator.wit @@ -1,4 +1,4 @@ -package bytecode-alliance:calculator@0.1.0; +package component-book:calculator@0.1.0; interface calculate { enum op { @@ -7,17 +7,10 @@ interface calculate { eval-expression: func(op: op, x: u32, y: u32) -> u32; } -interface add { - add: func(a: u32, b: u32) -> u32; -} - -world adder { - export add; -} world calculator { + import component-book:adder/add@0.1.0; export calculate; - import add; } world app { diff --git a/component-model/examples/tutorial/wit/calculator/wit.lock b/component-model/examples/tutorial/wit/calculator/wit.lock new file mode 100644 index 00000000..7ebf4d6d --- /dev/null +++ b/component-model/examples/tutorial/wit/calculator/wit.lock @@ -0,0 +1,11 @@ +# This file is automatically generated by wit. +# It is not intended for manual editing. +version = 1 + +[[package]] +name = "component-book:adder" + +[[package.version]] +requirement = "^0.1.0" +version = "0.1.0" +digest = "sha256:6e82c02aac69186d371c2324e6c266a5b03a0a45015980a063e48bd56fe46f66" diff --git a/component-model/examples/tutorial/wit/calculator/wit.toml b/component-model/examples/tutorial/wit/calculator/wit.toml new file mode 100644 index 00000000..e595dda9 --- /dev/null +++ b/component-model/examples/tutorial/wit/calculator/wit.toml @@ -0,0 +1,4 @@ +version = "0.1.0" + +[dependencies] +"component-book:adder" = "0.1.0" diff --git a/component-model/examples/tutorial/wit/local/adder.wit b/component-model/examples/tutorial/wit/local/adder.wit new file mode 100644 index 00000000..2696f24e --- /dev/null +++ b/component-model/examples/tutorial/wit/local/adder.wit @@ -0,0 +1,9 @@ +package component-book:adder@0.1.0; + +interface add { + add: func(a: u32, b: u32) -> u32; +} + +world adder { + export add; +} \ No newline at end of file diff --git a/component-model/examples/tutorial/wit/local/calculator.wit b/component-model/examples/tutorial/wit/local/calculator.wit new file mode 100644 index 00000000..98dc8d26 --- /dev/null +++ b/component-model/examples/tutorial/wit/local/calculator.wit @@ -0,0 +1,18 @@ +package component-book:calculator@0.1.0; + +interface calculate { + enum op { + add, + } + eval-expression: func(op: op, x: u32, y: u32) -> u32; +} + + +world calculator { + import component-book:adder/add@0.1.0; + export calculate; +} + +world app { + import calculate; +} diff --git a/component-model/src/creating-and-consuming/composing.md b/component-model/src/creating-and-consuming/composing.md index e7d59f95..d4f061c2 100644 --- a/component-model/src/creating-and-consuming/composing.md +++ b/component-model/src/creating-and-consuming/composing.md @@ -17,8 +17,8 @@ When you compose components, you wire up the imports of one "primary" component For example, consider the following WIT packages and components ```wit -// component `bytecode-alliance:validator-impl` -package bytecode-alliance:validator@0.1.0; +// component `component-book:validator-impl` +package component-book:validator@0.1.0; interface validation { validate-text: func(text: string) -> string; @@ -26,11 +26,11 @@ interface validation { world validator-world { export validator; - import bytecode-alliance:regex/match@0.1.0; + import component-book:regex/match@0.1.0; } -// component 'bytecode-alliance:regex-impl' -package bytecode-alliance:regex@0.1.0; +// component 'component-book:regex-impl' +package component-book:regex@0.1.0; interface match { first-match: func(regex: string, text: string) -> string; @@ -41,16 +41,17 @@ world regex-world { } ``` -Here we have two WIT packages, `bytecode-alliance:validator` and `bytecode-alliance:regex`. The component `bytecode-alliance:validator-impl` implements the world `bytecode-alliance:validator/validator-world` and the component `bytecode-alliance:regex-impl` implements the world `bytecode-alliance:regex/regex-world`, each of which could have been written in any guest language that targets the component model. +Here we have two WIT packages, `component-book:validator` and `component-book:regex`. The component `component-book:validator-impl` implements the world `component-book:validator/validator-world` and the component `component-book:regex-impl` implements the world `component-book:regex/regex-world`, each of which could have been written in any guest language that targets the component model. + +You can think of the components that people author as having their shape described by a world defined in a WIT package. Since worlds import and export interfaces, and components implement worlds, when we author a component, we don't specify which implementations we're importing, but just the interfaces from the world we're targeting. When performing composition, we are specifying which concrete implementation of each imported interface we want to use for a specific implementation. When we compose components together, we are specifying which *instance* of an imported interface we want our components to use. -If we compose `bytecode-alliance:validator-impl` with `bytecode-alliance:regex-impl`, `bytecode-alliance:validator-impl`'s import of the `bytecode-alliance:regex/match@0.1.0` interface is wired up to `bytecode-alliance:regex-impl`'s export of `match`. The net result is that the composed component exports an instance of the `bytecode-alliance:validator/validation@0.1.0` interface, and has no imports. The composed component does _not_ export `bytecode-alliance:regex/match@0.1.0` - that has become an internal implementation detail of the composed component. +If we compose `component-book:validator-impl` with `component-book:regex-impl`, `component-book:validator-impl`'s import of the `component-book:regex/match@0.1.0` interface is wired up to `component-book:regex-impl`'s export of `match`. The net result is that the composed component exports an instance of the `component-book:validator/validation@0.1.0` interface, and has no imports. The composed component does _not_ export `component-book:regex/match@0.1.0` - that has become an internal implementation detail of the composed component. Component composition tools are in their early stages right now. Here are some tips to avoid or diagnose errors: -* Composition happens at the level of interfaces. If the initial component directly imports functions, then composition will fail. If composition reports an error such as "component `path/to/component` has a non-instance import named ``" then check that all imports and exports are defined by interfaces. -* Composition is asymmetrical. It is not just "gluing components together" - it takes a primary component which has imports, and satisfies its imports using dependency components. For example, composing an implementation of `validator` with an implementation of `regex` makes sense because `validator` has a dependency that `regex` can satisfy; doing it the other way round doesn't work, because `regex` doesn't have any dependencies, let alone ones that `validator` can satisfy. +* Compositions will fail unless the imported/exported types correspond! A component must export an interface that another component imports in order for the composition to succeed. The name of the interface is not enough... the types defined in it must also match the expected types * Composition cares about interface versions, and current tools are inconsistent about when they infer or inject versions. For example, if a Rust component exports `test:mypackage`, `cargo component build` will decorate this with the crate version, e.g. `test:mypackage@0.1.0`. If another Rust component _imports_ an interface from `test:mypackage`, that won't match `test:mypackage@0.1.0`. You can use [`wasm-tools component wit`](https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wit-component) to view the imports and exports embedded in the `.wasm` files and check whether they match up. ## Composing components with `wasm-tools` @@ -91,23 +92,12 @@ The example composition described above could be created with the `wac` file bel ``` //composition.wac -package bytecode-alliance:composition; +package component-book:composition; -let regex = new bytecode-alliance:regex-impl { ... }; -let validator = new bytecode-alliance:validator-impl { "bytecode-alliance:regex/match": regex.match, ... }; +let regex = new component-book:regex-impl { ... }; +let validator = new component-book:validator-impl { "component-book:regex/match": regex.match, ... }; export validator...; ``` -The `new` keyword here is used to create an instance of a component, namely `bytecode-alliance:regex-impl` and `bytecode-alliance:validator-impl` are instantiated (with instance names`regex` and `validator`) that target the `bytecode-alliance:validator/validator-world` and `bytecode-alliance:regex/regex-world` worlds respectively. - -When we instantiate the component `bytecode-alliance:validator-impl`, since its world targets `bytecode-alliance:validotor/validator-world` which imports the `bytecode-alliance:regex/match` interface, we need to specify which instance of that interface we want. We can use the syntax `regex.match` here to say we want the one from the `regex` instance we got from instantiating `bytecodealliance:regex-impl`. - -One of the nice features of composing this way, is that if you had two components that share a dependency on another component, but you don't want them to depend on the same instance, then you could create two separate instances for each of them to depend on. - -You may also be wondering what's up with the `...` syntax. It's common for components to import functionality from their host/runtime, like `wasi:filesystem` or `wasi:http` for example. The `...` syntax is how we pass that functionality along to all of the components that comprise the composition we're authoring. - -The components that you use in your composition can either be referenced from a registry or from a local file system. There are a few ways to configure where you want your dependencies to live in a local setup, which are described in the [wac repo](https://github.com/bytecodealliance/wac#dependencies). - -With all that, we can just run `wac encode composition.wac -o composition.wasm` and it will spit out a component that is runnable. - +For an in depth description about how to use the wac tool, you can check out the [language guide](https://github.com/bytecodealliance/wac/blob/main/LANGUAGE.md) \ No newline at end of file diff --git a/component-model/src/creating-and-consuming/distributing.md b/component-model/src/creating-and-consuming/distributing.md index f9296c70..0f3f3dd9 100644 --- a/component-model/src/creating-and-consuming/distributing.md +++ b/component-model/src/creating-and-consuming/distributing.md @@ -6,10 +6,10 @@ Today, the primary way to distribute components is via [OCI](https://opencontain ## Using Warg registries for WIT packages with the `wit` CLI -One of the primary use cases of a Warg registry is publishing and downloading WIT packages. The easiest way to create and use WIT packages is with the [wit](https://github.com/bytecodealliance/cargo-component/tree/main/crates/wit) CLI. After installing the CLI, you can start a project by simply typing `wit init`, and then writing any valid WIT file. If you want your WIT package to reference an interface defined in another WIT package, simply use `wit add :/`. You can produce a binary whenever you're finished authoring your package, via `wit build`, and can publish to a registry via `wit publish`. +One of the primary use cases of a Warg registry is publishing and downloading WIT packages. The easiest way to create and use WIT packages is with the [wit](https://github.com/bytecodealliance/cargo-component/tree/main/crates/wit) CLI. After installing the CLI, you can use it to create WIT packages that depend on other packages in a registry, as well as to build a final binary and publish the result to a registry -## Using Warg registries to author and distribute rust components -Another tool that is set up to interact with warg registries is `cargo-component`. You can read about how to build and use published packages in your rust projects in the [rust](../language-support/rust.md) section. +## Using Warg registries to author and distribute components +Another tool that is set up to interact with warg registries is `cargo-component`. You can read about how to build and use published packages in your rust projects in the [rust](../language-support/rust.md) section. Components authored with other tools and languages can also be published to the registry, but have less support for importing/exporting functionality between components today. In general, given a .wasm binary, you can always publish and download using the [warg cli](https://github.com/bytecodealliance/registry?tab=readme-ov-file#installation) ## Using Warg registries in your component compositions -The `wac` CLI is yet another tool with warg registry integration. Learn more about how to use registries and wac in the [composition](./composing.md#composing-components-with-the-wac-cli) section. +The `wac` CLI is yet another tool with warg registry integration. Learn more about how to use registries when you compose components in the [composition](./composing.md#composing-components-with-the-wac-cli) section. diff --git a/component-model/src/language-support/go.md b/component-model/src/language-support/go.md index 4f2b7a10..2ec829a9 100644 --- a/component-model/src/language-support/go.md +++ b/component-model/src/language-support/go.md @@ -152,7 +152,7 @@ world](https://github.com/bytecodealliance/component-docs/tree/main/component-mo For this example, we will use the following world, which moves the add function behind an `add` interface: ```wit -package bytecode-alliance:adder@0.1.0; +package component-book:adder@0.1.0; interface add { add: func(a: u32, b: u32) -> u32; @@ -201,7 +201,7 @@ gen ``` The `adder.go` file defines an `ExportsDocsAdder0_1_0_Add` interface that matches the structure of our `add` -interface. The name of the interface is taken from the WIT package name (`bytecode-alliance:adder@0.1.0`) combined with the interface name (`add`). In our Go module, first implement the `ExportsDocsAdder0_1_0_Add` interface by defining the `Add` function. +interface. The name of the interface is taken from the WIT package name (`component-book:adder@0.1.0`) combined with the interface name (`add`). In our Go module, first implement the `ExportsDocsAdder0_1_0_Add` interface by defining the `Add` function. ```go package main @@ -283,6 +283,6 @@ world root { import wasi:filesystem/types@0.2.0; import wasi:filesystem/preopens@0.2.0; - export bytecode-alliance:adder/add@0.1.0; + export component-book:adder/add@0.1.0; } ``` diff --git a/component-model/src/language-support/rust.md b/component-model/src/language-support/rust.md index 1c30a53c..12383715 100644 --- a/component-model/src/language-support/rust.md +++ b/component-model/src/language-support/rust.md @@ -84,7 +84,7 @@ $ cargo run --release -- 1 2 ../add/target/wasm32-wasi/release/add.wasm The [sample `add.wit` file](https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/example-host/add.wit) exports a function. However, to use your component from another component, it must export an interface. This results in slightly fiddlier bindings. For example, to implement the following world: ```wit -package bytecode-alliance:adder@0.1.0; +package component-book:adder@0.1.0; interface add { add: func(a: u32, b: u32) -> u32; @@ -100,7 +100,7 @@ you would write the following Rust code: ```rust mod bindings; // Separating out the interface puts it in a sub-module -use bindings::exports::bytecode-alliance::calculator::add::Guest; +use bindings::exports::bytecode_alliance::calculator::add::Guest; struct Component; @@ -111,6 +111,11 @@ impl Guest for Component { } ``` +## Exporting an interface from a registry with `cargo component` +If you know of a WIT package that has been published to the registry that defines a world, you can also create a library that targets that world specifically. We've gone ahead and published [adder](https://preview.wa.dev/component-book:adder) for reference. You can generate a scaffolding for a rust implementation of a world by running `cargo component new --lib --target :/ `. In our case, this translates to `cargo component new --lib --target component-book:adder/adder adder`. + +Note that when creating a component this way, you'll have no wit file that you can edit, as you're using the types defined in the published version of the WIT package. So if you're still working through what you want your types and function signatures to be, you're probably better off starting with a local WIT package rather than one from the registry. + ## 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. @@ -125,49 +130,34 @@ For example, suppose you have created and built an adder component as explained // in the 'calculator' project // wit/world.wit -package bytecode-alliance:calculator; +package component-book:calculator@0.1.0; interface calculate { - eval-expression: func(expr: string) -> u32; + enum op { + add, + } + eval-expression: func(op: op, x: u32, y: u32) -> u32; } world calculator { export calculate; - import bytecode-alliance:adder/add@0.1.0; + import component-book:adder/add0.1.0; } ``` ### Referencing the package to import -Because the `bytecode-alliance:adder` package is in a different project, we must first tell `cargo component` how to find it. To do this, add the following to the `Cargo.toml` file: +If you used the registry to target a specific world, then `cargo component` will have already resolved your types for you, and you can skip this step. + +Because the `component-book:adder` package is in a different project, we must first tell `cargo component` how to find it. To do this, add the following to the `Cargo.toml` file: ```toml [package.metadata.component.target.dependencies] -"bytecode-alliance:adder" = { path = "../adder/wit" } # directory containing the WIT package +"component-book:adder" = { path = "../adder/wit" } # directory containing the WIT package ``` 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. -### Using published WIT packages in a registry - -Since `cargo component` is integrated with the Warg protocol, you can also interact with WIT packages that have been published to a [Warg registry](/../creating-and-consuming/distributing.md). - -To create a component that targets a world in a WIT package, simply run - -``` -cargo component new --lib --target :/ path/to/library -``` - -Both the [calculator](https://preview.wa.dev/bytecode-alliance:calculator) and [adder](https://preview.wa.dev/bytecode-alliance:adder) packages have been published to wa.dev, so the following commands will create rust projects with the needed implementations for the WIT packages scaffolded out for you. - - -``` -cargo component new --lib --target bytecode-alliance:calculator/calculator calculator -cargo component new --lib --target bytecode-alliance:adder/adder adder -``` - -Since this flow uses WIT packages from a registry, this approach doesn't need the prior step for pointing to a local WIT package. - ### Calling the import from Rust Now the declaration of `add` in the adder's WIT file is visible to the `calculator` project. To invoke the imported `add` interface from the `calculate` implementation: @@ -176,18 +166,18 @@ Now the declaration of `add` in the adder's WIT file is visible to the `calculat // src/lib.rs mod bindings; -use bindings::exports::bytecode_alliance::calculator::calculate::Guest; +use bindings::exports::component_book::calculator::calculate::{Guest, Op}; // Bring the imported add function into scope -use bindings::bytecode_alliance::calculator::add::add; +use bindings::component_book::calculator::add::add; struct Component; impl Guest for Component { - fn eval_expression(expr: String) -> u32 { - // Cleverly parse `expr` into values and operations, and evaluate - // them meticulously. - add(123, 456) + fn eval_expression(op: Op, x: u32, y: u32) -> u32 { + match op { + Op::Add => add(x, y), + } } } ``` @@ -204,22 +194,22 @@ $ wasm-tools component wit ./target/wasm32-wasi/release/calculator.wasm package root:component; world root { - import bytecode-alliance:adder/add@0.1.0; + import component-book:adder/add@0.1.0; - export bytecode-alliance:calculator/calculate@0.1.0; + export component-book:calculator/calculate@0.1.0; } ``` 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), or use the [wac CLI](../creating-and-consuming/composing.md#composing-components-with-the-wac-cli). -If you use the wac CLI, the following wac file would grab the bytecode alliance components ([adder-component](https://preview.wa.dev/bytecode-alliance:adder-component) and [calculator-component](https://preview.wa.dev/bytecode-alliance:calculator-component)) that implement each of the WIT interfaces ([adder](https://preview.wa.dev/bytecode-alliance:adder) and [calculator](https://preview.wa.dev/bytecode-alliance:calculator)). +If you use the wac CLI, the following wac file would grab the bytecode alliance components ([adder-component](https://preview.wa.dev/component-book:adder-component) and [calculator-component](https://preview.wa.dev/component-book:calculator-component)) that implement each of the WIT interfaces ([adder](https://preview.wa.dev/component-book:adder) and [calculator](https://preview.wa.dev/component-book:calculator)). ``` // composition.wac -package bytecode-alliance:composition; +package component-book:composition; -let adder = new bytecode-alliance:adder-component{ ... }; -let calc = new bytecode-alliance:calculator-component { "bytecode-alliance:adder/add@0.1.0": adder.add, ... }; +let adder = new component-book:adder-component{ ... }; +let calc = new component-book:calculator-component { "component-book:adder/add@0.1.0": adder.add, ... }; export calc...; ``` @@ -264,14 +254,14 @@ As mentioned above, `cargo component build` doesn't generate a WIT file for a co 1. Add a `wit/world.wit` to your project, and write a WIT world that imports the interface(s) you want to use. For example: ```wit -package bytecode-alliance:app; +package component-book:app; world app { - import bytecode-alliance:calculator/calculate@0.1.0; + import component-book:calculator/calculate@0.1.0; } ``` -> `cargo component` sometimes fails to find packages if versions are not set explicitly. For example, if the calculator WIT declares `package bytecode-alliance:calculator` rather than `bytecode-alliance:calculator@0.1.0`, then you may get an error even though `cargo component build` automatically versions the binary export. +> `cargo component` sometimes fails to find packages if versions are not set explicitly. For example, if the calculator WIT declares `package component-book:calculator` rather than `component-book:calculator@0.1.0`, then you may get an error even though `cargo component build` automatically versions the binary export. 2. Edit `Cargo.toml` to tell `cargo component` about the new WIT file: @@ -286,23 +276,23 @@ path = "wit" ```toml [package.metadata.component.target.dependencies] -"bytecode-alliance:calculator" = { path = "../calculator/wit" } -"bytecode-alliance:adder" = { path = "../adder/wit" } +"component-book:calculator" = { path = "../calculator/wit" } +"component-book:adder" = { path = "../adder/wit" } ``` -Alternatively, if you're using the registry packages, you can use the latest versions published instead of a path. You can find the versions on the registry pages, ([calculator](https://preview.wa.dev/bytecode-alliance:calculator) and [adder](https://preview.wa.dev/bytecode-alliance:adder)) +Alternatively, if you're using the registry packages, you can use the latest versions published instead of a path. You can find the versions on the registry pages, ([calculator](https://preview.wa.dev/component-book:calculator) and [adder](https://preview.wa.dev/component-book:adder)) ```toml [package.metadata.component.target.dependencies] -"bytecode-alliance:calculator" = "x.x.x" -"bytecode-alliance:adder" = "x.x.x" +"component-book:calculator" = "x.x.x" +"component-book:adder" = "x.x.x" ``` > If the external package refers to other packages, you need to provide the paths to them as well. 4. Use the imported interface in your Rust code: ```rust -use bindings::bytecode-alliance::calculator::calculate::eval_expression; +use bindings::component-book::calculator::calculate::eval_expression; fn main() { let result = eval_expression("1 + 1"); diff --git a/component-model/src/tutorial.md b/component-model/src/tutorial.md index 8d0eaef8..1f1b9e46 100644 --- a/component-model/src/tutorial.md +++ b/component-model/src/tutorial.md @@ -15,8 +15,10 @@ Wasm components, we will compose them into a single runnable component, and test ## The calculator interface -For tutorial purposes, we are going to define all our interfaces in one WIT package (in fact, one -`.wit` file). This file defines: + +For tutorial purposes, we are going to define all our interfaces in 2 separate wit files because in a real world use case a component is granular and will have its own wit file. +These files are `adder.wit` and `calculator.wit`. These files define: * An interface for the calculator itself. We'll use this later to carry out calculations. It contains an evaluate function, and an enum that delineates the operations that can be involved in @@ -33,16 +35,15 @@ For tutorial purposes, we are going to define all our interfaces in one WIT pack the component will take in command line arguments and pass them to the "eval-expression" function of the calculator component. -```wit -// calculator.wit -package bytecode-alliance:calculator@0.1.0; +The first file is for the `component-book:adder` package and contains: -interface calculate { - enum op { - add, - } - eval-expression: func(op: op, x: u32, y: u32) -> u32; -} +* An "add" interface that other wit packages and components can import or export + +* An "adder" world that can be targeted by components that implement it + +```wit +//adder.wit +package component-book:adder@0.1.0; interface add { add: func(a: u32, b: u32) -> u32; @@ -51,10 +52,30 @@ interface add { world adder { export add; } +``` + +The second file is for the `component-book:calculator` package and contains: + +* The "calculate" interface that other wit packages and components can import or export + +* The "calculator" world that can be targeted by components that implement it. Note that this imports the "add" interface defined in the previous WIT package. + +* The "app" world that can be targeted by components that implement it. + +```wit +// calculator.wit +package component-book:calculator@0.1.0; + +interface calculate { + enum op { + add, + } + eval-expression: func(op: op, x: u32, y: u32) -> u32; +} world calculator { export calculate; - import add; + import component-book:adder/add@0.1.0; } world app { @@ -63,14 +84,20 @@ world app { ``` -If you're using rust and you want to learn how to use a registry instead, you can use the WIT packages that have been published for this tutorial ([calculator](https://preview.wa.dev/bytecode-alliance:calculator) and [adder](https://preview.wa.dev/bytecode-alliance:adder)) or publish the same packages on your own namespace using the [wit CLI](./creating-and-consuming/distributing.md#using-warg-registries-for-wit-packages-with-the-wit-cli) +It is not uncommon for many WIT packages to be published on a registry, indicating that there are a variety of implementors of the worlds they define. If you haven't encountered sharing types across WIT packages before, they're briefly covered in the [composition section](./creating-and-consuming/composing.md) + +You'll notice in the [wit examples](https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/tutorial/wit) that we have definitions in the `local` folder that resolve packages locally, as well as packages that were authored using the [wit](https://github.com/bytecodealliance/cargo-component/tree/main/crates/wit) CLI, which resolves packages using the registry. + +If you're using rust and you want to learn how to use a registry instead of the local files, you can use the WIT packages that have been published for this tutorial ([calculator](https://preview.wa.dev/component-book:calculator) and [adder](https://preview.wa.dev/component-book:adder)) or publish the same packages on your own namespace using the [wit CLI](./creating-and-consuming/distributing.md#using-warg-registries-for-wit-packages-with-the-wit-cli) + + ## Create an `add` component Reference the [language guide](language-support.md) and [authoring components documentation](creating-and-consuming/authoring.md) to create a component that implements the `adder` world of `calculator.wit`. For reference, see the completed -[example](https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/tutorial/adder/). If using the registry, this will use the [adder](https://preview.wa.dev/bytecode-alliance:adder) WIT package. +[example](https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/tutorial/adder/). If using the registry, this will use the [adder](https://preview.wa.dev/component-book:adder) WIT package. ## Create a `calculator` component @@ -90,7 +117,7 @@ with a `main` function to a component with `wasi:cli/run` exported. Scaffold a n with a `command` component: ```sh -cargo component new +cargo component new ``` This component will implement the [`app`](https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/tutorial/wit/calculator.wit) world, which @@ -103,13 +130,14 @@ path = "../path/to/calculator.wit" world = "app" ``` -If you're using the registry, you can specify the import. +If you're using the registry, you can specify the target world. ``` -[package.metadata.component.target.dependencies] -"bytecode-alliance:calculator" = "x.x.x" +[package.metadata.component] +package = "component-book:command-impl" +target = "component-book:calculator/app@0.1.0" ``` -Check [calculator](https://preview.wa.dev/bytecode-alliance:calculator) for the latest version to use. +Check [calculator](https://preview.wa.dev/component-book:calculator) for the latest version to use. Now, implement a command line application that: @@ -132,8 +160,14 @@ wasm-tools compose calculator.wasm -d adder.wasm -o composed.wasm wasm-tools compose command.wasm -d composed.wasm -o final.wasm ``` -You can also use the [wac](https://github.com/bytecodealliance/wac) CLI to compose these components together. -Check out the [docs](./creating-and-consuming/composing.md#composing-components-with-the-wac-cli) for information on how. +You can also use the [wac](https://github.com/bytecodealliance/wac) CLI to compose these components together, and use components that are fetched from the registry. + +```sh +wac plug component-book:calculator-impl --plug component-book:adder-impl -o composed.wasm +wac plug component-book:command-impl --plug ./composed.wasm -o final.wasm +``` + +The above command pulls implemented components from the registry, but you can also publish your own components to the registry and use wac to compose those instead! > If you'd prefer to take a more visual approach to composing components, see the [documentation on > composing components with From 5d60c5abbddf24967caf76e7e75c08627dc23719 Mon Sep 17 00:00:00 2001 From: Daniel Macovei Date: Tue, 21 May 2024 11:34:27 -0500 Subject: [PATCH 3/3] address comments, local and registy examples, prod components instead of preview in examples --- component-model/examples/tutorial/README.md | 17 +- .../tutorial/{ => local}/adder/Cargo.lock | 0 .../tutorial/{ => local}/adder/Cargo.toml | 4 +- .../{ => local}/adder/src/bindings.rs | 0 .../tutorial/{ => local}/adder/src/lib.rs | 0 .../{ => local}/calculator/Cargo.lock | 0 .../{ => local}/calculator/Cargo.toml | 7 +- .../{ => local}/calculator/src/bindings.rs | 0 .../{ => local}/calculator/src/lib.rs | 0 .../tutorial/{ => local}/command/Cargo.lock | 0 .../tutorial/{ => local}/command/Cargo.toml | 6 +- .../{ => local}/command/src/bindings.rs | 0 .../tutorial/{ => local}/command/src/main.rs | 0 .../registry/adder-impl/Cargo-component.lock | 11 + .../tutorial/registry/adder-impl/Cargo.lock | 25 ++ .../tutorial/registry/adder-impl/Cargo.toml | 25 ++ .../registry/adder-impl/src/bindings.rs | 166 +++++++++++ .../tutorial/registry/adder-impl/src/lib.rs | 14 + .../calculator-impl/Cargo-component.lock | 11 + .../registry/calculator-impl/Cargo.lock | 25 ++ .../registry/calculator-impl/Cargo.toml | 25 ++ .../registry/calculator-impl/src/bindings.rs | 233 ++++++++++++++++ .../registry/calculator-impl/src/lib.rs | 17 ++ .../command-impl/Cargo-component.lock | 11 + .../tutorial/registry/command-impl/Cargo.lock | 260 ++++++++++++++++++ .../tutorial/registry/command-impl/Cargo.toml | 17 ++ .../registry/command-impl/src/bindings.rs | 152 ++++++++++ .../registry/command-impl/src/main.rs | 46 ++++ .../examples/tutorial/wit/adder/wit.lock | 3 + .../examples/tutorial/wit/calculator/wit.lock | 2 +- .../src/creating-and-consuming/composing.md | 40 +-- .../creating-and-consuming/distributing.md | 2 +- component-model/src/language-support/rust.md | 9 +- component-model/src/tutorial.md | 18 +- 34 files changed, 1085 insertions(+), 61 deletions(-) rename component-model/examples/tutorial/{ => local}/adder/Cargo.lock (100%) rename component-model/examples/tutorial/{ => local}/adder/Cargo.toml (81%) rename component-model/examples/tutorial/{ => local}/adder/src/bindings.rs (100%) rename component-model/examples/tutorial/{ => local}/adder/src/lib.rs (100%) rename component-model/examples/tutorial/{ => local}/calculator/Cargo.lock (100%) rename component-model/examples/tutorial/{ => local}/calculator/Cargo.toml (69%) rename component-model/examples/tutorial/{ => local}/calculator/src/bindings.rs (100%) rename component-model/examples/tutorial/{ => local}/calculator/src/lib.rs (100%) rename component-model/examples/tutorial/{ => local}/command/Cargo.lock (100%) rename component-model/examples/tutorial/{ => local}/command/Cargo.toml (71%) rename component-model/examples/tutorial/{ => local}/command/src/bindings.rs (100%) rename component-model/examples/tutorial/{ => local}/command/src/main.rs (100%) create mode 100644 component-model/examples/tutorial/registry/adder-impl/Cargo-component.lock create mode 100644 component-model/examples/tutorial/registry/adder-impl/Cargo.lock create mode 100644 component-model/examples/tutorial/registry/adder-impl/Cargo.toml create mode 100644 component-model/examples/tutorial/registry/adder-impl/src/bindings.rs create mode 100644 component-model/examples/tutorial/registry/adder-impl/src/lib.rs create mode 100644 component-model/examples/tutorial/registry/calculator-impl/Cargo-component.lock create mode 100644 component-model/examples/tutorial/registry/calculator-impl/Cargo.lock create mode 100644 component-model/examples/tutorial/registry/calculator-impl/Cargo.toml create mode 100644 component-model/examples/tutorial/registry/calculator-impl/src/bindings.rs create mode 100644 component-model/examples/tutorial/registry/calculator-impl/src/lib.rs create mode 100644 component-model/examples/tutorial/registry/command-impl/Cargo-component.lock create mode 100644 component-model/examples/tutorial/registry/command-impl/Cargo.lock create mode 100644 component-model/examples/tutorial/registry/command-impl/Cargo.toml create mode 100644 component-model/examples/tutorial/registry/command-impl/src/bindings.rs create mode 100644 component-model/examples/tutorial/registry/command-impl/src/main.rs create mode 100644 component-model/examples/tutorial/wit/adder/wit.lock diff --git a/component-model/examples/tutorial/README.md b/component-model/examples/tutorial/README.md index 14db75ce..fa5ccca6 100644 --- a/component-model/examples/tutorial/README.md +++ b/component-model/examples/tutorial/README.md @@ -1,7 +1,7 @@ # Building a Calculator of Wasm Components This tutorial walks through how to compose a component to build a Wasm calculator. -It is a rich example of using multiple components, targeting distinct worlds described across multiple WIT packages +This example uses multiple components that target distinct worlds defined across multiple WIT packages. The first package consists of addition operations @@ -18,8 +18,8 @@ world adder { } ``` -The WIT package for the calculator consists of a world for each mathematical operator -add an `op` enum that delineates each operator. The following example interface only +The second WIT package defines the calculator which consists of a world for each mathematical operator +and an `op` enum that delineates each operator. The following example interface only has an `add` operation: ```wit @@ -42,20 +42,21 @@ To expand the exercise to add more components, add another operator world, expan ## Building and running the example -To compose a calculator component with an add operator, run the following: +To compose a calculator component with an add operator, you'll first need to install [wac](https://github.com/bytecodealliance/wac), and then you can run the following: ```sh (cd calculator && cargo component build --release) (cd adder && cargo component build --release) (cd command && cargo component build --release) -wasm-tools compose calculator/target/wasm32-wasi/release/calculator.wasm -d adder/target/wasm32-wasi/release/adder.wasm -o composed.wasm -wasm-tools compose command/target/wasm32-wasi/release/command.wasm -d composed.wasm -o command.wasm +wac plug local/calculator/target/wasm32-wasi/release/calculator.wasm --plug local/adder/target/wasm32-wasi/release/adder.wasm -o composed.wasm +wac plug command/target/wasm32-wasi/release/command.wasm --plug composed.wasm -o command.wasm ``` -You can also use `wac` instead of `wasm-tools compose` if you would like to fetch these components from a registry instead: +For the `wac` commands, if you'd like to fetch example components from the registry for your composition, you can use the following instead: ``` -wac plug component-book:calculator-impl --plug component-book:adder-impl -o composed.wasm && wac plug component-book:command-impl --plug ./composed.wasm -o command.wasm +wac plug component-book:calculator-impl --plug component-book:adder-impl -o composed.wasm +wac plug component-book:command-impl --plug ./composed.wasm -o command.wasm ``` Now, run the component with wasmtime: diff --git a/component-model/examples/tutorial/adder/Cargo.lock b/component-model/examples/tutorial/local/adder/Cargo.lock similarity index 100% rename from component-model/examples/tutorial/adder/Cargo.lock rename to component-model/examples/tutorial/local/adder/Cargo.lock diff --git a/component-model/examples/tutorial/adder/Cargo.toml b/component-model/examples/tutorial/local/adder/Cargo.toml similarity index 81% rename from component-model/examples/tutorial/adder/Cargo.toml rename to component-model/examples/tutorial/local/adder/Cargo.toml index daa9aead..c69f9be5 100644 --- a/component-model/examples/tutorial/adder/Cargo.toml +++ b/component-model/examples/tutorial/local/adder/Cargo.toml @@ -11,10 +11,10 @@ wit-bindgen-rt = { version = "0.24.0", features = ["bitflags"] } crate-type = ["cdylib"] [package.metadata.component] -package = "component-book:calculator" +package = "component-book:adder-impl" [package.metadata.component.target] -path = "../wit/adder/adder.wit" +path = "../../wit/local/adder.wit" world = "adder" [package.metadata.component.dependencies] diff --git a/component-model/examples/tutorial/adder/src/bindings.rs b/component-model/examples/tutorial/local/adder/src/bindings.rs similarity index 100% rename from component-model/examples/tutorial/adder/src/bindings.rs rename to component-model/examples/tutorial/local/adder/src/bindings.rs diff --git a/component-model/examples/tutorial/adder/src/lib.rs b/component-model/examples/tutorial/local/adder/src/lib.rs similarity index 100% rename from component-model/examples/tutorial/adder/src/lib.rs rename to component-model/examples/tutorial/local/adder/src/lib.rs diff --git a/component-model/examples/tutorial/calculator/Cargo.lock b/component-model/examples/tutorial/local/calculator/Cargo.lock similarity index 100% rename from component-model/examples/tutorial/calculator/Cargo.lock rename to component-model/examples/tutorial/local/calculator/Cargo.lock diff --git a/component-model/examples/tutorial/calculator/Cargo.toml b/component-model/examples/tutorial/local/calculator/Cargo.toml similarity index 69% rename from component-model/examples/tutorial/calculator/Cargo.toml rename to component-model/examples/tutorial/local/calculator/Cargo.toml index 7fe5ea44..5f9f5a7e 100644 --- a/component-model/examples/tutorial/calculator/Cargo.toml +++ b/component-model/examples/tutorial/local/calculator/Cargo.toml @@ -9,12 +9,13 @@ wit-bindgen-rt = { version = "0.24.0", features = ["bitflags"] } [lib] crate-type = ["cdylib"] + [package.metadata.component] -package = "docs:calculator" +package = "component-book:calculator-impl" [package.metadata.component.target.dependencies] -"docs:adder" = { path = "../wit/local/adder.wit" } +"component-book:adder" = { path = "../../wit/local/adder.wit" } [package.metadata.component.target] -path = "../wit/local/calculator.wit" +path = "../../wit/local/calculator.wit" world = "calculator" diff --git a/component-model/examples/tutorial/calculator/src/bindings.rs b/component-model/examples/tutorial/local/calculator/src/bindings.rs similarity index 100% rename from component-model/examples/tutorial/calculator/src/bindings.rs rename to component-model/examples/tutorial/local/calculator/src/bindings.rs diff --git a/component-model/examples/tutorial/calculator/src/lib.rs b/component-model/examples/tutorial/local/calculator/src/lib.rs similarity index 100% rename from component-model/examples/tutorial/calculator/src/lib.rs rename to component-model/examples/tutorial/local/calculator/src/lib.rs diff --git a/component-model/examples/tutorial/command/Cargo.lock b/component-model/examples/tutorial/local/command/Cargo.lock similarity index 100% rename from component-model/examples/tutorial/command/Cargo.lock rename to component-model/examples/tutorial/local/command/Cargo.lock diff --git a/component-model/examples/tutorial/command/Cargo.toml b/component-model/examples/tutorial/local/command/Cargo.toml similarity index 71% rename from component-model/examples/tutorial/command/Cargo.toml rename to component-model/examples/tutorial/local/command/Cargo.toml index f2fd8bca..7a3382ad 100644 --- a/component-model/examples/tutorial/command/Cargo.toml +++ b/component-model/examples/tutorial/local/command/Cargo.toml @@ -4,14 +4,14 @@ version = "0.1.0" edition = "2021" [package.metadata.component] -package = "component-book:calculator" +package = "component-book:command-impl" [package.metadata.component.target] -path = "../wit/local/calculator.wit" +path = "../../wit/local/calculator.wit" world = "app" [package.metadata.component.target.dependencies] -"docs:adder" = { path = "../wit/local/adder.wit" } +"component-model:adder" = { path = "../../wit/local/adder.wit" } [dependencies] anyhow = "1" diff --git a/component-model/examples/tutorial/command/src/bindings.rs b/component-model/examples/tutorial/local/command/src/bindings.rs similarity index 100% rename from component-model/examples/tutorial/command/src/bindings.rs rename to component-model/examples/tutorial/local/command/src/bindings.rs diff --git a/component-model/examples/tutorial/command/src/main.rs b/component-model/examples/tutorial/local/command/src/main.rs similarity index 100% rename from component-model/examples/tutorial/command/src/main.rs rename to component-model/examples/tutorial/local/command/src/main.rs diff --git a/component-model/examples/tutorial/registry/adder-impl/Cargo-component.lock b/component-model/examples/tutorial/registry/adder-impl/Cargo-component.lock new file mode 100644 index 00000000..efa517cb --- /dev/null +++ b/component-model/examples/tutorial/registry/adder-impl/Cargo-component.lock @@ -0,0 +1,11 @@ +# This file is automatically generated by cargo-component. +# It is not intended for manual editing. +version = 1 + +[[package]] +name = "component-book:adder" + +[[package.version]] +requirement = "^0.1.0" +version = "0.1.0" +digest = "sha256:2afffac0a89b4f6add89903754bb5a09a51378ef14f159283c1a6408abb43147" diff --git a/component-model/examples/tutorial/registry/adder-impl/Cargo.lock b/component-model/examples/tutorial/registry/adder-impl/Cargo.lock new file mode 100644 index 00000000..0099d1d0 --- /dev/null +++ b/component-model/examples/tutorial/registry/adder-impl/Cargo.lock @@ -0,0 +1,25 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adder-impl" +version = "0.1.0" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "wit-bindgen-rt" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef83e2f948056d4195b4c2a236a10378b70c8fd7501039c5a106c1a756fa7da6" +dependencies = [ + "bitflags", +] diff --git a/component-model/examples/tutorial/registry/adder-impl/Cargo.toml b/component-model/examples/tutorial/registry/adder-impl/Cargo.toml new file mode 100644 index 00000000..a22a83bf --- /dev/null +++ b/component-model/examples/tutorial/registry/adder-impl/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "adder-impl" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +wit-bindgen-rt = { version = "0.25.0", features = ["bitflags"] } + +[lib] +crate-type = ["cdylib"] + +[profile.release] +codegen-units = 1 +opt-level = "s" +debug = false +strip = true +lto = true + +[package.metadata.component] +package = "component-book:adder-impl" +target = "component-book:adder/adder@0.1.0" + +[package.metadata.component.dependencies] diff --git a/component-model/examples/tutorial/registry/adder-impl/src/bindings.rs b/component-model/examples/tutorial/registry/adder-impl/src/bindings.rs new file mode 100644 index 00000000..12c43ef3 --- /dev/null +++ b/component-model/examples/tutorial/registry/adder-impl/src/bindings.rs @@ -0,0 +1,166 @@ +// Generated by `wit-bindgen` 0.24.0. DO NOT EDIT! +// Options used: +#[allow(dead_code)] +pub mod exports { + #[allow(dead_code)] + pub mod component_book { + #[allow(dead_code)] + pub mod adder { + #[allow(dead_code, clippy::all)] + pub mod add { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::super::__link_custom_section_describing_imports; + use super::super::super::super::_rt; + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_add_cabi(arg0: i32, arg1: i32) -> i32 { + #[cfg(target_arch = "wasm32")] + _rt::run_ctors_once(); + let result0 = T::add(arg0 as u32, arg1 as u32); + _rt::as_i32(result0) + } + pub trait Guest { + fn add(a: u32, b: u32) -> u32; + } + #[doc(hidden)] + + macro_rules! __export_component_book_adder_add_0_1_0_cabi{ + ($ty:ident with_types_in $($path_to_types:tt)*) => (const _: () = { + + #[export_name = "component-book:adder/add@0.1.0#add"] + unsafe extern "C" fn export_add(arg0: i32,arg1: i32,) -> i32 { + $($path_to_types)*::_export_add_cabi::<$ty>(arg0, arg1) + } + };); + } + #[doc(hidden)] + pub(crate) use __export_component_book_adder_add_0_1_0_cabi; + } + } + } +} +mod _rt { + + #[cfg(target_arch = "wasm32")] + pub fn run_ctors_once() { + wit_bindgen_rt::run_ctors_once(); + } + + pub fn as_i32(t: T) -> i32 { + t.as_i32() + } + + pub trait AsI32 { + fn as_i32(self) -> i32; + } + + impl<'a, T: Copy + AsI32> AsI32 for &'a T { + fn as_i32(self) -> i32 { + (*self).as_i32() + } + } + + impl AsI32 for i32 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for u32 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for i16 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for u16 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for i8 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for u8 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for char { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for usize { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } +} + +/// Generates `#[no_mangle]` functions to export the specified type as the +/// root implementation of all generated traits. +/// +/// For more information see the documentation of `wit_bindgen::generate!`. +/// +/// ```rust +/// # macro_rules! export{ ($($t:tt)*) => (); } +/// # trait Guest {} +/// struct MyType; +/// +/// impl Guest for MyType { +/// // ... +/// } +/// +/// export!(MyType); +/// ``` +#[allow(unused_macros)] +#[doc(hidden)] + +macro_rules! __export_adder_impl { + ($ty:ident) => (self::export!($ty with_types_in self);); + ($ty:ident with_types_in $($path_to_types_root:tt)*) => ( + $($path_to_types_root)*::exports::component_book::adder::add::__export_component_book_adder_add_0_1_0_cabi!($ty with_types_in $($path_to_types_root)*::exports::component_book::adder::add); + ) +} +#[doc(inline)] +pub(crate) use __export_adder_impl as export; + +#[cfg(target_arch = "wasm32")] +#[link_section = "component-type:wit-bindgen:0.24.0:adder:encoded world"] +#[doc(hidden)] +pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 223] = *b"\ +\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07d\x01A\x02\x01A\x02\x01\ +B\x02\x01@\x02\x01ay\x01by\0y\x04\0\x03add\x01\0\x04\x01\x1ecomponent-book:adder\ +/add@0.1.0\x05\0\x04\x01\x20component-book:adder/adder@0.1.0\x04\0\x0b\x0b\x01\0\ +\x05adder\x03\0\0\0G\x09producers\x01\x0cprocessed-by\x02\x0dwit-component\x070.\ +202.0\x10wit-bindgen-rust\x060.24.0"; + +#[inline(never)] +#[doc(hidden)] +#[cfg(target_arch = "wasm32")] +pub fn __link_custom_section_describing_imports() { + wit_bindgen_rt::maybe_link_cabi_realloc(); +} diff --git a/component-model/examples/tutorial/registry/adder-impl/src/lib.rs b/component-model/examples/tutorial/registry/adder-impl/src/lib.rs new file mode 100644 index 00000000..d4f92564 --- /dev/null +++ b/component-model/examples/tutorial/registry/adder-impl/src/lib.rs @@ -0,0 +1,14 @@ +#[allow(warnings)] +mod bindings; + +use bindings::exports::component_book::adder::add::Guest; + +struct Component; + +impl Guest for Component { + fn add(a: u32, b: u32) -> u32 { + a + b + } +} + +bindings::export!(Component with_types_in bindings); diff --git a/component-model/examples/tutorial/registry/calculator-impl/Cargo-component.lock b/component-model/examples/tutorial/registry/calculator-impl/Cargo-component.lock new file mode 100644 index 00000000..7e8d5d03 --- /dev/null +++ b/component-model/examples/tutorial/registry/calculator-impl/Cargo-component.lock @@ -0,0 +1,11 @@ +# This file is automatically generated by cargo-component. +# It is not intended for manual editing. +version = 1 + +[[package]] +name = "component-book:calculator" + +[[package.version]] +requirement = "^0.1.0" +version = "0.1.0" +digest = "sha256:1f75d599bae47f96644c797b824de58f161e1da7e20461da4c881568b4fd6462" diff --git a/component-model/examples/tutorial/registry/calculator-impl/Cargo.lock b/component-model/examples/tutorial/registry/calculator-impl/Cargo.lock new file mode 100644 index 00000000..7a2efa78 --- /dev/null +++ b/component-model/examples/tutorial/registry/calculator-impl/Cargo.lock @@ -0,0 +1,25 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "calculator-impl" +version = "0.1.0" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef83e2f948056d4195b4c2a236a10378b70c8fd7501039c5a106c1a756fa7da6" +dependencies = [ + "bitflags", +] diff --git a/component-model/examples/tutorial/registry/calculator-impl/Cargo.toml b/component-model/examples/tutorial/registry/calculator-impl/Cargo.toml new file mode 100644 index 00000000..75b2fbf1 --- /dev/null +++ b/component-model/examples/tutorial/registry/calculator-impl/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "calculator-impl" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +wit-bindgen-rt = { version = "0.25.0", features = ["bitflags"] } + +[lib] +crate-type = ["cdylib"] + +[profile.release] +codegen-units = 1 +opt-level = "s" +debug = false +strip = true +lto = true + +[package.metadata.component] +package = "component-book:calculator-impl" +target = "component-book:calculator/calculator@0.1.0" + +[package.metadata.component.dependencies] diff --git a/component-model/examples/tutorial/registry/calculator-impl/src/bindings.rs b/component-model/examples/tutorial/registry/calculator-impl/src/bindings.rs new file mode 100644 index 00000000..82fa688b --- /dev/null +++ b/component-model/examples/tutorial/registry/calculator-impl/src/bindings.rs @@ -0,0 +1,233 @@ +// Generated by `wit-bindgen` 0.24.0. DO NOT EDIT! +// Options used: +#[allow(dead_code)] +pub mod component_book { + #[allow(dead_code)] + pub mod adder { + #[allow(dead_code, clippy::all)] + pub mod add { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + #[allow(unused_unsafe, clippy::all)] + pub fn add(a: u32, b: u32) -> u32 { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "component-book:adder/add@0.1.0")] + extern "C" { + #[link_name = "add"] + fn wit_import(_: i32, _: i32) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i32) -> i32 { + unreachable!() + } + let ret = wit_import(_rt::as_i32(&a), _rt::as_i32(&b)); + ret as u32 + } + } + } + } +} +#[allow(dead_code)] +pub mod exports { + #[allow(dead_code)] + pub mod component_book { + #[allow(dead_code)] + pub mod calculator { + #[allow(dead_code, clippy::all)] + pub mod calculate { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::super::__link_custom_section_describing_imports; + use super::super::super::super::_rt; + #[repr(u8)] + #[derive(Clone, Copy, Eq, PartialEq)] + pub enum Op { + Add, + } + impl ::core::fmt::Debug for Op { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Op::Add => f.debug_tuple("Op::Add").finish(), + } + } + } + + impl Op { + pub(crate) unsafe fn _lift(val: u8) -> Op { + if !cfg!(debug_assertions) { + return ::core::mem::transmute(val); + } + + match val { + 0 => Op::Add, + + _ => panic!("invalid enum discriminant"), + } + } + } + + #[doc(hidden)] + #[allow(non_snake_case)] + pub unsafe fn _export_eval_expression_cabi( + arg0: i32, + arg1: i32, + arg2: i32, + ) -> i32 { + #[cfg(target_arch = "wasm32")] + _rt::run_ctors_once(); + let result0 = + T::eval_expression(Op::_lift(arg0 as u8), arg1 as u32, arg2 as u32); + _rt::as_i32(result0) + } + pub trait Guest { + fn eval_expression(op: Op, x: u32, y: u32) -> u32; + } + #[doc(hidden)] + + macro_rules! __export_component_book_calculator_calculate_0_1_0_cabi{ + ($ty:ident with_types_in $($path_to_types:tt)*) => (const _: () = { + + #[export_name = "component-book:calculator/calculate@0.1.0#eval-expression"] + unsafe extern "C" fn export_eval_expression(arg0: i32,arg1: i32,arg2: i32,) -> i32 { + $($path_to_types)*::_export_eval_expression_cabi::<$ty>(arg0, arg1, arg2) + } + };); + } + #[doc(hidden)] + pub(crate) use __export_component_book_calculator_calculate_0_1_0_cabi; + } + } + } +} +mod _rt { + + pub fn as_i32(t: T) -> i32 { + t.as_i32() + } + + pub trait AsI32 { + fn as_i32(self) -> i32; + } + + impl<'a, T: Copy + AsI32> AsI32 for &'a T { + fn as_i32(self) -> i32 { + (*self).as_i32() + } + } + + impl AsI32 for i32 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for u32 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for i16 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for u16 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for i8 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for u8 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for char { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for usize { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + #[cfg(target_arch = "wasm32")] + pub fn run_ctors_once() { + wit_bindgen_rt::run_ctors_once(); + } +} + +/// Generates `#[no_mangle]` functions to export the specified type as the +/// root implementation of all generated traits. +/// +/// For more information see the documentation of `wit_bindgen::generate!`. +/// +/// ```rust +/// # macro_rules! export{ ($($t:tt)*) => (); } +/// # trait Guest {} +/// struct MyType; +/// +/// impl Guest for MyType { +/// // ... +/// } +/// +/// export!(MyType); +/// ``` +#[allow(unused_macros)] +#[doc(hidden)] + +macro_rules! __export_calculator_impl { + ($ty:ident) => (self::export!($ty with_types_in self);); + ($ty:ident with_types_in $($path_to_types_root:tt)*) => ( + $($path_to_types_root)*::exports::component_book::calculator::calculate::__export_component_book_calculator_calculate_0_1_0_cabi!($ty with_types_in $($path_to_types_root)*::exports::component_book::calculator::calculate); + ) +} +#[doc(inline)] +pub(crate) use __export_calculator_impl as export; + +#[cfg(target_arch = "wasm32")] +#[link_section = "component-type:wit-bindgen:0.24.0:calculator:encoded world"] +#[doc(hidden)] +pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 338] = *b"\ +\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xd1\x01\x01A\x02\x01\ +A\x04\x01B\x02\x01@\x02\x01ay\x01by\0y\x04\0\x03add\x01\0\x03\x01\x1ecomponent-b\ +ook:adder/add@0.1.0\x05\0\x01B\x04\x01m\x01\x03add\x04\0\x02op\x03\0\0\x01@\x03\x02\ +op\x01\x01xy\x01yy\0y\x04\0\x0feval-expression\x01\x02\x04\x01)component-book:ca\ +lculator/calculate@0.1.0\x05\x01\x04\x01*component-book:calculator/calculator@0.\ +1.0\x04\0\x0b\x10\x01\0\x0acalculator\x03\0\0\0G\x09producers\x01\x0cprocessed-b\ +y\x02\x0dwit-component\x070.202.0\x10wit-bindgen-rust\x060.24.0"; + +#[inline(never)] +#[doc(hidden)] +#[cfg(target_arch = "wasm32")] +pub fn __link_custom_section_describing_imports() { + wit_bindgen_rt::maybe_link_cabi_realloc(); +} diff --git a/component-model/examples/tutorial/registry/calculator-impl/src/lib.rs b/component-model/examples/tutorial/registry/calculator-impl/src/lib.rs new file mode 100644 index 00000000..f3bca796 --- /dev/null +++ b/component-model/examples/tutorial/registry/calculator-impl/src/lib.rs @@ -0,0 +1,17 @@ +#[allow(warnings)] +mod bindings; + +use bindings::component_book::adder::add::add; +use bindings::exports::component_book::calculator::calculate::{Guest, Op}; + +struct Component; + +impl Guest for Component { + fn eval_expression(op: Op, x: u32, y: u32) -> u32 { + match op { + Op::Add => add(x, y), + } + } +} + +bindings::export!(Component with_types_in bindings); diff --git a/component-model/examples/tutorial/registry/command-impl/Cargo-component.lock b/component-model/examples/tutorial/registry/command-impl/Cargo-component.lock new file mode 100644 index 00000000..7e8d5d03 --- /dev/null +++ b/component-model/examples/tutorial/registry/command-impl/Cargo-component.lock @@ -0,0 +1,11 @@ +# This file is automatically generated by cargo-component. +# It is not intended for manual editing. +version = 1 + +[[package]] +name = "component-book:calculator" + +[[package.version]] +requirement = "^0.1.0" +version = "0.1.0" +digest = "sha256:1f75d599bae47f96644c797b824de58f161e1da7e20461da4c881568b4fd6462" diff --git a/component-model/examples/tutorial/registry/command-impl/Cargo.lock b/component-model/examples/tutorial/registry/command-impl/Cargo.lock new file mode 100644 index 00000000..95754f04 --- /dev/null +++ b/component-model/examples/tutorial/registry/command-impl/Cargo.lock @@ -0,0 +1,260 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "clap" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "colorchoice" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" + +[[package]] +name = "command" +version = "0.1.2" +dependencies = [ + "anyhow", + "clap", + "wit-bindgen-rt", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + +[[package]] +name = "proc-macro2" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "wit-bindgen-rt" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0780cf7046630ed70f689a098cd8d56c5c3b22f2a7379bbdb088879963ff96" +dependencies = [ + "bitflags", +] diff --git a/component-model/examples/tutorial/registry/command-impl/Cargo.toml b/component-model/examples/tutorial/registry/command-impl/Cargo.toml new file mode 100644 index 00000000..2737cbb6 --- /dev/null +++ b/component-model/examples/tutorial/registry/command-impl/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "command" +version = "0.1.2" +edition = "2021" + +[package.metadata.component] +package = "component-book:command-impl" +target = "component-book:calculator/app@0.1.0" + +[package.metadata.component.dependencies] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0.83" +clap = { version = "4.3.19", features = ["derive"] } +wit-bindgen-rt = { version = "0.24.0", features = ["bitflags"] } diff --git a/component-model/examples/tutorial/registry/command-impl/src/bindings.rs b/component-model/examples/tutorial/registry/command-impl/src/bindings.rs new file mode 100644 index 00000000..7b8d98e0 --- /dev/null +++ b/component-model/examples/tutorial/registry/command-impl/src/bindings.rs @@ -0,0 +1,152 @@ +// Generated by `wit-bindgen` 0.24.0. DO NOT EDIT! +// Options used: +#[allow(dead_code)] +pub mod component_book { + #[allow(dead_code)] + pub mod calculator { + #[allow(dead_code, clippy::all)] + pub mod calculate { + #[used] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + static __FORCE_SECTION_REF: fn() = + super::super::super::__link_custom_section_describing_imports; + use super::super::super::_rt; + #[repr(u8)] + #[derive(Clone, Copy, Eq, PartialEq)] + pub enum Op { + Add, + } + impl ::core::fmt::Debug for Op { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Op::Add => f.debug_tuple("Op::Add").finish(), + } + } + } + + impl Op { + pub(crate) unsafe fn _lift(val: u8) -> Op { + if !cfg!(debug_assertions) { + return ::core::mem::transmute(val); + } + + match val { + 0 => Op::Add, + + _ => panic!("invalid enum discriminant"), + } + } + } + + #[allow(unused_unsafe, clippy::all)] + pub fn eval_expression(op: Op, x: u32, y: u32) -> u32 { + unsafe { + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "component-book:calculator/calculate@0.1.0")] + extern "C" { + #[link_name = "eval-expression"] + fn wit_import(_: i32, _: i32, _: i32) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i32, _: i32) -> i32 { + unreachable!() + } + let ret = wit_import(op.clone() as i32, _rt::as_i32(&x), _rt::as_i32(&y)); + ret as u32 + } + } + } + } +} +mod _rt { + + pub fn as_i32(t: T) -> i32 { + t.as_i32() + } + + pub trait AsI32 { + fn as_i32(self) -> i32; + } + + impl<'a, T: Copy + AsI32> AsI32 for &'a T { + fn as_i32(self) -> i32 { + (*self).as_i32() + } + } + + impl AsI32 for i32 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for u32 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for i16 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for u16 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for i8 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for u8 { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for char { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } + + impl AsI32 for usize { + #[inline] + fn as_i32(self) -> i32 { + self as i32 + } + } +} + +#[cfg(target_arch = "wasm32")] +#[link_section = "component-type:wit-bindgen:0.24.0:app:encoded world"] +#[doc(hidden)] +pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 267] = *b"\ +\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\x91\x01\x01A\x02\x01\ +A\x02\x01B\x04\x01m\x01\x03add\x04\0\x02op\x03\0\0\x01@\x03\x02op\x01\x01xy\x01y\ +y\0y\x04\0\x0feval-expression\x01\x02\x03\x01)component-book:calculator/calculat\ +e@0.1.0\x05\0\x04\x01#component-book:calculator/app@0.1.0\x04\0\x0b\x09\x01\0\x03\ +app\x03\0\0\0G\x09producers\x01\x0cprocessed-by\x02\x0dwit-component\x070.202.0\x10\ +wit-bindgen-rust\x060.24.0"; + +#[inline(never)] +#[doc(hidden)] +#[cfg(target_arch = "wasm32")] +pub fn __link_custom_section_describing_imports() { + wit_bindgen_rt::maybe_link_cabi_realloc(); +} diff --git a/component-model/examples/tutorial/registry/command-impl/src/main.rs b/component-model/examples/tutorial/registry/command-impl/src/main.rs new file mode 100644 index 00000000..9e229c3e --- /dev/null +++ b/component-model/examples/tutorial/registry/command-impl/src/main.rs @@ -0,0 +1,46 @@ +mod bindings; + +use clap::Parser; +use std::fmt; + +use bindings::component_book::calculator::{calculate, calculate::Op}; + +fn parse_operator(op: &str) -> anyhow::Result { + match op { + "add" => Ok(Op::Add), + _ => anyhow::bail!("Unknown operation: {}", op), + } +} + +impl fmt::Display for Op { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Op::Add => write!(f, "+"), + } + } +} + +/// A CLI for executing mathematical expressions +/// using WebAssembly +#[derive(Parser)] +#[clap(name = "calculator", version = env!("CARGO_PKG_VERSION"))] +struct Command { + /// The first operand + x: u32, + /// The second operand + y: u32, + /// Expression operator + #[clap(value_parser = parse_operator)] + op: Op, +} + +impl Command { + fn run(self) { + let res = calculate::eval_expression(self.op, self.x, self.y); + println!("{} {} {} = {res}", self.x, self.op, self.y); + } +} + +fn main() { + Command::parse().run() +} diff --git a/component-model/examples/tutorial/wit/adder/wit.lock b/component-model/examples/tutorial/wit/adder/wit.lock new file mode 100644 index 00000000..b7329043 --- /dev/null +++ b/component-model/examples/tutorial/wit/adder/wit.lock @@ -0,0 +1,3 @@ +# This file is automatically generated by wit. +# It is not intended for manual editing. +version = 1 diff --git a/component-model/examples/tutorial/wit/calculator/wit.lock b/component-model/examples/tutorial/wit/calculator/wit.lock index 7ebf4d6d..4d8707f0 100644 --- a/component-model/examples/tutorial/wit/calculator/wit.lock +++ b/component-model/examples/tutorial/wit/calculator/wit.lock @@ -8,4 +8,4 @@ name = "component-book:adder" [[package.version]] requirement = "^0.1.0" version = "0.1.0" -digest = "sha256:6e82c02aac69186d371c2324e6c266a5b03a0a45015980a063e48bd56fe46f66" +digest = "sha256:2afffac0a89b4f6add89903754bb5a09a51378ef14f159283c1a6408abb43147" diff --git a/component-model/src/creating-and-consuming/composing.md b/component-model/src/creating-and-consuming/composing.md index d4f061c2..dfcdb6a5 100644 --- a/component-model/src/creating-and-consuming/composing.md +++ b/component-model/src/creating-and-consuming/composing.md @@ -43,9 +43,7 @@ world regex-world { Here we have two WIT packages, `component-book:validator` and `component-book:regex`. The component `component-book:validator-impl` implements the world `component-book:validator/validator-world` and the component `component-book:regex-impl` implements the world `component-book:regex/regex-world`, each of which could have been written in any guest language that targets the component model. -You can think of the components that people author as having their shape described by a world defined in a WIT package. Since worlds import and export interfaces, and components implement worlds, when we author a component, we don't specify which implementations we're importing, but just the interfaces from the world we're targeting. When performing composition, we are specifying which concrete implementation of each imported interface we want to use for a specific implementation. - -When we compose components together, we are specifying which *instance* of an imported interface we want our components to use. +You can think of the components that people author as having their shape described by a world defined in a WIT package. Since worlds import and export interfaces, and components implement worlds, when we author a component, we don't specify which implementations we're importing, but just the interfaces from the world we're targeting. When performing a composition, we are specifying which concrete implementation will serve as an *instance* of the imported interface we want to use in our composed output. If we compose `component-book:validator-impl` with `component-book:regex-impl`, `component-book:validator-impl`'s import of the `component-book:regex/match@0.1.0` interface is wired up to `component-book:regex-impl`'s export of `match`. The net result is that the composed component exports an instance of the `component-book:validator/validation@0.1.0` interface, and has no imports. The composed component does _not_ export `component-book:regex/match@0.1.0` - that has become an internal implementation detail of the composed component. @@ -54,21 +52,23 @@ Component composition tools are in their early stages right now. Here are some * Compositions will fail unless the imported/exported types correspond! A component must export an interface that another component imports in order for the composition to succeed. The name of the interface is not enough... the types defined in it must also match the expected types * Composition cares about interface versions, and current tools are inconsistent about when they infer or inject versions. For example, if a Rust component exports `test:mypackage`, `cargo component build` will decorate this with the crate version, e.g. `test:mypackage@0.1.0`. If another Rust component _imports_ an interface from `test:mypackage`, that won't match `test:mypackage@0.1.0`. You can use [`wasm-tools component wit`](https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wit-component) to view the imports and exports embedded in the `.wasm` files and check whether they match up. -## Composing components with `wasm-tools` +## Composing components with the wac CLI -The [`wasm-tools` suite](https://github.com/bytecodealliance/wasm-tools) includes a `compose` command which can be used to compose components at the command line. +You can use the [wac](https://github.com/bytecodealliance/wac) CLI to create your composition. -To compose a component with the components it directly depends on, run: +The example composition described above could be created with the `wac` file below -```sh -wasm-tools compose path/to/component.wasm -d path/to/dep1.wasm -d path/to/dep2.wasm -o composed.wasm ``` +//composition.wac +package component-book:composition; -Here `component.wasm` is the component that imports interfaces from `dep1.wasm` and `dep2.wasm`, which export them. The composed component, with those dependencies satisfied and tucked away inside it, is saved to `composed.wasm`. +let regex = new component-book:regex-impl { ... }; +let validator = new component-book:validator-impl { "component-book:regex/match": regex.match, ... }; -> This syntax doesn't cover transitive dependencies. If, for example, `dep1.wasm` has unsatisfied imports that you want to satisfy from `dep3.wasm`, you'll need to use a [configuration file](https://github.com/bytecodealliance/wasm-tools/blob/main/crates/wasm-compose/CONFIG.md). (Or you can compose `dep1.wasm` with `dep3.wasm` first, then refer to that composed component instead of `dep1.wasm`. This doesn't scale to lots of transitive dependencies though!) +export validator...; +``` -For full information about `wasm-tools compose` including how to configure more advanced scenarios, see [the `wasm-tools compose` documentation](https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-compose). +For an in depth description about how to use the wac tool, you can check out the [wac usage guide](https://github.com/bytecodealliance/wac/blob/main/LANGUAGE.md) ## Composing components with a visual interface @@ -83,21 +83,3 @@ You can compose components visually using the builder app at https://wasmbuilder 4. To fulfil one of the primary component's imports with a dependency's export, drag from the "I" icon next to the export to the "I" item next to the import. (Again, the clickable area is quite small - wait for the cursor to change from a hand to a cross.) 5. When you have connected all the imports and exports that you want, click the Download Component button to download the composed component as a `.wasm` file. - -## Composing components with the wac CLI - -You can use the [wac](https://github.com/bytecodealliance/wac) CLI as well to create your composition. - -The example composition described above could be created with the `wac` file below - -``` -//composition.wac -package component-book:composition; - -let regex = new component-book:regex-impl { ... }; -let validator = new component-book:validator-impl { "component-book:regex/match": regex.match, ... }; - -export validator...; -``` - -For an in depth description about how to use the wac tool, you can check out the [language guide](https://github.com/bytecodealliance/wac/blob/main/LANGUAGE.md) \ No newline at end of file diff --git a/component-model/src/creating-and-consuming/distributing.md b/component-model/src/creating-and-consuming/distributing.md index 0f3f3dd9..594e6e4e 100644 --- a/component-model/src/creating-and-consuming/distributing.md +++ b/component-model/src/creating-and-consuming/distributing.md @@ -9,7 +9,7 @@ Today, the primary way to distribute components is via [OCI](https://opencontain One of the primary use cases of a Warg registry is publishing and downloading WIT packages. The easiest way to create and use WIT packages is with the [wit](https://github.com/bytecodealliance/cargo-component/tree/main/crates/wit) CLI. After installing the CLI, you can use it to create WIT packages that depend on other packages in a registry, as well as to build a final binary and publish the result to a registry ## Using Warg registries to author and distribute components -Another tool that is set up to interact with warg registries is `cargo-component`. You can read about how to build and use published packages in your rust projects in the [rust](../language-support/rust.md) section. Components authored with other tools and languages can also be published to the registry, but have less support for importing/exporting functionality between components today. In general, given a .wasm binary, you can always publish and download using the [warg cli](https://github.com/bytecodealliance/registry?tab=readme-ov-file#installation) +Another tool that is set up to interact with warg registries is `cargo-component`. You can read about how to build and use published packages in your Rust projects in the [Rust](../language-support/rust.md) section. Components authored with other tools and languages can also be published to the registry, but have less support for importing/exporting functionality between components today. In general, given a .wasm binary, you can always publish and download using the [warg cli](https://github.com/bytecodealliance/registry?tab=readme-ov-file#installation) ## Using Warg registries in your component compositions The `wac` CLI is yet another tool with warg registry integration. Learn more about how to use registries when you compose components in the [composition](./composing.md#composing-components-with-the-wac-cli) section. diff --git a/component-model/src/language-support/rust.md b/component-model/src/language-support/rust.md index 12383715..5ea3f9f2 100644 --- a/component-model/src/language-support/rust.md +++ b/component-model/src/language-support/rust.md @@ -112,7 +112,8 @@ impl Guest for Component { ``` ## Exporting an interface from a registry with `cargo component` -If you know of a WIT package that has been published to the registry that defines a world, you can also create a library that targets that world specifically. We've gone ahead and published [adder](https://preview.wa.dev/component-book:adder) for reference. You can generate a scaffolding for a rust implementation of a world by running `cargo component new --lib --target :/ `. In our case, this translates to `cargo component new --lib --target component-book:adder/adder adder`. + +If you know of a WIT package that has been published to the registry that defines a world, you can also create a library that targets that world specifically. We've gone ahead and published [adder](https://wa.dev/component-book:adder) for reference. You can generate a scaffolding for a rust implementation of a world by running `cargo component new --lib --target :/ `. In our case, this translates to `cargo component new --lib --target component-book:adder/adder adder`. Note that when creating a component this way, you'll have no wit file that you can edit, as you're using the types defined in the published version of the WIT package. So if you're still working through what you want your types and function signatures to be, you're probably better off starting with a local WIT package rather than one from the registry. @@ -200,9 +201,9 @@ 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), or use the [wac CLI](../creating-and-consuming/composing.md#composing-components-with-the-wac-cli). +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). -If you use the wac CLI, the following wac file would grab the bytecode alliance components ([adder-component](https://preview.wa.dev/component-book:adder-component) and [calculator-component](https://preview.wa.dev/component-book:calculator-component)) that implement each of the WIT interfaces ([adder](https://preview.wa.dev/component-book:adder) and [calculator](https://preview.wa.dev/component-book:calculator)). +If you use the wac CLI, the following wac file would grab the bytecode alliance components ([adder-component](https://wa.dev/component-book:adder-component) and [calculator-component](https://wa.dev/component-book:calculator-component)) that implement each of the WIT interfaces ([adder](https://wa.dev/component-book:adder) and [calculator](https://wa.dev/component-book:calculator)). ``` // composition.wac @@ -280,7 +281,7 @@ path = "wit" "component-book:adder" = { path = "../adder/wit" } ``` -Alternatively, if you're using the registry packages, you can use the latest versions published instead of a path. You can find the versions on the registry pages, ([calculator](https://preview.wa.dev/component-book:calculator) and [adder](https://preview.wa.dev/component-book:adder)) +Alternatively, if you're using the registry packages, you can use the latest versions published instead of a path. You can find the versions on the registry pages, ([calculator](https://wa.dev/component-book:calculator) and [adder](https://wa.dev/component-book:adder)) ```toml [package.metadata.component.target.dependencies] diff --git a/component-model/src/tutorial.md b/component-model/src/tutorial.md index 1f1b9e46..6c4efaac 100644 --- a/component-model/src/tutorial.md +++ b/component-model/src/tutorial.md @@ -15,8 +15,6 @@ Wasm components, we will compose them into a single runnable component, and test ## The calculator interface - For tutorial purposes, we are going to define all our interfaces in 2 separate wit files because in a real world use case a component is granular and will have its own wit file. These files are `adder.wit` and `calculator.wit`. These files define: @@ -88,16 +86,14 @@ It is not uncommon for many WIT packages to be published on a registry, indicati You'll notice in the [wit examples](https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/tutorial/wit) that we have definitions in the `local` folder that resolve packages locally, as well as packages that were authored using the [wit](https://github.com/bytecodealliance/cargo-component/tree/main/crates/wit) CLI, which resolves packages using the registry. -If you're using rust and you want to learn how to use a registry instead of the local files, you can use the WIT packages that have been published for this tutorial ([calculator](https://preview.wa.dev/component-book:calculator) and [adder](https://preview.wa.dev/component-book:adder)) or publish the same packages on your own namespace using the [wit CLI](./creating-and-consuming/distributing.md#using-warg-registries-for-wit-packages-with-the-wit-cli) - - +If you're using Rust, and you want to learn how to use a registry instead of the local files, you can use the WIT packages that have been published for this tutorial ([calculator](https://wa.dev/component-book:calculator) and [adder](https://wa.dev/component-book:adder)) or publish the same packages on your own namespace using the [wit CLI](./creating-and-consuming/distributing.md#using-warg-registries-for-wit-packages-with-the-wit-cli) ## Create an `add` component Reference the [language guide](language-support.md) and [authoring components documentation](creating-and-consuming/authoring.md) to create a component that implements the `adder` world of `calculator.wit`. For reference, see the completed -[example](https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/tutorial/adder/). If using the registry, this will use the [adder](https://preview.wa.dev/component-book:adder) WIT package. +[example](https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/tutorial/adder/). If using the registry, this will use the [adder](https://wa.dev/component-book:adder) WIT package. ## Create a `calculator` component @@ -137,7 +133,7 @@ package = "component-book:command-impl" target = "component-book:calculator/app@0.1.0" ``` -Check [calculator](https://preview.wa.dev/component-book:calculator) for the latest version to use. +Check [calculator](https://wa.dev/component-book:calculator) for the latest version to use. Now, implement a command line application that: @@ -155,12 +151,14 @@ imports. We then compose that resolved calculator component with the command com its `calculate` imports. The result is a command component that has all its imports satisfied and exports the `wasi:cli/run` function, which can be executed by `wasmtime`. +The [wac CLI](https://github.com/bytecodealliance/wac) is a great tool for composing components together. + ```sh -wasm-tools compose calculator.wasm -d adder.wasm -o composed.wasm -wasm-tools compose command.wasm -d composed.wasm -o final.wasm +wac plug ./path/to/calculator.wasm --plug ./path/to/adder.wasm -o composed.wasm +wac plug ./path/to/command.wasm --plug ./composed.wasm -o final.wasm ``` -You can also use the [wac](https://github.com/bytecodealliance/wac) CLI to compose these components together, and use components that are fetched from the registry. +The wac CLI also supports fetching the components it composes from the registry. We published some example components that you can use by running the following: ```sh wac plug component-book:calculator-impl --plug component-book:adder-impl -o composed.wasm