Skip to main content

Module js

Module js 

Source
Expand description

Javascript endpoints rendered from service traits at compile time.

endpoint! is the Javascript counterpart of crate::Builder and reads the same way: service = names the trait the generated endpoint serves, client = the trait it calls, and the values are the same generated struct names one would pass to with_service and with_client. At least one is required.

// The Rust side of this binary.
Builder::new(iface)
    .with_service::<CalculatorService<_>>(calculator)
    .with_client::<DisplayClient>();
// The other end of the same connection, described as itself.
web_rpc::js::endpoint!(service = DisplayService, client = CalculatorClient);

The expansion writes a .mjs and a .d.ts into two custom sections of the wasm binary, named after the class in snake_case: __web_rpc_calculator_client_js and __web_rpc_calculator_client_d_ts for the example above. Extract them with llvm-objcopy (or rust-objcopy from cargo-binutils), before wasm-bindgen runs:

llvm-objcopy --dump-section=__web_rpc_calculator_client_js=calculator_client.mjs \
             --dump-section=__web_rpc_calculator_client_d_ts=calculator_client.d.ts \
             in.wasm out.wasm

Add --remove-section=... for each to strip them from what you ship. The .mjs has no imports and needs no bundling.

The generated module is the shell in js/endpoint.mjs, which is trait-independent, followed by data: a schema value per type the traits reach, a method table per trait, and a class whose methods forward to the shell. Encoding and decoding are interpreted from those values by the shell’s Codec, which the module also exports along with Writer and Reader, for an embedder that wants to speak postcard itself.

One caveat follows from how #[link_section] works on wasm: the macro must be invoked in the binary crate that is linked into the wasm module, because a static in an rlib that contributes no symbol to the link is dropped by wasm-ld.

§What the renderers reject

Rendering happens during const evaluation, which cannot format a panic message, so the compiler’s const-eval backtrace is what points at the offending type. An enum whose struct variant has a field named tag would collide with the discriminant of the Typescript union that represents it:

#[derive(serde::Serialize, serde::Deserialize, postcard_schema::Schema)]
pub enum Bad {
    Variant { tag: u32 },
}

#[web_rpc::service]
pub trait Uses {
    fn take(&self, value: Bad);
}

web_rpc::js::endpoint!(client = UsesClient);

So would two types that render to the same Typescript name:

#[derive(serde::Serialize, serde::Deserialize, postcard_schema::Schema)]
pub struct Alpha { pub x: u32 }

#[derive(serde::Serialize, serde::Deserialize, postcard_schema::Schema)]
#[serde(rename = "Alpha")]
pub struct Beta { pub y: String }

#[web_rpc::service]
pub trait Uses {
    fn one(&self, value: Alpha);
    fn two(&self, value: Beta);
}

web_rpc::js::endpoint!(client = UsesClient);

And so would a type named Request, Subscription or Endpoint, which the generated declarations define themselves:

#[derive(serde::Serialize, serde::Deserialize, postcard_schema::Schema)]
pub struct Request { pub id: u32 }

#[web_rpc::service]
pub trait Uses {
    fn one(&self, value: Request);
}

web_rpc::js::endpoint!(client = UsesClient);

Macros§

endpoint
Render a Javascript endpoint and a .d.ts for the other end of a connection into two custom sections of the wasm binary. See the web_rpc::js module.

Structs§

Endpoint
What the macro renders: a class name and the traits filling each half of the connection.
Output
Const-evaluable output buffer.

Constants§

MAX_DECLARATIONS
The number of distinct containers one endpoint may reach.
SHELL
The trait-independent part of every generated endpoint, emitted ahead of the rendered schemas, method tables and class.

Functions§

method_at
The indexth enabled method of a service. Its position here is its index on the wire.
method_count
The number of methods of a service that survived cfg evaluation.
render_dts
Render the Typescript declarations for one endpoint.
render_js
Render the Javascript module for one endpoint.