COOLJAPAN
← All posts

OxiCode 0.1.0 Released — A Modern Pure Rust Binary Serializer, the Successor to bincode

The first real release of OxiCode: a compact, fast, no_std-friendly binary serialization library for Rust with 100% bincode 2.0 binary compatibility. Drop-in encode/decode, derive macros, optional SIMD, compression, schema versioning, streaming, and validation. 10,860 lines of pure Rust, 211 passing tests, zero unwrap.

release oxicode bincode serialization serde no-std pure-rust encoding

Binary serialization in Rust just got a sovereign, modern foundation.

Today we released OxiCode 0.1.0 — a compact, fast binary encoder/decoder for Rust, built from the ground up as the spiritual successor to bincode while keeping 100% binary compatibility with it.

No C. No Fortran. No Python pickle. No language-specific serialization runtime.
Just a clean, memory-safe, zero-fluff binary codec that compiles to a single static binary (or WASM) and runs everywhere Rust runs.

Why OxiCode 0.1.0 matters

For years, the practical choice for compact binary serialization in Rust was bincode. It is a fine library and the community owes it a lot — but the ecosystem has moved on, and a few things have nagged for a long time:

OxiCode 0.1.0 is our answer. The core goal for this first release was simple and strict: be a drop-in replacement for bincode 2.0 that you can adopt without a flag day. Data encoded with bincode decodes with OxiCode, and vice versa — verified by 18/18 byte-for-byte binary-compatibility tests.

// Before (bincode 2.0)
let bytes = bincode::encode_to_vec(&value, config::standard())?;

// After (OxiCode) — same shape, same bytes
let bytes = oxicode::encode_to_vec(&value)?;

On top of that baseline, 0.1.0 already ships the features we wanted bincode to have, behind opt-in flags so the default build stays tiny.

Technical Deep Dive: a layered, no_std-first codec

The workspace is intentionally small and honest for a first release — a core crate plus a derive crate plus a compatibility test crate:

  1. Core layer (oxicode)
    Varint and fixed-width integer encoding, the Encode / Decode traits, a flexible config system (config::standard() for little-endian + varint, config::legacy() for bincode-1.0-compatible fixed-int), configurable size limits, and comprehensive typed errors. 112+ types implement Encode/Decode out of the box — every integer and float, bool, char, Option, Result, Box, Rc, Arc, Cow, PhantomData, the full standard collection family (Vec, HashMap, BTreeMap, VecDeque, LinkedList, BinaryHeap, …), NonZero*, tuples up to 16, and arrays of any size.

  2. Derive layer (oxicode_derive)
    #[derive(Encode, Decode)] generates the trait impls for your own structs and enums, with informative compile-time errors.

  3. no_std from the start
    default = ["std", "derive"], but the core works under no_std. Turn on just alloc for heap types without pulling in full std — embedded and WASM targets are first-class, not an afterthought.

  4. Opt-in enhancements (the “150% beyond bincode” set)

    • SIMD (features = ["simd"]): auto-detects SSE2 / AVX2 / AVX-512 and accelerates large i32/u32/i64/u64/f32/f64 arrays (2–4× on supported CPUs), with a scalar fallback everywhere else.
    • Compression (compression-lz4, compression-zstd): CompressedEncoder / CompressedDecoder for network and storage payloads.
    • Schema evolution: a Version type, embedded version tags, compatibility checking, and VersionedEncoder / VersionedDecoder.
    • Streaming: chunked sync encoders/decoders, plus async via async-tokio.
    • Validation middleware: constraint-based Validator<T> (MaxLength, Range, NonEmpty, AsciiOnly, …) for decoding untrusted data safely.

A non-negotiable throughout: zero unwrap() in the codebase. Every fallible path returns a typed error you can match on.

Getting Started

cargo add oxicode

A minimal encode/decode round-trip with the derive macros:

use oxicode::{Encode, Decode};

#[derive(Encode, Decode, PartialEq, Debug)]
struct Point {
    x: f32,
    y: f32,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let point = Point { x: 1.0, y: 2.0 };

    // Encode to bytes
    let encoded = oxicode::encode_to_vec(&point)?;

    // Decode from bytes
    let (decoded, _): (Point, _) = oxicode::decode_from_slice(&encoded)?;

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

Prefer to keep your existing serde derives? Enable the optional serde feature and serialize through it:

let encoded = oxicode::serde::encode_to_vec(&person, oxicode::config::standard())?;
let (decoded, _): (Person, _) =
    oxicode::serde::decode_from_slice(&encoded, oxicode::config::standard())?;

What’s inside

Tips

This is the foundation

OxiCode is meant to be a quiet, dependable layer that other Pure Rust projects can serialize against — simulation state for Spintronics, tensors for TenRSo and TensorLogic, audio buffers for VoiRS, and numeric arrays alongside OxiBLAS. As the COOLJAPAN stack grows, OxiCode aims to be the binary codec underneath it.

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

Star the repo if you want a modern, drop-in successor to bincode without adding a single C dependency.

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

KitaSan at COOLJAPAN OÜ December 28, 2025

↑ Back to all posts