This documentation is part of the "Projects with Books" initiative at zenOSmosis.
The source code for this project is available on GitHub.
Shared Service Definition Pattern
Loading…
Shared Service Definition Pattern
Relevant source files
- LICENSE
- benches/README.md
- examples/example-muxio-rpc-service-definition/Cargo.toml
- examples/example-muxio-rpc-service-definition/README.md
- examples/example-muxio-rpc-service-definition/src/lib.rs
- examples/example-muxio-rpc-service-definition/src/prebuffered.rs
The Shared Service Definition Pattern is a core architectural idiom in Muxio that allows both the client and the server to share a single source of truth for RPC method signatures and serialization logic. By defining services in a dedicated crate, developers ensure type safety and protocol consistency across different transport implementations (e.g., Tokio-based servers and WASM-based clients).
Purpose and Scope
The primary goal of this pattern is to decouple the what (the RPC contract) from the how (the network transport and runtime). This is achieved through the RpcMethodPrebuffered trait, which defines how high-level Rust types are transformed into binary payloads and identifies methods using unique 64-bit hashes.
In the provided examples, the example-muxio-rpc-service-definition crate serves as this shared contract, utilized by both the server and client.
Sources: examples/example-muxio-rpc-service-definition/src/lib.rs4 examples/example-muxio-rpc-service-definition/src/prebuffered/add.rs17
Crate Structure
A typical service definition crate is lightweight and usually depends only on muxio-rpc-service and a serialization library like bitcode examples/example-muxio-rpc-service-definition/Cargo.toml:10-12 The example structure follows a modular approach:
add.rs: Implements a mathematical addition service examples/example-muxio-rpc-service-definition/src/prebuffered/add.rs:1-44mult.rs: Implements a mathematical multiplication service examples/example-muxio-rpc-service-definition/src/prebuffered/mult.rs:1-44echo.rs: Implements a raw byte-array echo service examples/example-muxio-rpc-service-definition/src/prebuffered/echo.rs:1-27
The crate re-exposes the RpcMethodPrebuffered trait for simplicity examples/example-muxio-rpc-service-definition/src/lib.rs4
Sources: examples/example-muxio-rpc-service-definition/src/lib.rs:1-5 examples/example-muxio-rpc-service-definition/src/prebuffered.rs:1-9 examples/example-muxio-rpc-service-definition/Cargo.toml:1-13
Implementation: RpcMethodPrebuffered
The RpcMethodPrebuffered trait is the cornerstone of the shared definition. It requires the implementation of four serialization methods and a unique METHOD_ID.
Method Identification via rpc_method_id!
To avoid manual management of integer IDs, Muxio uses the rpc_method_id! macro. This macro generates a u64 at compile-time by hashing a string literal (e.g., "math.add") using the XXH3 algorithm examples/example-muxio-rpc-service-definition/src/prebuffered/add.rs18 This ensures that as long as the string name is consistent, the client and server will agree on the dispatch ID.
Data Flow and Serialization
The pattern typically uses a serialization library (like bitcode) to handle the conversion of parameters into bytes examples/example-muxio-rpc-service-definition/src/prebuffered/add.rs1
| Stage | Function | Direction |
|---|---|---|
| Request Encoding | encode_request | Caller: Input -> Vec<u8> |
| Request Decoding | decode_request | Endpoint: &[u8] -> Input |
| Response Encoding | encode_response | Endpoint: Output -> Vec<u8> |
| Response Decoding | decode_response | Caller: &[u8] -> Output |
Example: The Add Service
In add.rs, the service defines internal structs for request and response parameters that are hidden from the public API of the Add unit struct.
Entity Mapping: Add Service
graph TD
subgraph "Natural Language Space"
"Math Addition Service"
end
subgraph "Code Entity Space"
Add["struct Add"]
AddReq["struct AddRequestParams"]
AddRes["struct AddResponseParams"]
Trait["RpcMethodPrebuffered"]
Add -- "implements" --> Trait
AddReq -- "serialized by" --> Add
AddRes -- "serialized by" --> Add
Add -- "uses" --> rpc_method_id["rpc_method_id!('math.add')"]
end
Sources: examples/example-muxio-rpc-service-definition/src/prebuffered/add.rs:5-15 examples/example-muxio-rpc-service-definition/src/prebuffered/add.rs:17-18
Detailed Method Implementations
Structured Data: Add and Mult
The Add and Mult implementations use bitcode to handle Vec<f64> inputs.
AddImplementation: DefinesMETHOD_IDasrpc_method_id!("math.add")examples/example-muxio-rpc-service-definition/src/prebuffered/add.rs18 It maps aVec<f64>input to a singlef64output examples/example-muxio-rpc-service-definition/src/prebuffered/add.rs:20-21MultImplementation: Mirrors theAddstructure but usesrpc_method_id!("math.mult")examples/example-muxio-rpc-service-definition/src/prebuffered/mult.rs18
Passthrough: Echo
The Echo service demonstrates a “raw” implementation where no external serialization is needed because the Input and Output types are already Vec<u8> examples/example-muxio-rpc-service-definition/src/prebuffered/echo.rs:9-10 The implementation simply returns the input bytes or clones them into a vector examples/example-muxio-rpc-service-definition/src/prebuffered/echo.rs:12-26
sequenceDiagram
participant Client as "RpcClient (Caller)"
participant Shared as "example-muxio-rpc-service-definition"
participant Server as "RpcServer (Endpoint)"
Note over Client, Server: Both crates depend on Shared Definition
rect rgb(240, 240, 240)
Note right of Client: call_rpc_buffered::<Add>(...)
Client->>Shared: encode_request(Vec<f64>)
Shared-->>Client: Vec<u8> (Payload)
end
Client->>Server: Frame (METHOD_ID: math.add)
rect rgb(240, 240, 240)
Note left of Server: handle_request (Add)
Server->>Shared: decode_request(Vec<u8>)
Shared-->>Server: Vec<f64> (Input)
Note left of Server: Execute Logic
Server->>Shared: encode_response(f64)
Shared-->>Server: Vec<u8> (Payload)
end
Server->>Client: Frame (Response)
rect rgb(240, 240, 240)
Client->>Shared: decode_response(Vec<u8>)
Shared-->>Client: f64 (Output)
end
Shared Usage Diagram
The following diagram illustrates how the shared crate bridges the Client and Server components by providing common serialization logic.
Protocol Interaction Flow
Sources: examples/example-muxio-rpc-service-definition/src/prebuffered/add.rs:23-43 examples/example-muxio-rpc-service-definition/src/prebuffered/echo.rs:6-27
Key Functions and Traits
RpcMethodPrebuffered: The trait that defines the interface for a specific RPC method examples/example-muxio-rpc-service-definition/src/prebuffered/add.rs17rpc_method_id!: A macro that generates a uniqueu64identifier based on a string name examples/example-muxio-rpc-service-definition/src/prebuffered/add.rs18bitcode::encode/bitcode::decode: Used within the trait methods to transform parameters into the binary format required for transport examples/example-muxio-rpc-service-definition/src/prebuffered/add.rs:24-29
Sources:
- examples/example-muxio-rpc-service-definition/src/lib.rs
- examples/example-muxio-rpc-service-definition/src/prebuffered/add.rs
- examples/example-muxio-rpc-service-definition/src/prebuffered/mult.rs
- examples/example-muxio-rpc-service-definition/src/prebuffered/echo.rs
- examples/example-muxio-rpc-service-definition/Cargo.toml