# 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`:
```toml
# Before
[dependencies]
bincode = "2.0"
# After
[dependencies]
oxicode = "0.2"
```
### Step 2: Update Imports
```rust
// 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:
```rust
// 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:
```rust
// 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
```rust
// 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:
```rust
let config = oxicode::config::legacy(); // Wire-format compatible with bincode 1.x default
```
## Feature Flags
OxiCode maintains similar feature flags to bincode:
```toml
[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
```toml
[dependencies]
oxicode = { version = "0.2", features = ["serde"] }
serde = { version = "1.0", features = ["derive"] }
```
### Step 2: Use serde module
```rust
// 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:
```rust
// Before (bincode)
use bincode::error::DecodeError;
// After (oxicode)
use oxicode::Error;
```
### Result Types
```rust
// 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](README.md#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:
```bash
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<u8>
```rust
// Before
let bytes = bincode::serialize(&data)?;
// After
let bytes = oxicode::encode_to_vec_with_config(&data, oxicode::config::standard())?;
```
### Decoding from &[u8]
```rust
// 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
```rust
// 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:
```rust
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](README.md#known-compatibility-caveats)
(`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:
```toml
[dev-dependencies]
bincode = "2.0"
oxicode = "0.2"
```
2. Write compatibility tests:
```rust
#[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](https://docs.rs/oxicode)
2. Look at [examples](examples/)
3. Open an issue on [GitHub](https://github.com/cool-japan/oxicode/issues)
## 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
```toml
[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!