From 10e3dc46af59b7367d2435ab3a98b87d32f4e3d0 Mon Sep 17 00:00:00 2001 From: Daniel Macovei Date: Wed, 15 May 2024 14:39:59 -0500 Subject: [PATCH] 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 2ac0772..e6b1b2a 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 e0b71c3..14db75c 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 6f0b12c..daa9aea 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 3e6cd4a..12c43ef 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 6e1464f..efadfb8 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 032a1f1..7fe5ea4 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 0bd400b..82fa688 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 00f9679..b0ed92d 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 16b1798..f2fd8bc 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 475f0c2..7b8d98e 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 7a3a546..9e229c3 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 0000000..2696f24 --- /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 0000000..9f7a875 --- /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 6586f9a..98dc8d2 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 0000000..7ebf4d6 --- /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 0000000..e595dda --- /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 0000000..2696f24 --- /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 0000000..98dc8d2 --- /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 e7d59f9..d4f061c 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 f9296c7..0f3f3dd 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 4f2b7a1..2ec829a 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 1c30a53..1238371 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 8d0eaef..59357e9 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" interace that can otehr wit packages and components can import or export + +* The "calculator" world that can be targeted by components that implement it. Not that this imports the "add" interface defined in the prvious 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 implemntors 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