Skip to content

Commit

Permalink
Fixes, README, rpc-error type (#2)
Browse files Browse the repository at this point in the history
* Fixes, README, rpc-error type

* Export RpcError
  • Loading branch information
vigoo authored Feb 16, 2024
1 parent 6001df4 commit b6aa445
Show file tree
Hide file tree
Showing 9 changed files with 229 additions and 103 deletions.
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

0 comments on commit b6aa445

Please sign in to comment.