Serialization Specification

NOTE: This specification is primarily defined in the context of Rust, but aims to be implementable across different programming languages.

Definitions

Endianness

By default, this serialization format uses little-endian byte order for basic numeric types. This means multi-byte values are encoded with their least significant byte first.

Endianness can be configured with the following methods, allowing for big-endian serialization when required:

Byte Order Considerations

Basic Types

Boolean Encoding

Numeric Types

Floating Point Special Values

Character Encoding

IntEncoding

Bincode currently supports 2 different types of IntEncoding. With the default config, VarintEncoding is selected.

VarintEncoding

Encoding an unsigned integer u works as follows:

  1. If u < 251, encode it as a single byte with that value.

  2. If 251 <= u < 2**16, encode it as a literal byte 251, followed by a u16 with value u.

  3. If 2**16 <= u < 2**32, encode it as a literal byte 252, followed by a u32 with value u.

  4. If 2**32 <= u < 2**64, encode it as a literal byte 253, followed by a u64 with value u.

  5. If 2**64 <= u < 2**128, encode it as a literal byte 254, followed by a u128 with value u.

usize is encoded as u64 and isize as i64.

FixintEncoding

Bit-Packed Layout

When BitPacking is enabled in the configuration, types marked as BitPacked (via the derive macro) use a specialized bit-level layout.

Layout Principles

Supported Fields

Collections

General Collection Serialization

Collections are encoded with their length value first, followed by each entry. The length value is based on the configured IntEncoding.

Arrays

Fixed-length array length is never encoded. The elements follow strictly in sequence.

String and &str

Performance Implementation Notes (Internal)

While not affecting the wire format, implementers should consider the following for extreme performance:

  1. SIMD Varint Scanning: When decoding a Vec of variable-length integers, scanning for consecutive single-byte varints (values 0..250) using SIMD (SSE2/NEON) can significantly increase throughput.

  2. Bulk Copy: If the encoding is Fixint and the target system endianness matches the configuration (or for 1-byte types), slices can be copied directly using memcpy or equivalent.

  3. Double-Pass Avoidance: For collections, pre-allocate space (Vec::with_capacity) and read directly into uninitialized memory (MaybeUninit) to avoid zero-initialization overhead.