justcode-core 0.1.0

Compact binary encoder/decoder with space-efficient encoding
Documentation

Justcode

A compact binary encoder/decoder with space-efficient encoding scheme. The encoded size will be the same or smaller than the size that the object takes up in memory in a running Rust program.

Justcode is a replacement for bincode, providing similar functionality with a focus on binary encoding without any ideological baggage.

Features

  • Compact Encoding: Space-efficient binary encoding that's the same size or smaller than in-memory representation
  • Varint Encoding: Variable-length integer encoding for lengths and small values (enabled by default)
  • Architecture Invariant: Byte-order independent, works across different architectures
  • Streaming API: Reader/Writer API for integration with files, network streams, and compression libraries
  • Configurable: Size limits, variable int encoding, and other options
  • Derive Macros: Automatic Encode and Decode trait implementations

Usage

Add to your Cargo.toml:

[dependencies]
justcode-core = { path = "../services/justcode/justcode-core" }

Example

use justcode_core::{config, Decode, Encode};

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

#[derive(Encode, Decode, PartialEq, Debug)]
struct World(Vec<Entity>);

fn main() {
    let config = config::standard();

    let world = World(vec![Entity { x: 0.0, y: 4.0 }, Entity { x: 10.0, y: 20.5 }]);

    let encoded: Vec<u8> = justcode_core::encode_to_vec(&world, config).unwrap();

    // The length of the vector is encoded as a varint u64, which in this case is encoded as a single byte
    // See the documentation on varint for more information.
    // The 4 floats are encoded in 4 bytes each.
    assert_eq!(encoded.len(), 1 + 4 * 4);

    let (decoded, len): (World, usize) = justcode_core::decode_from_slice(&encoded[..], config).unwrap();

    assert_eq!(world, decoded);
    assert_eq!(len, encoded.len()); // read all bytes
}

Configuration

Justcode provides a configurable encoding system:

use justcode_core::config;

// Standard configuration (varint encoding enabled, no size limit)
let config = config::standard();

// With size limit (recommended for untrusted input)
let config = config::standard().with_limit(1024 * 1024); // 1MB limit

// Without variable int encoding (fixed-size integers)
let config = config::standard().with_variable_int_encoding(false);

Supported Types

Primitives

  • All integer types: u8, u16, u32, u64, usize, i8, i16, i32, i64
  • Floating point: f32, f64
  • Boolean: bool
  • Character: char

Collections

  • Vec<T> where T: Encode/Decode
  • Option<T> where T: Encode/Decode
  • String and &str
  • Arrays up to 32 elements
  • Tuples up to 4 elements

Custom Types

Use the derive macros for structs and enums:

#[derive(Encode, Decode)]
struct MyStruct {
    field1: u32,
    field2: String,
}

#[derive(Encode, Decode)]
enum MyEnum {
    Variant1,
    Variant2(u32),
    Variant3 { x: f32, y: f32 },
}

Enum Encoding

Enums are encoded with a variant index (using varint encoding by default) followed by the variant data. The variant index is determined by the order of variants in the enum definition.

Reader/Writer API

For streaming operations:

use justcode_core::{config, writer::Writer, reader::Reader};

let config = config::standard();
let mut writer = Writer::new(config);
value.encode(&mut writer)?;
let bytes = writer.into_bytes();

let mut reader = Reader::new(&bytes, config);
let decoded = T::decode(&mut reader)?;

FAQ

Is Justcode suitable for storage?

Yes, the encoding format is stable when using the same configuration. Justcode is architecture-invariant and space-efficient, making it suitable for storage. However, it does not implement data versioning schemes or file headers.

Is Justcode suitable for untrusted inputs?

Justcode attempts to protect against hostile data. Use Config::with_limit() to set a maximum size limit to prevent memory exhaustion attacks. Deserializing malicious inputs will fail safely without causing undefined behavior.

What is Justcode's MSRV (minimum supported Rust version)?

Justcode requires Rust 1.70.0 or later.

Why does justcode not respect #[repr(u8)]?

Justcode encodes enum variants using varint encoding (or u32 when variable int encoding is disabled). This ensures compact encoding while maintaining compatibility. If you need to interop with a different protocol, consider implementing Encode and Decode manually.

License

MIT