Skip to content

Update rust guide and tutorial examples to use registries for WITs #251

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions component-model/examples/tutorial/adder/Cargo-component.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# This file is automatically generated by cargo-component.
# It is not intended for manual editing.
version = 1

[[package]]
name = "docs:adder"
registry = "ghcr.io/bytecodealliance"

[[package.version]]
requirement = "^0.1.0"
version = "0.1.0"
digest = "sha256:d4cb950366f8756821c401ec496ad43b35ffb0df3b2e757eb6aa3c1fa30d38c2"
18 changes: 12 additions & 6 deletions component-model/examples/tutorial/adder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,17 @@ wit-bindgen-rt = { version = "0.37.0", features = ["bitflags"] }
[lib]
crate-type = ["cdylib"]

[package.metadata.component]
# Tell cargo-component where to find the package for the target world
# The following tells cargo-component to fetch the WIT from ghcr.io/bytecodealliance/docs/adder:0.1.0
[package.metadata.component.target]
# The registry which contains the package
registry = "ghcr.io/bytecodealliance"
# The package name
package = "docs:adder"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks really slick now!

Copy link
Collaborator

@vados-cosmonic vados-cosmonic Apr 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed! I've sometimes been accused of being too verbose, but what do you all think about a comment line near this explaining how this works?

A small blurb (or even a link) to let people know that BCA packages are automatically pullable from a known registry (which is recognized by/built into cargo component), and maybe a link to docs and/or the OCI repo. I see that we have the registry key in here which should make things a bit easier to figure out!

Heavily commented configuration files are often an underrated entry point for understanding how things work IMO, and explaining a little bit of the magic here would be nice.

[EDIT] How about leaving the world in here? IMO it's nice to be overly explicit -- while single-world WIT interfaces can have their world auto-selected, I personally prefer people thinking about this actively up until they optimize that away (and only people who care about absolutely minimal configuration files will do that anyway).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like there may be a bug in cargo-componen because when i add a world to reference, i get this error:

error: failed to create a target world for package `adder` (/Users/kagold/Programs/component-docs/component-model/examples/tutorial/adder/Cargo.toml)

Caused by:
    0: failed to select world from target package `docs:adder`
    1: no world named `adder` in package

For now, i'll leave the world out but ill file an issue with cargo-component

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have another example (or text) which shows people how to use a local WIT file? I am cautious lest the second thing they do is "ooh let me try this with my own interface" and bam, they're lost.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can add in docs on that or we can have the calculator component take the local filesystem approach. Maybe both?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good - whatever works out to be more convenient is fine!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To both example implementations I added local and registry options to the Cargo.toml and in the Rust doc I added a note on how to use local files instead

# The package version
version = "0.1.0"

[package.metadata.component.dependencies]

