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`:

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

## Example

```rust
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:

```rust
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:

```rust
#[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:

```rust
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