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.wasmAdd --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.tsfor the other end of a connection into two custom sections of the wasm binary. See theweb_rpc::jsmodule.
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.