[package.metadata.component.target]
path = "../wit/adder"
world = "adder"
# # To instead use a WIT on the local filesystem, uncomment the following lines
# [package.metadata.component.target]
# # Path to the directory containing the WIT
# path = "../wit/adder"
16 changes: 8 additions & 8 deletions component-model/examples/tutorial/adder/src/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ mod _rt {
/// ```
#[allow(unused_macros)]
#[doc(hidden)]
macro_rules! __export_adder_impl {
macro_rules! __export_root_impl {
($ty:ident) => {
self::export!($ty with_types_in self);
};
Expand All @@ -133,19 +133,19 @@ macro_rules! __export_adder_impl {
};
}
#[doc(inline)]
pub(crate) use __export_adder_impl as export;
pub(crate) use __export_root_impl as export;
#[cfg(target_arch = "wasm32")]
#[unsafe(
link_section = "component-type:wit-bindgen:0.41.0:docs:adder@0.1.0:adder:encoded world"
link_section = "component-type:wit-bindgen:0.41.0:root:component:root:encoded world"
)]
#[doc(hidden)]
#[allow(clippy::octal_escapes)]
pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 203] = *b"\
\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07P\x01A\x02\x01A\x02\x01\
pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 199] = *b"\
\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07M\x01A\x02\x01A\x02\x01\
B\x02\x01@\x02\x01xy\x01yy\0y\x04\0\x03add\x01\0\x04\0\x14docs:adder/add@0.1.0\x05\
\0\x04\0\x16docs:adder/adder@0.1.0\x04\0\x0b\x0b\x01\0\x05adder\x03\0\0\0G\x09pr\
oducers\x01\x0cprocessed-by\x02\x0dwit-component\x070.227.1\x10wit-bindgen-rust\x06\
0.41.0";
\0\x04\0\x13root:component/root\x04\0\x0b\x0a\x01\0\x04root\x03\0\0\0G\x09produc\
ers\x01\x0cprocessed-by\x02\x0dwit-component\x070.227.1\x10wit-bindgen-rust\x060\
.41.0";
#[inline(never)]
#[doc(hidden)]
pub fn __link_custom_section_describing_imports() {
Expand Down
21 changes: 14 additions & 7 deletions component-model/examples/tutorial/calculator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,21 @@ wit-bindgen-rt = { version = "0.24.0", features = ["bitflags"] }
[lib]
crate-type = ["cdylib"]

[package.metadata.component]
package = "docs:calculator"

[package.metadata.component.target.dependencies]
"docs:adder" = { path = "../wit/adder" } # directory containing the WIT package

# Tell cargo-component where to find the package for the target world
# The following tells cargo-component to fetch the WIT from a local directory
[package.metadata.component.target]
# Path to the directory containing the WIT
path = "../wit/calculator"
# World within the package to target
world = "calculator"

[package.metadata.component.dependencies]
[package.metadata.component.target.dependencies]
# Tell cargo-component where to find the package for the dependencies
"docs:adder" = { path = "../wit/adder" }

## To instead fetch the package and it's dependencies from a registry, uncomment the following lines
# [package.metadata.component.target]
# package = "docs:calculator"
# version = "0.1.0"
# registry = "ghcr.io/bytecodealliance"
# world = "calculator"
125 changes: 56 additions & 69 deletions component-model/examples/tutorial/calculator/src/bindings.rs
Original file line number Diff line number Diff line change
@@ -1,193 +1,177 @@
// Generated by `wit-bindgen` 0.25.0. DO NOT EDIT!
// Generated by `wit-bindgen` 0.41.0. DO NOT EDIT!
// Options used:
#[allow(dead_code)]
// * runtime_path: "wit_bindgen_rt"
#[rustfmt::skip]
#[allow(dead_code, clippy::all)]
pub mod docs {
#[allow(dead_code)]
pub mod adder {
#[allow(dead_code, clippy::all)]
#[allow(dead_code, async_fn_in_trait, unused_imports, 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;
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(x: u32, y: u32) -> u32 {
unsafe {
#[cfg(target_arch = "wasm32")]
#[link(wasm_import_module = "docs:adder/add@0.1.0")]
extern "C" {
unsafe extern "C" {
#[link_name = "add"]
fn wit_import(_: i32, _: i32) -> i32;
fn wit_import0(_: i32, _: i32) -> i32;
}

#[cfg(not(target_arch = "wasm32"))]
fn wit_import(_: i32, _: i32) -> i32 {
unsafe extern "C" fn wit_import0(_: i32, _: i32) -> i32 {
unreachable!()
}
let ret = wit_import(_rt::as_i32(&a), _rt::as_i32(&b));
let ret = unsafe { wit_import0(_rt::as_i32(&x), _rt::as_i32(&y)) };
ret as u32
}
}
}
}
}
#[allow(dead_code)]
#[rustfmt::skip]
#[allow(dead_code, clippy::all)]
pub mod exports {
#[allow(dead_code)]
pub mod docs {
#[allow(dead_code)]
pub mod calculator {
#[allow(dead_code, clippy::all)]
#[allow(dead_code, async_fn_in_trait, unused_imports, 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;
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)]
#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
pub enum Op {
Add,
}
impl ::core::fmt::Debug for Op {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
fn fmt(
&self,
f: &mut ::core::fmt::Formatter<'_>,
) -> ::core::fmt::Result {
match self {
Op::Add => f.debug_tuple("Op::Add").finish(),
}
}
}

impl Op {
#[doc(hidden)]
pub 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<T: Guest>(
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);
#[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_docs_calculator_calculate_0_1_0_cabi{
($ty:ident with_types_in $($path_to_types:tt)*) => (const _: () = {

#[export_name = "docs:calculator/calculate@0.1.0#eval-expression"]
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)
}
};);
}
macro_rules! __export_docs_calculator_calculate_0_1_0_cabi {
($ty:ident with_types_in $($path_to_types:tt)*) => {
const _ : () = { #[unsafe (export_name =
"docs:calculator/calculate@0.1.0#eval-expression")] unsafe extern
"C" fn export_eval_expression(arg0 : i32, arg1 : i32, arg2 :
i32,) -> i32 { unsafe { $($path_to_types)*::
_export_eval_expression_cabi::<$ty > (arg0, arg1, arg2) } } };
};
}
#[doc(hidden)]
pub(crate) use __export_docs_calculator_calculate_0_1_0_cabi;
}
}
}
}
#[rustfmt::skip]
mod _rt {

#![allow(dead_code, clippy::all)]
pub fn as_i32<T: AsI32>(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.
/// Generates `#[unsafe(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!`.
///
Expand All @@ -204,31 +188,34 @@ mod _rt {
/// ```
#[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::docs::calculator::calculate::__export_docs_calculator_calculate_0_1_0_cabi!($ty with_types_in $($path_to_types_root)*::exports::docs::calculator::calculate);
)
($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);
};
}
#[doc(inline)]
pub(crate) use __export_calculator_impl as export;

