Skip to content

Latest commit

 

History

History
348 lines (250 loc) · 9.19 KB

File metadata and controls

348 lines (250 loc) · 9.19 KB

Migration Guide: From bincode to OxiCode

This guide helps you migrate your project from bincode to OxiCode.

Why Migrate?

OxiCode is the successor to bincode, offering:

  • Modern Rust practices (2021 edition)
  • Strict safety guarantees (no-unwrap policy)
  • Better error handling
  • Active maintenance and long-term support
  • Performance improvements
  • Backward compatibility options

Quick Migration

Step 1: Update Dependencies

Replace in your Cargo.toml:

# Before
[dependencies]
bincode = "2.0"

# After
[dependencies]
oxicode = "0.2"

Step 2: Update Imports

// Before
use bincode::{Encode, Decode};

// After
use oxicode::{Encode, Decode};

Step 3: Update Function Calls

Most bincode functions have direct equivalents in OxiCode. Note that bincode::serialize/bincode::deserialize are the bincode 1.x API — if you are migrating from bincode = "1", that's the case that applies to you:

// Before (bincode 1.x — Cargo.toml: bincode = "1")
let encoded = bincode::serialize(&value)?;
let decoded: T = bincode::deserialize(&encoded)?;

// After (oxicode) — config::legacy() matches bincode 1.x's default wire format
let encoded = oxicode::encode_to_vec_with_config(&value, oxicode::config::legacy())?;
let (decoded, _len): (T, usize) = oxicode::decode_from_slice_with_config(&encoded, oxicode::config::legacy())?;

If you are migrating from bincode 2.x (bincode = "2.0"), there is no serialize/deserialize in that API at all — bincode 2 already uses encode_to_vec/decode_from_slice with an explicit config, and the migration is a near-identical rename:

// Before (bincode 2.x — Cargo.toml: bincode = "2.0")
use bincode::config;
let encoded = bincode::encode_to_vec(&value, config::standard())?;
let (decoded, _len): (T, usize) = bincode::decode_from_slice(&encoded, config::standard())?;

// After (oxicode) — same shape; the *_with_config suffix is oxicode's naming
let encoded = oxicode::encode_to_vec_with_config(&value, oxicode::config::standard())?;
let (decoded, _len): (T, usize) = oxicode::decode_from_slice_with_config(&encoded, oxicode::config::standard())?;

Configuration Migration

Standard Configuration

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

// After (oxicode)
let config = oxicode::config::standard();
let encoded = oxicode::encode_to_vec_with_config(&value, config)?;

Legacy/Bincode-Compatible Configuration

If you need exact bincode compatibility:

let config = oxicode::config::legacy();  // Wire-format compatible with bincode 1.x default

Feature Flags

OxiCode maintains similar feature flags to bincode:

[dependencies]
oxicode = { version = "0.2", features = ["derive"] }

# For no_std environments
oxicode = { version = "0.2", default-features = false, features = ["alloc"] }

Using Serde Integration

OxiCode's serde support is optional. If you're using serde types:

Step 1: Enable serde feature

[dependencies]
oxicode = { version = "0.2", features = ["serde"] }
serde = { version = "1.0", features = ["derive"] }

Step 2: Use serde module

// Before (bincode)
use bincode::serde::{encode_to_vec, decode_from_slice};
let bytes = encode_to_vec(&value, config::standard())?;
let (decoded, _) = decode_from_slice(&bytes, config::standard())?;

// After (oxicode) - almost identical!
use oxicode::serde::{encode_to_vec, decode_from_slice};
let bytes = encode_to_vec(&value, oxicode::config::standard())?;
let (decoded, _) = decode_from_slice(&bytes, oxicode::config::standard())?;

Important: like bincode 2.x (which also gates its serde integration behind a serde Cargo feature), oxicode requires explicit features = ["serde"] in Cargo.toml — this is not a divergence from bincode 2, only from bincode 1.x, which bundled serde support unconditionally.

Why is serde optional?

  • Smaller binary size: Projects not using serde don't pay for it
  • no_std compatibility: Serde-free usage in embedded environments
  • Flexible: Use native Encode/Decode traits or serde, your choice

Breaking Changes

Error Types

OxiCode uses its own error types:

// Before (bincode)
use bincode::error::DecodeError;

// After (oxicode)
use oxicode::Error;

Result Types

// Before (bincode)
fn process() -> Result<T, bincode::error::EncodeError> { ... }

