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 c5c1d1b5..fa5ccca6 100644 --- a/component-model/examples/tutorial/README.md +++ b/component-model/examples/tutorial/README.md @@ -1,19 +1,13 @@ # Building a Calculator of Wasm Components This tutorial walks through how to compose a component to build a Wasm calculator. -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: +This example uses multiple components that target distinct worlds defined across multiple WIT packages. -```wit -package docs:calculator@0.1.0; +The first package consists of addition operations -interface calculate { - enum op { - add, - } - eval-expression: func(op: op, x: u32, y: u32) -> u32; -} +```wit +//adder.wit +package component-book:adder@0.1.0; interface add { add: func(a: u32, b: u32) -> u32; @@ -22,10 +16,25 @@ interface add { world adder { export add; } +``` + +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 +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; } ``` @@ -33,14 +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 +``` + +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 ``` 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 a6dfd29a..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 = "docs:calculator" +package = "component-book:adder-impl" [package.metadata.component.target] -path = "../wit/calculator.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 80% rename from component-model/examples/tutorial/adder/src/bindings.rs rename to component-model/examples/tutorial/local/adder/src/bindings.rs index d991f90a..12c43ef3 100644 --- a/component-model/examples/tutorial/adder/src/bindings.rs +++ b/component-model/examples/tutorial/local/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 = "docs: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::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::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\x19docs:calculator/add@\ -0.1.0\x05\0\x04\x01\x1bdocs: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/local/adder/src/lib.rs similarity index 72% rename from component-model/examples/tutorial/adder/src/lib.rs rename to component-model/examples/tutorial/local/adder/src/lib.rs index 0afc22d8..efadfb82 100644 --- a/component-model/examples/tutorial/adder/src/lib.rs +++ b/component-model/examples/tutorial/local/adder/src/lib.rs @@ -1,6 +1,6 @@ mod bindings; -use crate::bindings::exports::docs::calculator::add::Guest; +use crate::bindings::exports::component_book::adder::add::Guest; struct Component; 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 59% rename from component-model/examples/tutorial/calculator/Cargo.toml rename to component-model/examples/tutorial/local/calculator/Cargo.toml index 762844f5..5f9f5a7e 100644 --- a/component-model/examples/tutorial/calculator/Cargo.toml +++ b/component-model/examples/tutorial/local/calculator/Cargo.toml @@ -11,10 +11,11 @@ wit-bindgen-rt = { version = "0.24.0", features = ["bitflags"] } crate-type = ["cdylib"] [package.metadata.component] -package = "docs:calculator" +package = "component-book:calculator-impl" + +[package.metadata.component.target.dependencies] +"component-book: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/local/calculator/src/bindings.rs similarity index 83% rename from component-model/examples/tutorial/calculator/src/bindings.rs rename to component-model/examples/tutorial/local/calculator/src/bindings.rs index 94b1483e..82fa688b 100644 --- a/component-model/examples/tutorial/calculator/src/bindings.rs +++ b/component-model/examples/tutorial/local/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 = "docs: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 = "docs: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::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::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\x19docs: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\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/local/calculator/src/lib.rs similarity index 70% rename from component-model/examples/tutorial/calculator/src/lib.rs rename to component-model/examples/tutorial/local/calculator/src/lib.rs index 5eb86f14..b0ed92d5 100644 --- a/component-model/examples/tutorial/calculator/src/lib.rs +++ b/component-model/examples/tutorial/local/calculator/src/lib.rs @@ -1,9 +1,9 @@ mod bindings; -use bindings::exports::docs::calculator::calculate::{Guest, Op}; +use bindings::exports::component_book::calculator::calculate::{Guest, Op}; // Bring the imported add function into scope -use bindings::docs::calculator::add::add; +use bindings::component_book::adder::add::add; struct Component; 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 61% rename from component-model/examples/tutorial/command/Cargo.toml rename to component-model/examples/tutorial/local/command/Cargo.toml index c395a7e1..7a3382ad 100644 --- a/component-model/examples/tutorial/command/Cargo.toml +++ b/component-model/examples/tutorial/local/command/Cargo.toml @@ -4,12 +4,15 @@ version = "0.1.0" edition = "2021" [package.metadata.component] -package = "docs:calculator" +package = "component-book:command-impl" [package.metadata.component.target] -path = "../wit/calculator.wit" +path = "../../wit/local/calculator.wit" world = "app" +[package.metadata.component.target.dependencies] +"component-model: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/local/command/src/bindings.rs similarity index 85% rename from component-model/examples/tutorial/command/src/bindings.rs rename to component-model/examples/tutorial/local/command/src/bindings.rs index 1dbe7d85..7b8d98e0 100644 --- a/component-model/examples/tutorial/command/src/bindings.rs +++ b/component-model/examples/tutorial/local/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 = "docs: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\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\ -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/local/command/src/main.rs similarity index 93% rename from component-model/examples/tutorial/command/src/main.rs rename to component-model/examples/tutorial/local/command/src/main.rs index 055fffbe..9e229c3e 100644 --- a/component-model/examples/tutorial/command/src/main.rs +++ b/component-model/examples/tutorial/local/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::component_book::calculator::{calculate, calculate::Op}; fn parse_operator(op: &str) -> anyhow::Result { match op { 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/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.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/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 59% rename from component-model/examples/tutorial/wit/calculator.wit rename to component-model/examples/tutorial/wit/calculator/calculator.wit index ebfd2344..98dc8d26 100644 --- a/component-model/examples/tutorial/wit/calculator.wit +++ b/component-model/examples/tutorial/wit/calculator/calculator.wit @@ -1,4 +1,4 @@ -package docs: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..4d8707f0 --- /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:2afffac0a89b4f6add89903754bb5a09a51378ef14f159283c1a6408abb43147" 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 5d7365a8..dfcdb6a5 100644 --- a/component-model/src/creating-and-consuming/composing.md +++ b/component-model/src/creating-and-consuming/composing.md @@ -14,56 +14,61 @@ 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 `component-book:validator-impl` +package component-book: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 component-book:regex/match@0.1.0; } -// component 'regex' -package docs: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; } -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, `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 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. 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` +## 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 diff --git a/component-model/src/creating-and-consuming/distributing.md b/component-model/src/creating-and-consuming/distributing.md index 3abdc3c9..594e6e4e 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 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) + +## 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/go.md b/component-model/src/language-support/go.md index 26dd3eb3..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 docs: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 (`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 (`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 docs: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 fcdff582..5ea3f9f2 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 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::docs::calculator::add::Guest; +use bindings::exports::bytecode_alliance::calculator::add::Guest; struct Component; @@ -111,6 +111,12 @@ 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://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,25 +131,30 @@ For example, suppose you have created and built an adder component as explained // in the 'calculator' project // wit/world.wit -package docs: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 docs:adder/add@0.1.0; + import component-book:adder/add0.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: +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] -"docs: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. @@ -156,18 +167,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::docs::calculator::calculate::Guest; +use bindings::exports::component_book::calculator::calculate::{Guest, Op}; // Bring the imported add function into scope -use bindings::docs::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), + } } } ``` @@ -184,14 +195,30 @@ $ wasm-tools component wit ./target/wasm32-wasi/release/calculator.wasm package root:component; world root { - import docs:adder/add@0.1.0; + import component-book:adder/add@0.1.0; - export docs: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). +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 +package component-book:composition; + +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...; +``` + +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` A _command_ is a component with a specific export that allows it to be executed directly by `wasmtime` (or other `wasm:cli` hosts). In Rust terms, it's the equivalent of an application (`bin`) package with a `main` function, instead of a library crate (`lib`) package. @@ -228,14 +255,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 component-book:app; world app { - import docs: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 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 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: @@ -250,16 +277,23 @@ path = "wit" ```toml [package.metadata.component.target.dependencies] -"docs:calculator" = { path = "../calculator/wit" } -"docs: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://wa.dev/component-book:calculator) and [adder](https://wa.dev/component-book:adder)) + +```toml +[package.metadata.component.target.dependencies] +"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::docs::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 819c7655..6c4efaac 100644 --- a/component-model/src/tutorial.md +++ b/component-model/src/tutorial.md @@ -15,8 +15,8 @@ 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 +33,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 docs: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 +50,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,12 +82,18 @@ world app { ``` +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://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/). +[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 @@ -88,7 +113,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 +126,15 @@ path = "../path/to/calculator.wit" world = "app" ``` +If you're using the registry, you can specify the target world. +``` +[package.metadata.component] +package = "component-book:command-impl" +target = "component-book:calculator/app@0.1.0" +``` + +Check [calculator](https://wa.dev/component-book: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") @@ -117,11 +151,22 @@ 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 ``` +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 +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 > wasmbuilder.app](creating-and-consuming/composing.md#composing-components-with-a-visual-interface).