Crdt.Model_codec_cbor

crdt · API reference

CBOR (RFC 7049) encoding/decoding primitives

CBOR and binary encoding/decoding primitives.

This module provides low-level encoding and decoding functions for:

  • CBOR (RFC 7049) value encoding/decoding
  • Variable-length integers (vu57, b1vu56)
  • Compact ID encoding for CRDT timestamps The implementation is optimized for performance with:
  • Inline annotations on hot paths
  • Unsafe byte operations where safe
  • Pre-allocated buffers with growth strategy
  • Batched capacity checks

Encoder

type encoder = {
  mutable buf : bytes;
  mutable pos : int;
  mutable cap : int;
}

Mutable encoder with auto-growing buffer

val create_encoder : ?capacity:int -> unit -> encoder

Create a new encoder with optional initial capacity (default 4096)

val reset_encoder : encoder -> unit

Reset encoder position to reuse buffer

val grow : encoder -> int -> unit

Grow the encoder buffer to accommodate at least min_additional more bytes

val ensure_capacity : encoder -> int -> unit

Ensure capacity for n more bytes

val encoder_contents : encoder -> bytes

Get the encoded contents as bytes

val encoder_contents_string : encoder -> string

Get the encoded contents as string

Primitive Writers

val write_u8 : encoder -> int -> unit

Write a single byte

val write_u32 : encoder -> int -> unit

Write a 32-bit unsigned integer in big-endian

val set_u32 : encoder -> int -> int -> unit

Set a 32-bit value at a specific offset (for backpatching)

val write_bytes : encoder -> bytes -> unit

Write raw bytes

val write_string : encoder -> string -> unit

Write a string as raw bytes

Variable-Length Integer Encoding

val write_vu57 : encoder -> int -> unit

Encode variable-length unsigned integer up to 57 bits (8 bytes max).

Format: each byte uses 7 bits for value, high bit indicates continuation.

byte 1   byte 2   ...   byte 8
?zzzzzzz ?zzzzzzz       zzzzzzzz

where ? = 1 means more bytes follow, ? = 0 means last byte

val write_b1vu56 : encoder -> bool -> int -> unit

Encode 1-bit flag + up to 56-bit value.

Format: first byte uses 6 bits for value, then continuation like vu57.

byte 1     byte 2   ...
f?zzzzzz   ?zzzzzzz

where f = flag bit, ? = continuation bit

val write_id : encoder -> int -> int -> unit

Write CRDT ID in compact form.

If session_index <= 7 and time_diff <= 15: single byte (0xxxyyyy) Otherwise: b1vu56(1, session_index) + vu57(time_diff)

CBOR Encoding

val write_cbor_uint : encoder -> int -> unit

Write CBOR unsigned integer (major type 0)

val write_cbor_negint : encoder -> int -> unit

Write CBOR negative integer (major type 1)

val write_cbor_int : encoder -> int -> unit

Write CBOR integer (chooses unsigned or negative encoding)

val write_cbor_string : encoder -> string -> unit

Write CBOR text string (major type 3)

val write_cbor_bytes : encoder -> bytes -> unit

Write CBOR byte string (major type 2)

val write_cbor_float : encoder -> float -> unit

Write CBOR float64 (major type 7, additional 27)

val write_cbor_null : encoder -> unit

Write CBOR null

val write_cbor_undefined : encoder -> unit

Write CBOR undefined

val write_cbor_bool : encoder -> bool -> unit

Write CBOR boolean

val write_cbor_array_header : encoder -> int -> unit

Write CBOR array header (major type 4)

val write_cbor_map_header : encoder -> int -> unit

Write CBOR map header (major type 5)

val write_cbor_value : encoder -> Value.t -> unit

Write a complete Value.t as CBOR via Cbor_simd

Decoder

type decoder = {
  data : bytes;
  mutable pos : int;
  len : int;
}

Mutable decoder state

val create_decoder : bytes -> decoder

Create a decoder from bytes

val create_decoder_string : string -> decoder

Create a decoder from string

val decoder_remaining : decoder -> int

Get remaining bytes in decoder

val decoder_has_more : decoder -> bool

Check if decoder has more data

val decoder_pos : decoder -> int

Get current decoder position

val set_decoder_pos : decoder -> int -> unit

Set decoder position (for seeking)

Primitive Readers

val read_u8 : decoder -> int

Read a single byte

val peek_u8 : decoder -> int

Peek at next byte without consuming

val read_u32 : decoder -> int

Read 32-bit unsigned integer in big-endian

val read_bytes : decoder -> int -> bytes

Read n bytes

val read_string : decoder -> int -> string

Read n bytes as string

Variable-Length Integer Decoding

val read_vu57 : decoder -> int

Read variable-length unsigned integer (up to 57 bits)

val read_b1vu56 : decoder -> bool * int

Read 1-bit flag + variable-length unsigned integer (up to 56 bits)

val read_id : decoder -> int * int

Read CRDT ID in compact form. Returns (session_index, time_diff)

CBOR Decoding

val read_cbor_length : decoder -> int -> int

Read CBOR length/value based on additional info byte

val read_cbor_float : decoder -> float

Read CBOR float64

val read_cbor_value : decoder -> Value.t

Read a complete CBOR value as Value.t via Cbor_simd.

Note: We need to read the CBOR value starting at the current decoder position, then advance the decoder past the consumed bytes. Since Cbor_simd's decoder tracks its own position, we create a sub-decoder and sync positions after.

val read_cbor_string_only : decoder -> string

Read a CBOR string (expects major type 3)

Convenience Functions

val encode_cbor : Value.t -> bytes

Encode a Value.t to CBOR bytes

val encode_cbor_string : Value.t -> string

Encode a Value.t to CBOR string

val decode_cbor : bytes -> Value.t

Decode CBOR bytes to Value.t

val decode_cbor_string : string -> Value.t

Decode CBOR string to Value.t