This documentation is part of the "Projects with Books" initiative at zenOSmosis.
The source code for this project is available on GitHub.
Design Philosophy
Loading…
Design Philosophy
Relevant source files
Purpose and Scope
This document describes the fundamental design principles that guide the architecture and implementation of the rust-muxio framework. It covers four core tenets: runtime-agnostic architecture through a non-async callback-driven model, binary protocol with schemaless RPC design, cross-platform compatibility spanning native and WASM environments, and bidirectional symmetric communication patterns.
For details on how these principles manifest in the layered architecture, see Layered Architecture. For concrete platform implementations, see Platform Implementations.
Runtime Agnosticism: The Non-Async Core
The Callback-Driven Model
The muxio core library is deliberately implemented without async/await primitives. Instead, it uses a synchronous control flow with callback functions to handle events. This architectural choice enables the same core logic to function across fundamentally different runtime environments without modification.
graph TB
subgraph CoreLibrary["muxio Core Library"]
RpcDispatcher["RpcDispatcher"]
RpcSession["RpcSession"]
FrameDecoder["FrameDecoder"]
end
subgraph Callbacks["Callback Interfaces"]
OnRead["on_read_bytes()\nInvoked when data arrives"]
OnFrame["Frame callbacks\nInvoked per decoded frame"]
OnResponse["Response handlers\nInvoked on RPC completion"]
end
subgraph Runtimes["Compatible Runtimes"]
Tokio["Tokio Multi-threaded\nasync runtime"]
StdThread["std::thread\nSingle-threaded or custom"]
WASM["WASM Browser\nJavaScript event loop"]
end
RpcDispatcher -->|registers| OnResponse
RpcSession -->|registers| OnFrame
FrameDecoder -->|invokes| OnFrame
Tokio -->|drives| CoreLibrary
StdThread -->|drives| CoreLibrary
WASM -->|drives| CoreLibrary
CoreLibrary -->|invokes| Callbacks
The key insight is that the core library never blocks, never spawns tasks, and never assumes an async executor. Instead:
- Data ingestion occurs through explicit
read_bytes()calls src/rpc/rpc_dispatcher.rs:265-389 - Event processing happens synchronously within the call stack
- Downstream actions are delegated via callbacks, allowing the caller to decide whether to spawn async tasks, queue work, or handle synchronously
Sources: DRAFT.md:48-52 README.md:35-36
Benefits of Runtime Agnosticism
| Benefit | Description | Code Reference |
|---|---|---|
| WASM Compatibility | No reliance on thread-based async executors that don’t exist in browser environments | extensions/muxio-wasm-rpc-client/src/rpc_wasm_client.rs:15-140 |
| Flexible Integration | Core can be wrapped in TokioMutex, StdMutex, or RefCell depending on context | extensions/muxio-tokio-rpc-client/src/rpc_client.rs:30-38 |
| Deterministic Execution | No hidden task spawning or scheduling; control flow is explicit | src/rpc/rpc_dispatcher.rs:1-47 |
| Testing Simplicity | Can test without async harness; unit tests run synchronously | src/rpc/rpc_dispatcher.rs:391-490 |
Sources: DRAFT.md:48-52 README.md:35-36 extensions/muxio-wasm-rpc-client/src/rpc_wasm_client.rs:1-32
Binary Protocol and Schemaless Design
Low-Overhead Binary Framing
The muxio protocol operates entirely on raw byte sequences. Unlike text-based protocols (JSON, XML), every layer—from frame headers to RPC payloads—is transmitted as compact binary data. This design decision prioritizes performance and minimizes CPU overhead.
Sources: README.md:33-34 README.md:46-47
graph LR
subgraph Application["Application Layer"]
RustStruct["Rust Struct\nAdd{a: f64, b: f64}"]
end
subgraph Serialization["Serialization Layer"]
Bitcode["bitcode::encode()\nCompact binary"]
end
subgraph RPC["RPC Protocol Layer"]
RpcRequest["RpcRequest\nmethod_id: u64\nparams: Vec<u8>"]
MethodID["xxhash(method_name)\nCompile-time constant"]
end
subgraph Framing["Framing Layer"]
FrameHeader["Frame Header\nstream_id: u64\nflags: u8\npayload_len: u32"]
FramePayload["Binary Payload\nRaw bytes"]
end
RustStruct -->|serialize| Bitcode
Bitcode -->|Vec<u8>| RpcRequest
RpcRequest -->|hash name| MethodID
RpcRequest -->|encode| FramePayload
FramePayload -->|wrap| FrameHeader
Schemaless RPC with Type Safety
The RPC layer is “schemaless” in that the protocol itself makes no assumptions about payload structure. Method IDs are 64-bit hashes computed at compile time via xxhash, and payloads are opaque byte vectors. However, type safety is enforced through shared service definitions :
This design achieves:
- Compile-time verification : Mismatched types between client and server result in compilation errors, not runtime failures
- Zero schema overhead : No runtime schema validation or parsing
- Flexibility : Different services can use different serialization formats (bitcode, bincode, protobuf, etc.) as long as both sides agree
Sources: README.md:50-51 extensions/muxio-rpc-service/src/prebuffered/mod.rs:1-50
Performance Characteristics
| Aspect | Text-Based (JSON) | Binary (muxio) |
|---|---|---|
| Parsing Overhead | Parse UTF-8, validate syntax, construct AST | Direct byte copying, minimal validation |
| Payload Size | Verbose keys, quoted strings, escape sequences | Compact type encodings, no metadata |
| CPU Usage | High for serialization/deserialization | Low, mainly memcpy operations |
| Latency | Higher due to parsing | Lower due to binary processing |
Sources: README.md:46-47 DRAFT.md11
Cross-Platform Compatibility
Platform-Specific Extensions on a Shared Core
The muxio architecture separates platform-agnostic logic from platform-specific implementations. The core library (muxio) contains all RPC logic, multiplexing, and framing. Platform extensions provide transport bindings:
Sources: README.md:37-41 README.md:48-49
graph TB
subgraph Shared["Platform-Agnostic Core"]
MuxioCore["muxio crate\nRpcDispatcher, RpcSession, FrameDecoder"]
RpcService["muxio-rpc-service\nRpcMethodPrebuffered trait"]
RpcCaller["muxio-rpc-service-caller\nRpcServiceCallerInterface"]
RpcEndpoint["muxio-rpc-service-endpoint\nRpcServiceEndpointInterface"]
end
subgraph Native["Native Platform (Tokio)"]
TokioClient["muxio-tokio-rpc-client\nRpcClient\ntokio-tungstenite"]
TokioServer["muxio-tokio-rpc-server\nRpcServer\naxum + tokio-tungstenite"]
end
subgraph Browser["Browser Platform (WASM)"]
WasmClient["muxio-wasm-rpc-client\nRpcWasmClient\nwasm-bindgen + js-sys"]
JSBridge["JavaScript Bridge\nstatic_muxio_write_bytes()"]
end
subgraph Application["Application Code"]
ServiceDef["example-muxio-rpc-service-definition\nShared service contracts"]
AppLogic["Application Logic\nSame code for both platforms"]
end
MuxioCore --> RpcCaller
MuxioCore --> RpcEndpoint
RpcService --> RpcCaller
RpcService --> RpcEndpoint
RpcCaller --> TokioClient
RpcCaller --> WasmClient
RpcEndpoint --> TokioServer
TokioClient --> AppLogic
WasmClient --> AppLogic
ServiceDef --> AppLogic
ServiceDef --> RpcService
WasmClient --> JSBridge
Write Once, Deploy Everywhere
Because the RpcServiceCallerInterface extensions/muxio-rpc-service-caller/src/caller_interface.rs:1-97 abstracts the underlying transport, application code that calls RPC methods is platform-independent :
The same pattern applies to server-side handlers via RpcServiceEndpointInterface extensions/muxio-rpc-service-endpoint/src/endpoint_interface.rs:1-137 Handlers registered on the endpoint work identically whether the server is Tokio-based or hypothetically implemented for another runtime.
Sources: README.md:48-49 Cargo.toml:20-41
WASM-Specific Considerations
The WASM client (muxio-wasm-rpc-client) demonstrates how the callback-driven core enables browser integration:
- No native async runtime : WASM doesn’t have threads or a native async executor. The callback model works directly with JavaScript’s event loop.
- Static singleton pattern : Uses
thread_local!withRefCellto maintain a global client reference extensions/muxio-wasm-rpc-client/src/static_lib/static_client.rs:10-12 - JavaScript bridge : Exposes a single function
static_muxio_write_bytes()that JavaScript calls when WebSocket data arrives extensions/muxio-wasm-rpc-client/src/static_lib/mod.rs:63-75
Sources: extensions/muxio-wasm-rpc-client/src/rpc_wasm_client.rs:1-140 extensions/muxio-wasm-rpc-client/src/static_lib/static_client.rs:1-49
Bidirectional and Symmetric Communication
Client-Server Symmetry
Unlike traditional RPC systems where clients can only call servers, muxio treats both sides symmetrically. Every connection has:
- An
RpcDispatchersrc/rpc/rpc_dispatcher.rs:19-47 for initiating calls and correlating responses - An
RpcServiceEndpointextensions/muxio-rpc-service-endpoint/src/endpoint_interface.rs:1-25 for registering handlers and processing incoming requests
This enables:
- Server-initiated calls : Servers can invoke methods on connected clients
- Bidirectional streaming : Either side can send data streams
- Event-driven architectures : Push notifications, real-time updates, etc.
Implementation Details:
- Both
RpcClientextensions/muxio-tokio-rpc-client/src/rpc_client.rs:30-38 andRpcServerextensions/muxio-tokio-rpc-server/src/rpc_server.rs:41-59 hold both a dispatcher and an endpoint - The
RpcServiceCallerInterfaceextensions/muxio-rpc-service-caller/src/caller_interface.rs:1-35 andRpcServiceEndpointInterfaceextensions/muxio-rpc-service-endpoint/src/endpoint_interface.rs:1-25 are orthogonal traits that can coexist on the same connection
Sources: DRAFT.md25 extensions/muxio-tokio-rpc-client/src/rpc_client.rs:30-38 extensions/muxio-tokio-rpc-server/src/rpc_server.rs:41-59
Streaming, Interleaving, and Cancellation
Support for Large Payloads
The multiplexing layer src/rpc/rpc_internals/rpc_session.rs:16-21 enables streaming operations:
- Chunked transmission : Large payloads are automatically split into frames based on
DEFAULT_MAX_CHUNK_SIZEsrc/rpc/rpc_internals/constants.rs:1-5 - Interleaved streams : Multiple concurrent RPCs can transmit simultaneously without head-of-line blocking
- Progressive decoding : Frames are decoded incrementally using per-stream
FrameDecoderinstances src/rpc/rpc_internals/rpc_session.rs:52-120
Sources: src/rpc/rpc_internals/rpc_session.rs:16-21 src/rpc/rpc_internals/constants.rs:1-5 DRAFT.md:19-21
Cancellation Support
The system supports mid-stream cancellation:
- Client-side : Cancel by dropping the response future or explicitly signaling cancellation (implementation-dependent)
- Protocol-level : Stream decoders are removed when
EndorErrorevents are received src/rpc/rpc_internals/rpc_session.rs:52-120 - Resource cleanup : Pending requests are cleared from the dispatcher’s hashmap when completed or errored src/rpc/rpc_dispatcher.rs:265-389
Sources: DRAFT.md21 src/rpc/rpc_dispatcher.rs:265-389 src/rpc/rpc_internals/rpc_session.rs:52-120
Design Trade-offs and Prioritization
What muxio Prioritizes
| Priority | Rationale | Implementation |
|---|---|---|
| Performance | Low latency and minimal overhead for high-throughput applications | Binary protocol, zero-copy where possible, compact serialization |
| Cross-platform | Same code works on native and WASM | Non-async core, callback-driven model |
| Type safety | Catch errors at compile time, not runtime | Shared service definitions, trait-based contracts |
| Simplicity | Easy to reason about, minimal magic | Explicit control flow, no hidden task spawning |
What muxio Does Not Prioritize
- Human readability of wire protocol : The binary format is not human-inspectable (unlike JSON). Debugging requires tooling.
- Built-in authentication/encryption : Transport security (TLS, authentication) is delegated to the transport layer (e.g.,
wss://WebSockets). - Schema evolution : No built-in versioning. Breaking changes require careful service definition updates.
- Automatic code generation : Service definitions are written manually using traits. No macros or code generation (by design, for transparency).
Sources: README.md:42-53 DRAFT.md:9-23
Summary
The muxio design philosophy centers on four pillars:
- Runtime agnosticism via non-async, callback-driven primitives
- Binary protocol with schemaless flexibility and compile-time type safety
- Cross-platform compatibility spanning native (Tokio) and WASM environments
- Bidirectional symmetry enabling client-server parity and streaming operations
These choices enable muxio to serve as a high-performance, flexible foundation for distributed systems that require low latency, cross-platform deployment, and type-safe communication.
Sources: README.md:42-53 DRAFT.md:9-52 Cargo.toml:20-41