Rustery is a Rust implementation of the Bitsery serialization format.
The goal is wire-format compatibility with C++ Bitsery, exposed through a Rust-native API: typed encoders/decoders, borrowed zero-copy views, and generic container/extension support where the Bitsery model maps cleanly to Rust.
Rustery is pinned to this Bitsery target:
- Repository:
https://github.com/victorstewart/bitsery.git - Branch:
zero-copy-read - Revision:
93dc81684f4e7a8ee8c4087876d5417bae6968ca - Typed-wire reader:
bitsery/typed_wire.h,bitsery::tw::makeTypedWireView
The pin is also recorded in Cargo.toml under package.metadata.bitsery.
- Bitsery-compatible little-endian scalar payloads.
- Bitsery variable-length size prefixes.
- Strings, bytes, arrays, Rust containers, maps/sets, options, tuples, tagged unions, fixed bitsets, compact integers, ranges, entropy defaults, and growable sections.
- Bit packing with alignment validation.
- C++ interop tests against the pinned Bitsery branch.
#[derive(BitseryView)]borrowed views for Rust zero-copy reads, including nested views, scalar arrays, and generic view parameters.
Capability coverage is tracked in audits/bitsery_capability_matrix.md.
Rustery is production-ready for the documented Rust-native Bitsery payload API, typed-wire encoding, borrowed views, and covered extension set. It does not yet claim byte-for-byte feature parity for every C++ Bitsery surface.
Known parity gaps:
- Stream adapters: buffer/cursor adapters are implemented; streaming I/O adapters are pending.
- Big-endian configuration: current payload support is little-endian.
- Low-level data operations: core bit packing and alignment are implemented; broader C++ adapter operation parity is still being expanded.
- Pointer and identity graphs: direct C++ pointer/RTTI/inheritance semantics do not map one-to-one to Rust. Rustery will model these through explicit IDs, tagged unions, and ownership-safe schema APIs instead of raw pointer cloning.
use rustery::{Result, TypedWireDecode, TypedWireEncode, Writer, Reader};
struct Ping {
version: u32,
nonce: u64,
}
impl TypedWireEncode for Ping {
fn encode_typed_wire(&self, writer: &mut Writer) -> Result<()> {
writer.write_u32(self.version);
writer.write_u64(self.nonce);
Ok(())
}
}
impl<'a> TypedWireDecode<'a> for Ping {
fn decode_typed_wire(reader: &mut Reader<'a>) -> Result<Self> {
Ok(Self {
version: reader.read_u32()?,
nonce: reader.read_u64()?,
})
}
}
let bytes = Ping { version: 1, nonce: 42 }.to_typed_wire()?;
let ping = Ping::from_typed_wire(&bytes)?;Rust does not have C++26-style reflection, so Rustery uses compile-time derive generation instead. Safe views validate the Bitsery payload once, copy scalar values, and borrow dynamic fields directly from the original buffer.
use rustery::{BitseryView, Result, TypedWireEncode, Writer};
#[derive(BitseryView)]
struct Message {
id: u32,
title: String,
payload: Vec<u8>,
}
impl TypedWireEncode for Message {
fn encode_typed_wire(&self, writer: &mut Writer) -> Result<()> {
writer.write_u32(self.id);
writer.write_str(&self.title)?;
writer.write_sized_bytes(&self.payload)
}
}
let bytes = Message {
id: 7,
title: "hello".to_string(),
payload: vec![1, 2, 3],
}.to_typed_wire()?;
let view = MessageView::new(&bytes)?;
assert_eq!(view.id(), 7);
assert_eq!(view.title(), "hello"); // borrowed &'a str
assert_eq!(view.payload(), &[1, 2, 3]); // borrowed &'a [u8]This is intentionally not a &Message transmute. Bitsery wire layout is not
Rust struct layout.
The derive supports concrete named structs, nested derived structs, Vec<u8> as
borrowed bytes, scalar vectors, fixed scalar arrays, and generic parameters that
represent nested view types. Generated views also expose unsafe new_trusted
for payloads that are already known to be valid; that path skips validation such
as UTF-8 checks and is the closest apples-to-apples match for Bitsery's C++
typed byte views.
benches/typed_wire_perf.rs mirrors the pinned Bitsery branch's active
tests/typed_wire_perf.cpp cases: application-state, activity,
versioned-state, static-sample, dynamic-sample, and kitchen-sink.
Latest local comparison artifact:
benchmarks/typed_wire_perf_exact_comparison_latest.tsv.
Ratio columns below are Bitsery time / Rustery time; values above 1.0x
mean Rustery was faster in this local run.
| case | bytes | fresh/no-hint serialize | size-hint serialize | reusable serialize | owned decode | typed read | safe view | trusted view |
|---|---|---|---|---|---|---|---|---|
| application-state | 1 | 1.52x | 2.57x | 4.49x | 1.98x | 1.92x | 1.93x | 1.93x |
| activity | 24 | 0.24x | 1.68x | 1.29x | 1.34x | 1.84x | 1.67x | 1.68x |
| versioned-state | 8 | 1.29x | 1.86x | 1.57x | 2.24x | 1.60x | 1.60x | 1.60x |
| static-sample | 40 | 0.35x | 1.66x | 1.27x | 1.89x | 1.66x | 1.26x | 1.76x |
| dynamic-sample | 236 | 0.30x | 1.66x | 1.35x | 1.22x | 1.44x | 0.64x | 1.44x |
| kitchen-sink | 418 | 0.59x | 1.17x | 0.62x | 1.05x | 3.16x | 1.35x | 2.30x |
These are local microbenchmark results, not a broad claim that Rustery is always faster than Bitsery.
- Host CPU: AMD Ryzen Threadripper PRO 9965WX 24-Cores
- OS/kernel: Linux
6.19.10-1-cachyos-server - Rust:
rustc 1.94.1, LLVM21.1.8 - C++:
g++-16 16.0.1 20260425,-O3 -DNDEBUG -std=c++26 -freflection - Bitsery revision:
93dc81684f4e7a8ee8c4087876d5417bae6968ca - Rounds: 21
- CPU affinity:
taskset -c 0
Transparent reading of the results:
- Rustery typed reads and owned decodes were faster in all six mirrored cases on this host.
- Rustery trusted derived views were faster than Bitsery typed reads in all six cases on this host.
- Rustery safe derived views were faster than Bitsery typed reads in five of
six cases.
dynamic-sampleis slower because safe Rust views validate UTF-8 while Bitsery's typed view exposes text as bytes. - Rustery size-hinted serialization was faster in all six cases.
- Exact fresh/no-hint serialization was not uniformly faster; Rustery was slower in four of six cases.
- Reusable serialization was not uniformly faster; Rustery was slower on
kitchen-sink.
Raw samples and environment metadata are checked in under benchmarks/.
Regenerate them on the publication host before using the numbers as headline
claims.
cargo test --workspace --jobs $(nproc)
cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
cargo doc --workspace --no-deps --jobs $(nproc)
cargo package --workspace
cargo bench --bench typed_wire_perf -- \
--rounds 21 \
--out benchmarks/rustery_typed_wire_perf_latest.tsv \
--samples-out benchmarks/rustery_typed_wire_perf_samples_latest.tsvC++ interop tests run automatically when Bitsery headers are available at
/root/bitsery/include, or when RUSTERY_BITSERY_INCLUDE points to them.
RUSTERY_GXX16 and RUSTERY_CLANGXX can override compiler paths.
Rustery is licensed under the Apache License, Version 2.0.