COOLJAPAN
← All posts

OxiCode 0.2.0 Released — Zero-Copy Decode, Size Pre-Computation, and a Much Bigger API

OxiCode's first 0.2 minor: a major API expansion with a BorrowDecode derive for zero-copy decoding, the SizeWriter / encoded_size pre-allocation API, encode_to_file / decode_from_file, lazy DecodeIter streaming, CRC32 checksums, versioned-value helpers, and a rich set of derive attributes — all while keeping 100% bincode 2.0 binary compatibility. 19,929 passing tests, zero warnings.

release oxicode bincode serialization serde zero-copy no-std pure-rust scirs2

The Pure Rust successor to bincode just grew up into a full-featured codec.

Today we released OxiCode 0.2.0 — the first 0.2-series minor, and by far the largest API expansion since the debut. It keeps the same promise (a drop-in, 100%-bincode-2.0-binary-compatible encoder/decoder) and fills in the ergonomics that real production serialization demands: true zero-copy decoding, size pre-computation, file I/O, lazy streaming iterators, integrity checksums, and a deep set of derive attributes.

No C. No Fortran. No pickle, no Protobuf toolchain, no FFI.
Just memory-safe encode/decode that compiles to a single static binary (or WASM) and stays correct under Miri.

Why OxiCode 0.2.0 is a game changer

The 0.1.x line proved the thesis: you can replace bincode with pure Rust and gain SIMD, compression, and versioning without breaking the wire format. But day-to-day, three things kept coming up:

0.2.0 closes all three gaps, and then adds a derive system rich enough that most custom encodings no longer need hand-written impls. All of it lands on top of unchanged, byte-for-byte bincode compatibility — your existing .bin files keep working.

Technical Deep Dive: the new surface area

The workspace shape is unchanged — oxicode (core), oxicode_derive (macros), and a compatibility crate — but the core layer is meaningfully wider:

  1. Zero-copy decoding, first class
    A BorrowDecode derive macro now generates borrowing impls for your own types, and the standard library coverage was extended: BorrowDecode for Box<[T]>, Box<str>, Arc<[T]>, Arc<str>, Rc<[T]>, Rc<str>, String, char, Cow<str> and Cow<[u8]>, non-zero integers, atomics, Wrapping<T>, Reverse<T>, and ControlFlow. Decode straight out of the input slice without allocating.

  2. Size pre-computation
    A new SizeWriter plus the top-level encoded_size() / encoded_size_with_config() functions compute the exact byte length without allocating a buffer. Pair them with encode_to_vec_with_size_hint() to size your Vec once and never reallocate — or use encode_to_fixed_array::<N>() to encode straight into a stack-allocated [u8; N].

  3. Files, writers, and lazy streaming
    encode_to_file() / decode_from_file() (under the std feature) and encode_to_writer() / decode_from_reader() cover the common I/O paths. For multi-record buffers, decode_iter_from_slice() returns a lazy DecodeIter<T> and encode_iter_to_vec() / encode_seq_to_vec() go the other way. A BufferedIoReader<R> wraps BufReader for efficient streaming decode.

  4. Integrity and evolution
    An optional checksum feature adds CRC32 integrity checking (via crc32fast), exposed through encode_to_vec_checked / decode_from_slice_checked, and a new DecodeError::ChecksumMismatch. Versioned encoding gets ergonomic top-level helpers: encode_versioned_value / decode_versioned_value.

  5. A real derive vocabulary
    Field attributes — skip, default, default_value, flatten, bytes, with, encode_with / decode_with, rename, seq_len. Container attributes — bound, rename_all, crate, transparent. Variant attributes — variant (custom discriminant), rename, and a tag_type control to pick the enum discriminant width (u8/u16/u32/u64). Hex display lands too, via EncodedBytes / encode_to_hex / decode_from_hex.

Quality held the line: 19,929 tests passing with 0 regressions, 0 warnings, 0 clippy errors, 42 tests green under Miri (--no-default-features, zero undefined-behavior findings), cargo publish --dry-run clean for both crates, and every file under 2,000 lines.

Getting Started

cargo add oxicode

Round-trip a value, then borrow-decode and pre-compute its size — all 0.2.0 APIs:

use oxicode::{Encode, Decode, BorrowDecode};

#[derive(Encode, Decode, BorrowDecode, PartialEq, Debug)]
struct Frame<'a> {
    id: u32,
    label: &'a str,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let frame = Frame { id: 7, label: "telemetry" };

    // Know the size before allocating
    let n = oxicode::encoded_size(&frame)?;

    // Encode (optionally size-hinted)
    let bytes = oxicode::encode_to_vec_with_size_hint(&frame, n)?;

    // Zero-copy decode: `label` borrows out of `bytes`
    let (decoded, _): (Frame, _) = oxicode::borrow_decode_from_slice(&bytes)?;

    assert_eq!(frame, decoded);
    Ok(())
}

Already using serde? The optional serde feature gives you encode_serde / decode_serde convenience functions, now with i128/u128 support.

What’s New in 0.2.0

Tips

This is the foundation

OxiCode is the binary codec the rest of the COOLJAPAN stack serializes against. With SciRS2 and NumRS2 for numerical checkpointing and data exchange, ToRSh for tensor buffers, OxiARC for archive-embedded payloads, and simulation engines like Spintronics for state save/load — 0.2.0’s zero-copy path and size-precise allocation make all of those hotter and leaner. Because it speaks serde and the bincode wire format, it drops into existing pipelines without a rewrite.

Repository: https://github.com/cool-japan/oxicode

Star the repo if you want fast, zero-copy, future-proof binary serialization without the old bincode limitations.

Pure Rust modern serialization is here — fast, compatible, and sovereign.

KitaSan at COOLJAPAN OÜ March 16, 2026

↑ Back to all posts