Skip to content
This repository has been archived by the owner on Dec 11, 2024. It is now read-only.

Fixes, README, rpc-error type #2

Merged
merged 2 commits into from
Feb 16, 2024
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
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@

## golem-wasm-rpc

Defines data types for [Golem](https://golem.cloud)'s remote function invocation and conversions between them.

- `WitValue` is the WIT-defined generic data type capable of representing an arbitrary value, generated by `wit-bindgen`
- A builder and an extractor API for `WitValue`
- `Value` is a recursive Rust type which is more convenient to work with than `WitValue`. Conversion between `WitValue` and `Value` is implemented in both directions.
- Protobuf message types for describing values and types, and a protobuf version of `WitValue` itself and conversion from and to `Value` and `WitValue`
- JSON representation of WIT values, as defined in [the Golem docs](https://learn.golem.cloud/docs/template-interface).
- Conversion of `Value` to and from `wasmtime` values

The JSON representation requires additional type information which can be extracted using the [golem-wasm-ast](https://crates.io/crates/golem-wasm-ast) crate.

## Host and stub mode

The `golem-wasm-rpc` crate can be both used in host and guest environments:

To compile the host version:
Expand All @@ -16,6 +29,15 @@ To compile the guest version, has minimal dependencies and feature set to be use
cargo component build -p wasm-rpc --no-default-features --features stub
```

## Feature flags
- `arbitrary` adds an `Arbitrary` instance for `Value`
- `json` adds conversion functions for mapping of a WIT value and type definition to/from JSON
- `protobuf` adds the protobuf message types
- `wasmtime` adds conversion to `wasmtime` `Val` values
- `host` enables all features: `arbitrary`, `json`, `protobuf`, `typeinfo`, and `wasmtime`
- `stub` is to be used in generated WASM stubs and disables all features, and generates guest bindings instead of host bindings


## golem-wasm-rpc-stubgen

The `golem-wasm-rpc-stubgen` is a CLI tool to generate the RPC stubs from a component's WIT definition.
Expand Down
35 changes: 35 additions & 0 deletions wasm-rpc-stubgen/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# golem-wasm-rpc-stubgen

The `golem-wasm-rpc-stubgen` is a CLI tool to generate the RPC stubs from a component's WIT definition.

```shell
Usage: wasm-rpc-stubgen generate [OPTIONS] --source-wit-root <SOURCE_WIT_ROOT> --dest-crate-root <DEST_CRATE_ROOT>

Options:
-s, --source-wit-root <SOURCE_WIT_ROOT>
-d, --dest-crate-root <DEST_CRATE_ROOT>
-w, --world <WORLD>
--stub-crate-version <STUB_CRATE_VERSION> [default: 0.0.1]
--wasm-rpc-path-override <WASM_RPC_PATH_OVERRIDE>
-h, --help Print help
-V, --version Print version
```

- `source-wit-root`: The root directory of the component's WIT definition to be called via RPC
- `dest-crate-root`: The target path to generate a new stub crate to
- `world`: The world name to be used in the generated stub crate. If there is only a single world in the source root
package, no need to specify.
- `stub-crate-version`: The crate version of the generated stub crate
- `wasm-rpc-path-override`: The path to the `wasm-rpc` crate to be used in the generated stub crate. If not specified,
the latest version of `wasm-rpc` will be used.

The command creates a new Rust crate that is ready to be compiled with

```shell
cargo component build --release
```

The resulting WASM component implements the **stub interface** corresponding to the source interface, found in the
target directory's
`wit/_stub.wit` file. This WASM component is to be composed together with another component that calls the original
interface via WASM RPC.
2 changes: 1 addition & 1 deletion wasm-rpc-stubgen/src/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ pub fn generate_cargo_toml(def: &StubDefinition) -> anyhow::Result<()> {
}),
};

let mut package = cargo_toml::Package::new(def.source_world_name()?, &def.stub_crate_version);
let mut package = cargo_toml::Package::new(def.target_crate_name()?, &def.stub_crate_version);
package.edition = Inheritable::Set(Edition::E2021);
package.metadata = Some(metadata);
manifest.package = Some(package);
Expand Down
44 changes: 28 additions & 16 deletions wasm-rpc-stubgen/src/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

use crate::stub::{FunctionResultStub, FunctionStub, StubDefinition};
use anyhow::anyhow;
use heck::{ToShoutySnakeCase, ToUpperCamelCase};
use heck::{ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase};
use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;
use std::fs;
Expand Down Expand Up @@ -51,20 +51,24 @@ pub fn generate_stub_source(def: &StubDefinition) -> anyhow::Result<()> {
let mut fn_impls = Vec::new();
for function in &interface.functions {
fn_impls.push(generate_function_stub_source(
def,
function,
&root_ns,
&root_name,
if interface.global {
None
} else {
Some(&interface.name)
},
&def.resolve,
)?);
}

let stub_interface_name = format!("stub-{}", def.source_world_name()?);
let stub_interface_name = Ident::new(
&to_rust_ident(&stub_interface_name).to_snake_case(),
Span::call_site(),
);

interface_impls.push(quote! {
impl crate::bindings::exports::#root_ns::#root_name::stub_api::#guest_interface_name for #interface_name {
impl crate::bindings::exports::#root_ns::#root_name::#stub_interface_name::#guest_interface_name for #interface_name {
fn new(location: crate::bindings::golem::rpc::types::Uri) -> Self {
let location = Uri { value: location.value };
Self {
Expand Down Expand Up @@ -101,11 +105,9 @@ pub fn generate_stub_source(def: &StubDefinition) -> anyhow::Result<()> {
}

fn generate_function_stub_source(
def: &StubDefinition,
function: &FunctionStub,
root_ns: &Ident,
root_name: &Ident,
interface_name: Option<&String>,
resolve: &Resolve,
) -> anyhow::Result<TokenStream> {
let function_name = Ident::new(&to_rust_ident(&function.name), Span::call_site());
let mut params = Vec::new();
Expand All @@ -114,7 +116,7 @@ fn generate_function_stub_source(

for param in &function.params {
let param_name = Ident::new(&to_rust_ident(&param.name), Span::call_site());
let param_typ = type_to_rust_ident(&param.typ, resolve)?;
let param_typ = type_to_rust_ident(&param.typ, &def.resolve)?;
params.push(quote! {
#param_name: #param_typ
});
Expand All @@ -123,14 +125,14 @@ fn generate_function_stub_source(
input_values.push(wit_value_builder(
&param.typ,
&param_name_access,
resolve,
&def.resolve,
quote! { WitValue::builder() },
)?);
}

let result_type = match &function.results {
FunctionResultStub::Single(typ) => {
let typ = type_to_rust_ident(typ, resolve)?;
let typ = type_to_rust_ident(typ, &def.resolve)?;
quote! {
#typ
}
Expand All @@ -139,7 +141,7 @@ fn generate_function_stub_source(
let mut results = Vec::new();
for param in params {
let param_name = Ident::new(&to_rust_ident(&param.name), Span::call_site());
let param_typ = type_to_rust_ident(&param.typ, resolve)?;
let param_typ = type_to_rust_ident(&param.typ, &def.resolve)?;
results.push(quote! {
#param_name: #param_typ
});
Expand All @@ -158,13 +160,17 @@ fn generate_function_stub_source(

match &function.results {
FunctionResultStub::Single(typ) => {
output_values.push(extract_from_wit_value(typ, resolve, quote! { result })?);
output_values.push(extract_from_wit_value(
typ,
&def.resolve,
quote! { result },
)?);
}
FunctionResultStub::Multi(params) => {
for (n, param) in params.iter().enumerate() {
output_values.push(extract_from_wit_value(
&param.typ,
resolve,
&def.resolve,
quote! { result.tuple_element(#n).expect("tuple not found") },
)?);
}
Expand All @@ -174,9 +180,15 @@ fn generate_function_stub_source(
let remote_function_name = match interface_name {
Some(remote_interface) => format!(
"{}:{}/{}/{}",
root_ns, root_name, remote_interface, function.name
def.root_package_name.namespace,
def.root_package_name.name,
remote_interface,
function.name
),
None => format!(
"{}:{}/{}",
def.root_package_name.namespace, def.root_package_name.name, function.name
),
None => format!("{}:{}/{}", root_ns, root_name, function.name),
};

Ok(quote! {
Expand Down
14 changes: 10 additions & 4 deletions wasm-rpc-stubgen/src/stub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ impl StubDefinition {
self.target_root.join("Cargo.toml")
}

pub fn target_crate_name(&self) -> anyhow::Result<String> {
Ok(format!("{}-stub", self.source_world_name()?))
}

pub fn target_rust_path(&self) -> PathBuf {
self.target_root.join("src/lib.rs")
}
Expand Down Expand Up @@ -315,10 +319,12 @@ fn get_unresolved_packages(

let mut deps = BTreeMap::new();
let deps_path = root_path.join(Path::new("deps"));
for dep_entry in fs::read_dir(deps_path)? {
let dep_entry = dep_entry?;
let dep = UnresolvedPackage::parse_path(&dep_entry.path())?;
deps.insert(dep.name.clone(), dep);
if deps_path.exists() {
for dep_entry in fs::read_dir(deps_path)? {
let dep_entry = dep_entry?;
let dep = UnresolvedPackage::parse_path(&dep_entry.path())?;
deps.insert(dep.name.clone(), dep);
}
}

// Perform a simple topological sort which will bail out on cycles
Expand Down
36 changes: 36 additions & 0 deletions wasm-rpc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# golem-wasm-rpc

Defines data types for [Golem](https://golem.cloud)'s remote function invocation and conversions between them.

- `WitValue` is the WIT-defined generic data type capable of representing an arbitrary value, generated by `wit-bindgen`
- A builder and an extractor API for `WitValue`
- `Value` is a recursive Rust type which is more convenient to work with than `WitValue`. Conversion between `WitValue` and `Value` is implemented in both directions.
- Protobuf message types for describing values and types, and a protobuf version of `WitValue` itself and conversion from and to `Value` and `WitValue`
- JSON representation of WIT values, as defined in [the Golem docs](https://learn.golem.cloud/docs/template-interface).
- Conversion of `Value` to and from `wasmtime` values

The JSON representation requires additional type information which can be extracted using the [golem-wasm-ast](https://crates.io/crates/golem-wasm-ast) crate.

## Host and stub mode

The `golem-wasm-rpc` crate can be both used in host and guest environments:

To compile the host version:

```shell
cargo build -p wasm-rpc --no-default-features --features host
```

To compile the guest version, has minimal dependencies and feature set to be used in generated stubs:

```shell
cargo component build -p wasm-rpc --no-default-features --features stub
```

## Feature flags
- `arbitrary` adds an `Arbitrary` instance for `Value`
- `json` adds conversion functions for mapping of a WIT value and type definition to/from JSON
- `protobuf` adds the protobuf message types
- `wasmtime` adds conversion to `wasmtime` `Val` values
- `host` enables all features: `arbitrary`, `json`, `protobuf`, `typeinfo`, and `wasmtime`
- `stub` is to be used in generated WASM stubs and disables all features, and generates guest bindings instead of host bindings
Loading
Loading