Skip to content

Data Types

Delta-Pack schemas are built from a fixed set of data types, each with a defined snapshot encoding, diff encoding, and parsing rules. Every type is available across all language implementations.

Types fall into three groups — primitives, containers, and named types — described below.

Primitives

Primitives represent the basic scalar values:

TypeYAML SyntaxJSON ExampleEncodeDiff
Stringstring"hello"UTF-8 with per-message dictionary compressionNew value (old value pre-loaded in dictionary)
Intint42, -7ZigZag varintNew value
Int (bounded)int(min=0, max=100)50Bit-packed in log₂(max − min + 1) bitsNew value
Uintuint42Varint (shorthand for int(min=0))New value
Floatfloat3.14IEEE 754 32-bitNew value
Float (quantized)float(precision=0.01)3.14round(value / precision) as ZigZag varintNew value
BooleanbooleantrueSingle bit (RLE-compressed)Change bit (decoder flips old value)

Containers

Containers wrap other types:

TypeYAML SchemaJSON ExampleEncodeDiff
Arrayint[][1, 2, 3]Length prefix + elements in sequenceNew length + sparse updates (index + element diff) + appended elements
Map<string, int>{"a": 1, "b": 2}Length prefix + key-value pairsPositional deletions + positional updates (with value diffs) + keyed additions
Optionalstring?"value" or nullPresence bit + value if presentWas null: new value directly; was non-null: presence bit + value diff

Named Types

Named types are the only types that can be directly encoded/decoded or used as the codegen --type:

TypeYAML SchemaJSON ExampleEncodeDiff
ObjectPosition:
  x: float
  y: float
{"x": 1.5, "y": 2.0}Fields in declaration orderChange bit + per-field change bits with diffs
EnumTeam:
  - RED
  - BLUE
  - GREEN
"RED"log₂(variant count) bitsNew value
UnionContact:
  - EmailContact
  - PhoneContact
{"EmailContact": {"email": "..."}}Variant bits + variant fieldsSame type: per-field diffs; new type: variant bits + full encode
Type aliasUserId: string"abc123"Resolved to underlying typeResolved to underlying type

Language bindings

How each schema type is represented in TypeScript, C#, and Rust:

Schema typeTypeScriptC#Rust
stringstringstringString
int, int(min,max)numberlongi64
uintnumberlongu64
float, float(p)numberfloatf32
booleanbooleanboolbool
T[]T[]List<T>Vec<T>
T?T | undefinedT?Option<T>
<K, V>Map<K, V>OrderedDictionary<K, V>IndexMap<K, V>
Objecttype (structural)classstruct
Enumstring literal unionenumenum
Uniondiscriminated union (_type)abstract class + variant subclassesenum (tagged)
Type aliasresolved to underlying typeresolved to underlying typeresolved to underlying type

Binary layout

Every encoded message shares the same structure:

[data section][RLE bits][bit count (reverse varint)]

The data section holds whole-byte values (strings, varints, floats). The RLE section holds packed bits (booleans, enums, bounded integers, and change flags). The bit count at the end lets the decoder find the boundary.

Diff compactness comes from change bits: inside objects, unions, arrays, and maps, each field or element is preceded by a single bit in the RLE section. If it's 0, nothing else is encoded for that field — the decoder keeps the old value.

Released under the MIT License.