This documentation is part of the "Projects with Books" initiative at zenOSmosis.
The source code for this project is available on GitHub.
Serialization with Bitcode
Loading…
Serialization with Bitcode
Relevant source files
- Cargo.lock
- src/rpc/rpc_internals/rpc_header.rs
- src/rpc/rpc_request_response.rs
- tests/rpc_dispatcher_tests.rs
This page documents how the bitcode library provides compact binary serialization for RPC parameters, responses, and metadata throughout the muxio framework. For information about defining service methods that use these serialized types, see Creating Service Definitions. For details on how method identifiers are generated, see Method ID Generation.
Purpose and Role
The bitcode crate serves as the serialization layer that transforms strongly-typed Rust structs into compact binary representations suitable for network transmission. This enables type-safe RPC communication while maintaining minimal payload sizes and efficient encoding/decoding performance.
Sources:
Bitcode in the Data Pipeline
Diagram: Bitcode serialization flow between application types and wire format
Sources:
Core Traits and Functions
| Trait/Function | Purpose | Usage Context |
|---|---|---|
bitcode::Encode | Derive macro for serialization | Applied to request/response parameter structs |
bitcode::Decode | Derive macro for deserialization | Applied to request/response parameter structs |
bitcode::encode(&T) | Encodes a value to Vec<u8> | Used before sending RPC requests/responses |
bitcode::decode::<T>(&[u8]) | Decodes bytes to type T | Used after receiving RPC requests/responses |
Sources:
Type Definitions with Bitcode
Types used in RPC communication must derive both Encode and Decode traits. These derivations are typically combined with Debug and PartialEq for testing and debugging purposes.
Diagram: Type definition pattern for serializable RPC parameters
graph TB
subgraph "Example Type Definition"
Struct["#[derive(Encode, Decode, PartialEq, Debug)]\nstruct AddRequestParams"]
Field1["numbers: Vec<f64>"]
Struct --> Field1
end
subgraph "Bitcode Derive Macros"
EncodeMacro["bitcode_derive::Encode"]
DecodeMacro["bitcode_derive::Decode"]
end
subgraph "Generated Implementations"
EncodeImpl["impl Encode for AddRequestParams"]
DecodeImpl["impl Decode for AddRequestParams"]
end
Struct -.->|expands to| EncodeMacro
Struct -.->|expands to| DecodeMacro
EncodeMacro --> EncodeImpl
DecodeMacro --> DecodeImpl
Example from test suite:
tests/rpc_dispatcher_tests.rs:10-28 demonstrates the standard pattern:
Sources:
Integration with RPC Request/Response Types
The serialized bytes produced by bitcode::encode() are stored in specific fields of the RPC protocol structures:
| RPC Type | Field | Purpose |
|---|---|---|
RpcRequest | rpc_param_bytes: Option<Vec<u8>> | Encoded method parameters sent in header metadata |
RpcRequest | rpc_prebuffered_payload_bytes: Option<Vec<u8>> | Encoded payload data for prebuffered requests |
RpcResponse | rpc_prebuffered_payload_bytes: Option<Vec<u8>> | Encoded response payload |
RpcHeader | rpc_metadata_bytes: Vec<u8> | Encoded metadata (parameters or status) |
Sources:
- src/rpc/rpc_request_response.rs:9-33
- src/rpc/rpc_request_response.rs:40-76
- src/rpc/rpc_internals/rpc_header.rs:3-24
Request Encoding Pattern
Diagram: Encoding flow for RPC request parameters
Example from test suite:
tests/rpc_dispatcher_tests.rs:42-49 demonstrates encoding request parameters:
Sources:
Response Decoding Pattern
Diagram: Decoding flow for RPC response payload
Example from test suite:
tests/rpc_dispatcher_tests.rs:100-116 demonstrates decoding response payloads:
Sources:
graph LR
subgraph "Receive Phase"
ReqBytes["rpc_param_bytes"]
DecodeReq["bitcode::decode\n<AddRequestParams>"]
ReqParams["AddRequestParams"]
ReqBytes --> DecodeReq
DecodeReq --> ReqParams
end
subgraph "Processing"
Logic["Business Logic\n(sum numbers)"]
RespParams["AddResponseParams"]
ReqParams --> Logic
Logic --> RespParams
end
subgraph "Send Phase"
EncodeResp["bitcode::encode"]
RespBytes["rpc_prebuffered_payload_bytes"]
RespParams --> EncodeResp
EncodeResp --> RespBytes
end
Server-Side Processing Pattern
The server decodes incoming request parameters, processes them, and encodes response payloads:
Diagram: Complete encode-process-decode cycle on server
Example from test suite:
tests/rpc_dispatcher_tests.rs:151-167 demonstrates the complete server-side pattern:
Sources:
Supported Types
Bitcode supports a wide range of Rust types through its derive macros:
| Type Category | Examples | Notes |
|---|---|---|
| Primitives | i32, u64, f64, bool | Direct binary encoding |
| Standard collections | Vec<T>, HashMap<K,V>, Option<T> | Length-prefixed encoding |
| Tuples | (T1, T2, T3) | Sequential encoding |
| Structs | Custom types with #[derive(Encode, Decode)] | Field-by-field encoding |
| Enums | Tagged unions with variants | Discriminant + variant data |
Sources:
- Cargo.lock:158-168 (bitcode dependencies including arrayvec, bytemuck, glam, serde)
- tests/rpc_dispatcher_tests.rs:10-28
graph TB
Bytes["Incoming Bytes"]
Decode["bitcode::decode<T>()"]
Success["Ok(T)"]
Error["Err(bitcode::Error)"]
Bytes --> Decode
Decode -->|Valid binary| Success
Decode -->|Invalid/incompatible| Error
Error -->|Handle| ErrorHandler["Error Handler\n(log, return error response)"]
Error Handling
Decoding operations return Result types to handle malformed or incompatible binary data:
Diagram: Error handling in bitcode deserialization
The test code demonstrates using .unwrap() for simplicity, but production code should handle decode errors gracefully:
tests/rpc_dispatcher_tests.rs:152-153 shows unwrapping (test code):
Sources:
Compact Binary Format
Bitcode produces compact binary representations compared to text-based formats like JSON. The format characteristics include:
| Feature | Benefit |
|---|---|
| No field names in output | Reduces payload size by relying on struct definition order |
| Variable-length integer encoding | Smaller values use fewer bytes |
| No schema overhead | Binary is decoded based on compile-time type information |
| Aligned data structures | Optimized for fast deserialization via bytemuck |
Sources:
- Cargo.lock:158-168 (bitcode with bytemuck dependency for zero-copy operations)
Dependencies and Ecosystem Integration
The bitcode crate integrates with the broader Rust ecosystem:
Diagram: Bitcode dependency graph
Sources:
Usage in Muxio Ecosystem
Bitcode is used throughout the muxio workspace:
| Crate | Usage |
|---|---|
muxio | Core RPC protocol structures |
muxio-rpc-service | Service definition trait bounds |
example-muxio-rpc-service-definition | Shared RPC parameter types |
muxio-rpc-service-endpoint | Server-side deserialization |
muxio-rpc-service-caller | Client-side serialization |
Sources:
- Cargo.lock:426-431 (example-muxio-rpc-service-definition dependencies)
- Cargo.lock:858-867 (muxio-rpc-service dependencies)
- Cargo.lock:830-839 (muxio dependencies)