#[cfg(target_arch = "wasm32")]
#[link_section = "component-type:wit-bindgen:0.25.0:calculator:encoded world"]
#[unsafe(
link_section = "component-type:wit-bindgen:0.41.0:docs:calculator@0.1.0:calculator:encoded world"
)]
#[doc(hidden)]
#[allow(clippy::octal_escapes)]
pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 308] = *b"\
\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xb3\x01\x01A\x02\x01\
A\x04\x01B\x02\x01@\x02\x01ay\x01by\0y\x04\0\x03add\x01\0\x03\x01\x14docs:adder/\
add@0.1.0\x05\0\x01B\x04\x01m\x01\x03add\x04\0\x02op\x03\0\0\x01@\x03\x02op\x01\x01\
xy\x01yy\0y\x04\0\x0feval-expression\x01\x02\x04\x01\x1fdocs:calculator/calculat\
e@0.1.0\x05\x01\x04\x01\x20docs:calculator/calculator@0.1.0\x04\0\x0b\x10\x01\0\x0a\
calculator\x03\0\0\0G\x09producers\x01\x0cprocessed-by\x02\x0dwit-component\x070\
.208.1\x10wit-bindgen-rust\x060.25.0";

A\x04\x01B\x02\x01@\x02\x01xy\x01yy\0y\x04\0\x03add\x01\0\x03\0\x14docs:adder/ad\
d@0.1.0\x05\0\x01B\x04\x01m\x01\x03add\x04\0\x02op\x03\0\0\x01@\x03\x02op\x01\x01\
xy\x01yy\0y\x04\0\x0feval-expression\x01\x02\x04\0\x1fdocs:calculator/calculate@\
0.1.0\x05\x01\x04\0\x20docs:calculator/calculator@0.1.0\x04\0\x0b\x10\x01\0\x0ac\
alculator\x03\0\0\0G\x09producers\x01\x0cprocessed-by\x02\x0dwit-component\x070.\
227.1\x10wit-bindgen-rust\x060.41.0";
#[inline(never)]
#[doc(hidden)]
#[cfg(target_arch = "wasm32")]
pub fn __link_custom_section_describing_imports() {
wit_bindgen_rt::maybe_link_cabi_realloc();
}
Loading