OxiCode
A modern binary serialization library for Rust - the successor to bincode.
About
OxiCode is a compact encoder/decoder pair that uses a binary zero-fluff encoding scheme. The size of the encoded object will be the same or smaller than the size that the object takes up in memory in a running Rust program.
This project serves as the spiritual successor to bincode, maintaining 100% binary compatibility while introducing modern improvements and advanced features that make it 150% better.
Features
Core Features (100% Bincode Compatible)
- Compact encoding: Efficient binary serialization with compact varint encoding
- Fast: Optimized for performance with zero-copy operations where possible
- Flexible: Support for various encoding configurations
- Safe: Strict no-unwrap policy, comprehensive error handling
- Modern: Built with latest Rust practices and 2021 edition features
- no_std support: Works in embedded and resource-constrained environments (with
allocfeature) - Bincode compatibility: 100% binary format compatibility with bincode 2.0 (
config::legacy()) - BorrowDecode: Zero-copy decoding via the
BorrowDecodetrait — decode into borrowed slices without allocation - encoded_size API: Pre-calculate exact encoded byte length without allocating via
encoded_size/encoded_size_with_config - Fixed-array encoding:
encode_to_fixed_array::<N>()— encode directly into a stack-allocated[u8; N] - Sequence API:
encode_seq_to_vec/decode_iter_from_slicefor streaming multi-item buffers - Checksum API:
encode_with_checksum/decode_with_checksum— CRC32 integrity protection (optional feature) - Hex display:
encode_to_display/EncodedBytes— display encoded bytes as hex without allocating aString
150% Enhancement Features (Beyond Bincode)
- ⚡ SIMD Optimization: Hardware-accelerated array encoding (2-4x speedup)
- 🗜️ Compression: LZ4 (fast) and Zstd (better ratio) support
- 📦 Schema Evolution: Version tracking and automatic migration
- 🌊 Streaming: Chunked encoding/decoding for large datasets
- ⏱️ Async Streaming: Non-blocking async I/O with tokio
- ✅ Validation: Constraint-based validation middleware
See Feature Comparison below for detailed breakdown.
Why OxiCode?
While bincode has served the Rust community well, OxiCode brings:
- 100% Binary Compatibility: Drop-in replacement with identical binary format
- Modern Rust practices: Built from the ground up with Rust 2021 edition
- Safety first: Strict no-unwrap policy throughout the codebase
- Better error handling: More informative error messages and comprehensive error types
- Advanced features: SIMD, compression, streaming, async, validation - features bincode lacks
- Active maintenance: Dedicated to long-term support and evolution
Installation
Add this to your Cargo.toml:
[]
= "0.2"
# With serde support (for serde::Serialize/Deserialize types)
= { = "0.2", = ["serde"] }
# Optional features
= { = "0.2", = ["simd", "compression", "async-tokio"] }
Feature Flags
= ["std", "derive"]
= ["alloc"] # Standard library support
= [] # Heap allocations (for no_std + alloc)
= [] # Derive macros for Encode/Decode/BorrowDecode
= [] # Serde integration (optional)
= [] # SIMD-accelerated array encoding
= [] # CRC32 integrity checking
= [] # LZ4 compression (pure Rust, fast)
= [] # Zstd compression (requires C toolchain)
= [] # Pure Rust zstd decompression
= ["tokio"] # Async streaming with Tokio
Quick Start
use ;
Derive Macros
OxiCode provides first-class derive macro support for Encode, Decode, and BorrowDecode.
use ;
Field Attributes
| Attribute | Description |
|---|---|
#[oxicode(skip)] |
Skip this field during encode/decode (uses Default::default() on decode) |
#[oxicode(default)] |
Use Default::default() if field is missing during decode |
#[oxicode(flatten)] |
Inline the fields of a nested struct |
#[oxicode(bytes)] |
Encode Vec<u8> or &[u8] as raw bytes without a length prefix |
#[oxicode(with = "module")] |
Use custom encode/decode functions from module |
#[oxicode(encode_with = "fn")] |
Use a custom encode function |
#[oxicode(decode_with = "fn")] |
Use a custom decode function |
#[oxicode(rename = "name")] |
Use a different name for this field in the encoded format |
#[oxicode(seq_len)] |
Mark field as carrying the sequence length |
Container Attributes
| Attribute | Description |
|---|---|
#[oxicode(bound = "T: Trait")] |
Override the trait bounds on the generated impl |
#[oxicode(rename_all = "camelCase")] |
Rename all fields using a naming convention |
#[oxicode(crate = "path")] |
Specify a custom path to the oxicode crate |
#[oxicode(transparent)] |
Treat a single-field struct as its inner type (no wrapper) |
#[oxicode(tag_type = "u8")] |
Set the integer type used for enum discriminants |
Variant Attributes
| Attribute | Description |
|---|---|
#[oxicode(variant = 5)] |
Assign a custom discriminant value to this variant |
#[oxicode(rename = "name")] |
Rename this variant in the encoded format |
Supported Types (120+)
OxiCode provides built-in Encode/Decode implementations for 120+ types:
Primitives & Core
bool, u8–u128, i8–i128, f32, f64, usize, isize, char, str, String
Option & Result
Option<T>, Result<T, E>
Collections
Vec<T>, HashMap<K,V>, HashSet<T>, BTreeMap<K,V>, BTreeSet<T>, BinaryHeap<T>, LinkedList<T>, VecDeque<T>
Smart Pointers & Slices
Box<T>, Arc<T>, Rc<T>, Box<[T]>, Arc<[T]>, Arc<str>, Cow<'_, T>
Network & Time
IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, Duration, SystemTime
Core Types
Range<T>, RangeInclusive<T>, Bound<T>, Cell<T>, RefCell<T>, Wrapping<T>
Atomic Types
AtomicBool, AtomicI8–AtomicI64, AtomicU8–AtomicU64, AtomicIsize, AtomicUsize
OS & Path
OsStr, OsString, Path, PathBuf
Miscellaneous
Ordering, Infallible, ControlFlow<B,C>, NonZeroU8–NonZeroU128, NonZeroI8–NonZeroI128, ManuallyDrop<T>, PhantomData<T>, tuples (up to 12 elements), arrays [T; N]
API Highlights
use ;
// Basic encode/decode
let bytes: = encode_to_vec?;
let : = decode_from_slice?;
// File I/O
encode_to_file?;
let decoded: T = decode_from_file?;
// Pre-calculate size without allocating
let size: usize = encoded_size?;
// Encode into a fixed-size stack array
let arr: = ?;
// Sequence encoding — encode multiple items into one buffer
let bytes = encode_seq_to_vec?;
let items: = decode_iter_from_slice?.?;
// Hex display without allocating a String
use EncodedBytes;
println!; // prints hex
Using with Serde
OxiCode provides optional serde integration for types that implement serde::Serialize and serde::Deserialize:
use ;
Enable serde feature in Cargo.toml:
[]
= { = "0.2", = ["serde"] }
= { = "1.0", = ["derive"] }
Configuration
OxiCode supports various encoding configurations:
use config;
// Standard configuration (default): little-endian + varint
let cfg = standard;
// Legacy bincode 1.0-compatible: little-endian + fixed-int
let cfg = legacy;
// Custom configuration
let cfg = standard
.with_big_endian
.with_fixed_int_encoding
.; // 1MB limit
// Use with encoding/decoding
let bytes = encode_to_vec_with_config?;
let = decode_from_slice_with_config?;
Advanced Features
Checksum (CRC32 Integrity)
Protect data against corruption with built-in CRC32 checksums:
use ;
let data = MyStruct ;
// Encode with CRC32 checksum appended
let bytes = encode_with_checksum?;
// Decode and verify checksum automatically — returns Err if checksum does not match
let : = decode_with_checksum?;
Enable with features = ["checksum"].
SIMD-Accelerated Arrays
Hardware acceleration for large array operations (2-4x speedup):
use ;
// Enable with features = ["simd"]
// Auto-detects CPU capabilities (SSE2, AVX2, AVX-512)
See examples/simd_arrays.rs for detailed usage.
Compression
Reduce size with LZ4 or Zstd compression:
use ;
// LZ4 - fast compression
let mut encoder = new?;
value.encode?;
// Zstd - better compression ratio
let mut encoder = new?;
value.encode?;
See examples/compression.rs for detailed usage.
Streaming Serialization
Process large datasets incrementally:
use ;
// Encode items one at a time
let mut encoder = new?;
for item in large_dataset
encoder.finish?;
// Decode items incrementally
let mut decoder = new?;
while let Some = decoder.?
See examples/streaming.rs for detailed usage.
Async Streaming
Non-blocking async I/O with tokio:
use AsyncStreamingEncoder;
// Async encoding
let mut encoder = new;
for item in dataset
let writer = encoder.finish.await?;
See examples/async_streaming.rs for detailed usage.
Validation Middleware
Validate data during decoding:
use ;
// Create validator with constraints
let mut validator = new;
validator.add_constraint;
validator.add_constraint;
// Validate decoded data
validator.validate?;
See examples/validation.rs for detailed usage.
Schema Evolution
Version your data formats and migrate gracefully:
use ;
let version = new;
let mut encoder = new?;
value.encode?;
// Decoder automatically validates version compatibility
See examples/versioning.rs for detailed usage.
Migration from bincode
OxiCode is 100% binary-compatible with bincode. Migration is straightforward:
// Before (bincode 2.0)
use ;
let bytes = encode_to_vec?;
let = decode_from_slice?;
// After (oxicode) - same API!
use ;
let bytes = encode_to_vec?;
let = decode_from_slice?;
Binary data is 100% compatible - you can mix libraries:
- Data encoded with bincode can be decoded with oxicode ✓
- Data encoded with oxicode can be decoded with bincode ✓
For detailed migration guide, see MIGRATION.md.
Comparison with bincode
OxiCode is the spiritual successor to bincode. In legacy mode (config::legacy()), oxicode produces byte-for-byte identical output to bincode 2.0, making it a true drop-in replacement.
Wire Format Compatibility
| Mode | Endianness | Int Encoding | Compatible with bincode? |
|---|---|---|---|
config::legacy() |
Little-endian | Fixed-width | Yes — 100% identical |
config::standard() |
Little-endian | Varint | No (more compact) |
Feature Delta
| Capability | bincode | oxicode |
|---|---|---|
| Supported types | ~60 | 120+ |
BorrowDecode / zero-copy |
No | Yes |
| Derive field attributes | Limited | 9 attributes |
| Container/variant attributes | No | Yes |
| Checksums (CRC32) | No | Yes (checksum feature) |
| Compression | No | Yes (LZ4, Zstd, pure-Rust Zstd) |
| Async streaming | No | Yes (async-tokio feature) |
| Validation middleware | No | Yes |
| Schema versioning | No | Yes |
encoded_size |
No | Yes |
encode_to_fixed_array |
No | Yes |
encode_seq_to_vec / decode_iter_from_slice |
No | Yes |
no_std |
Yes | Yes |
| SIMD acceleration | No | Yes (simd feature) |
Feature Comparison
| Feature | bincode | rkyv | postcard | borsh | oxicode |
|---|---|---|---|---|---|
| Binary Compatibility | ✓ | ✗ | ✗ | ✗ | ✓ |
| Zero-copy | ✗ | ✓ | ✗ | ✗ | ✓ |
| no_std | ✓ | ✓ | ✓ | ✓ | ✓ |
| SIMD Optimization | ✗ | ✗ | ✗ | ✗ | ✓ |
| Compression | ✗ | ✗ | ✗ | ✗ | ✓ |
| Async Streaming | ✗ | ✗ | ✗ | ✗ | ✓ |
| Validation | ✗ | ✗ | ✗ | ✗ | ✓ |
| Schema Evolution | ✗ | ✗ | ✗ | ✗ | ✓ |
| Varint Encoding | ✓ | ✗ | ✓ | ✗ | ✓ |
Project Status
🎯 Version 0.2.0 - Production Ready
All core features and enhancements complete. See CHANGELOG.md for details.
Statistics (as of 2026-03-16):
- Lines of Code: 513,228 (Rust source lines across 974 files)
- Files: 974 Rust files
- Test Coverage: 19,929 tests passing (100% pass rate, 0 skipped)
- 18 binary compatibility tests (100% byte-for-byte identical to bincode)
- 19,911+ feature, integration, property-based, and stress tests
- Type Coverage: 120+ types with full Encode/Decode support
- Binary Compatibility: 100% verified through cross-library testing
- Code Quality: ✓ Zero unwrap(), ✓ Zero warnings, ✓ All files < 2000 lines
Project Structure
This is a workspace with the following crates:
oxicode: Main library crateoxicode_derive: Procedural macros for deriving Encode/Decodeoxicode_compatibility: Compatibility tests and bincode interop
Development Principles
OxiCode follows strict development principles:
- No warnings policy: All code must compile without warnings
- No unwrap policy: All error cases must be properly handled
- Latest crates policy: Use latest versions of dependencies
- Workspace policy: Proper workspace structure with shared dependencies
- Refactoring policy: Keep individual files under 2000 lines
Performance
OxiCode is designed for performance:
- SIMD acceleration: 2-4x speedup for large arrays (with
simdfeature) - Zero-copy deserialization: Where possible
- Efficient varint encoding: For integers
- Minimal allocations: During encoding/decoding
- Benchmark suite: Included in
benches/
Run benchmarks:
Testing
# Run all tests
# Run specific feature tests
# Run with no-std
Examples
The examples/ directory contains comprehensive examples:
basic_usage.rs- Simple encoding/decodingconfiguration.rs- Configuration optionszero_copy.rs- Zero-copy deserializationsimd_arrays.rs- SIMD-accelerated arrayscompression.rs- LZ4 and Zstd compressionstreaming.rs- Chunked streamingasync_streaming.rs- Async tokio streamingvalidation.rs- Validation middlewareversioning.rs- Schema evolution
Run examples:
Fuzzing
OxiCode ships with cargo-fuzz targets in the fuzz/ directory.
# Install cargo-fuzz
# Run the decode-slice fuzzer
# Run roundtrip fuzzer
Targets:
fuzz_decode_slice— decode arbitrary bytes as multiple types (no panics)fuzz_roundtrip— encode + decode must be identity on structured datafuzz_streaming— streaming decoder on arbitrary bytesfuzz_versioned— versioned decode on arbitrary bytes
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Sponsorship
OxiCode is developed and maintained by COOLJAPAN OU (Team Kitasan).
If you find OxiCode useful, please consider sponsoring the project to support continued development of the Pure Rust ecosystem.
https://github.com/sponsors/cool-japan
Your sponsorship helps us:
- Maintain and improve the COOLJAPAN ecosystem
- Keep the entire ecosystem (OxiBLAS, OxiFFT, SciRS2, etc.) 100% Pure Rust
- Provide long-term support and security updates
License
Licensed under the Apache License, Version 2.0. See LICENSE for details.
Acknowledgments
This project builds upon the excellent work done by the bincode team and community. We're grateful for their contributions to the Rust ecosystem.