// After (oxicode)
fn process() -> oxicode::Result<T> { ... }

Compatibility Test Suite

Reading data encoded with bincode does not require any extra dependency: oxicode's own Decode/decode_from_slice (with a matching Config) reads bincode-produced bytes directly (subject to the Known compatibility caveats). There is no runtime "compatibility layer" crate to add.

The repository does ship an internal oxicode_compatibility crate (compatibility/), but it is publish = false and test-only — it exists to assert, via cargo test, that oxicode's output is byte-identical to bincode's for a battery of types and configs; it is never published to crates.io and exports no runtime API. If you want to run that same assertion suite against your own oxicode checkout:

git clone https://github.com/cool-japan/oxicode
cd oxicode
cargo test -p oxicode_compatibility

This is a development-time check, not something your project depends on.

Common Patterns

Encoding to Vec

// Before
let bytes = bincode::serialize(&data)?;

// After
let bytes = oxicode::encode_to_vec_with_config(&data, oxicode::config::standard())?;

Decoding from &[u8]

// Before
let data: MyStruct = bincode::deserialize(&bytes)?;

// After
let (data, _len): (MyStruct, usize) = oxicode::decode_from_slice_with_config(&bytes, oxicode::config::standard())?;

Derive Macros

// Before
use bincode::{Encode, Decode};

#[derive(Encode, Decode)]
struct MyStruct {
    field: String,
}

// After
use oxicode::{Encode, Decode};

#[derive(Encode, Decode)]
struct MyStruct {
    field: String,
}

Data Format Compatibility

OxiCode's default, oxicode::config::standard() (little-endian + varint), is verified byte-identical to bincode 2.x's own config::standard() for the types covered by the oxicode_compatibility test suite — you do not need to change configs just to match bincode 2's default. If you're migrating from bincode 1.x instead (which used fixed-width integers, not varint), match that wire format with:

let config = oxicode::config::legacy();

This ensures:

  • Same fixed-int encoding
  • Same byte ordering (little-endian)
  • Wire-format compatible with bincode 1.x default (equivalent to bincode 2.0's config::legacy() preset)

Both standard() and legacy() are subject to the same small list of standard-library-type divergences — see Known compatibility caveats in the README (SystemTime, SocketAddrV6, IpAddr/SocketAddr/Bound<T> tag width, Path/PathBuf, Ordering, Duration). These are known, tracked gaps rather than a general "slightly different format" — everything else that the compatibility suite exercises round-trips byte-for-byte.

Testing Your Migration

  1. Keep both dependencies temporarily:
[dev-dependencies]
bincode = "2.0"
oxicode = "0.2"
  1. Write compatibility tests:
#[test]
fn test_bincode_compatibility() {
    let data = MyStruct { field: "test".into() };

    // Encode with bincode (legacy mode = bincode 1.x wire format)
    let bincode_bytes = bincode::encode_to_vec(&data, bincode::config::legacy())
        .expect("bincode encode");

    // Decode with oxicode using matching legacy config
    let (decoded, _len): (MyStruct, usize) =
        oxicode::decode_from_slice_with_config(&bincode_bytes, oxicode::config::legacy())
            .expect("oxicode decode");

    assert_eq!(data, decoded);
}

Performance Considerations

OxiCode is designed to be as fast or faster than bincode:

  • Run benchmarks before and after migration
  • Use cargo bench to compare performance
  • Report any performance regressions as issues

Getting Help

If you encounter issues during migration:

  1. Check the documentation
  2. Look at examples
  3. Open an issue on GitHub

Timeline

We recommend:

  1. Week 1: Add oxicode as a dev-dependency and test
  2. Week 2-3: Gradually migrate code modules
  3. Week 4: Remove bincode dependency
  4. Ongoing: Monitor and optimize

Rollback Plan

If you need to rollback:

  1. Keep both dependencies during migration
  2. Use feature flags to switch between implementations
  3. Test thoroughly before removing bincode
[features]
default = ["use-oxicode"]
use-bincode = ["bincode"]
use-oxicode = ["oxicode"]

Future-Proofing

OxiCode is committed to:

  • Semantic versioning
  • Long-term support (LTS) releases
  • Clear migration paths for major versions
  • Backward compatibility options

Questions?

For questions or concerns about migration, please:

  • Open a discussion on GitHub
  • Check existing issues and PRs
  • Reach out to the community

We're here to help make your migration smooth and successful!