Skip to content

Serialization — BitWriter / BitReader

The typed bit helpers are the "functions for custom variables". They operate on the opaque handle passed into a manual serialize callback, and are also available standalone for building an RPC / event payload or for round-trip testing.

Bit-packed fields are written MSB-first within each byte, consistently on both ends; the encoding is identical on Linux and Windows.

BitWriter lifecycle

LATTICE_API lattice_bitwriter* lattice_bw_create(void);
LATTICE_API void               lattice_bw_destroy(lattice_bitwriter* w);
LATTICE_API void               lattice_bw_reset(lattice_bitwriter* w);
LATTICE_API uint32_t           lattice_bw_bit_count(const lattice_bitwriter* w);
LATTICE_API uint32_t           lattice_bw_byte_count(const lattice_bitwriter* w);
LATTICE_API const uint8_t*     lattice_bw_data(const lattice_bitwriter* w); /* flushed byte buffer */

lattice_bw_data returns the flushed byte buffer; pair it with lattice_bw_byte_count when handing a payload to lattice_rpc / lattice_send_event. lattice_bw_reset rewinds the writer for reuse.

BitWriter — typed writes

LATTICE_API void lattice_bw_write_bool(lattice_bitwriter* w, int v);
LATTICE_API void lattice_bw_write_enum(lattice_bitwriter* w, uint32_t value, uint32_t count);
LATTICE_API void lattice_bw_write_byte(lattice_bitwriter* w, uint8_t v);
LATTICE_API void lattice_bw_write_int(lattice_bitwriter* w, int32_t v);
LATTICE_API void lattice_bw_write_ranged_int(lattice_bitwriter* w, int32_t value, int32_t min, int32_t max);
LATTICE_API void lattice_bw_write_long(lattice_bitwriter* w, int64_t v);
LATTICE_API void lattice_bw_write_ranged_long(lattice_bitwriter* w, int64_t value, int64_t min, int64_t max);
LATTICE_API void lattice_bw_write_float(lattice_bitwriter* w, float v);
LATTICE_API void lattice_bw_write_compressed_float(lattice_bitwriter* w, float value, lattice_float_quant q);
LATTICE_API void lattice_bw_write_double(lattice_bitwriter* w, double v);
LATTICE_API void lattice_bw_write_vector2(lattice_bitwriter* w, lattice_vec2 v, lattice_float_quant q);
LATTICE_API void lattice_bw_write_vector3(lattice_bitwriter* w, lattice_vec3 v, lattice_float_quant q);
LATTICE_API void lattice_bw_write_vector4(lattice_bitwriter* w, lattice_vec4 v, lattice_float_quant q);
LATTICE_API void lattice_bw_write_quaternion(lattice_bitwriter* w, lattice_quat v, uint32_t bits_per_comp);
LATTICE_API void lattice_bw_write_string(lattice_bitwriter* w, const char* s);
LATTICE_API void lattice_bw_write_bytes(lattice_bitwriter* w, const uint8_t* p, uint32_t n);
LATTICE_API void lattice_bw_write_bits(lattice_bitwriter* w, uint32_t value, uint32_t bitcount);
Helper Notes
write_ranged_int / write_ranged_long Packs only the bits needed for [min, max].
write_compressed_float Quantizes to the lattice_float_quant {min, max, precision} window.
write_vector2/3/4 Per-component compressed float using q.
write_quaternion Smallest-three encoding; bits_per_comp typically 10.
write_enum Packs a value in [0, count) into ceil(log2(count)) bits.
write_bits Raw bitcount-bit field (≤ 32).

BitReader lifecycle

LATTICE_API lattice_bitreader* lattice_br_create(const uint8_t* data, uint32_t byte_len);
LATTICE_API void               lattice_br_destroy(lattice_bitreader* r);

data/byte_len is the buffer to decode (caller-owned for the reader's lifetime).

BitReader — typed reads (mirror the writes)

LATTICE_API int          lattice_br_read_bool(lattice_bitreader* r);
LATTICE_API uint32_t     lattice_br_read_enum(lattice_bitreader* r, uint32_t count);
LATTICE_API uint8_t      lattice_br_read_byte(lattice_bitreader* r);
LATTICE_API int32_t      lattice_br_read_int(lattice_bitreader* r);
LATTICE_API int32_t      lattice_br_read_ranged_int(lattice_bitreader* r, int32_t min, int32_t max);
LATTICE_API int64_t      lattice_br_read_long(lattice_bitreader* r);
LATTICE_API int64_t      lattice_br_read_ranged_long(lattice_bitreader* r, int64_t min, int64_t max);
LATTICE_API float        lattice_br_read_float(lattice_bitreader* r);
LATTICE_API float        lattice_br_read_compressed_float(lattice_bitreader* r, lattice_float_quant q);
LATTICE_API double       lattice_br_read_double(lattice_bitreader* r);
LATTICE_API lattice_vec2 lattice_br_read_vector2(lattice_bitreader* r, lattice_float_quant q);
LATTICE_API lattice_vec3 lattice_br_read_vector3(lattice_bitreader* r, lattice_float_quant q);
LATTICE_API lattice_vec4 lattice_br_read_vector4(lattice_bitreader* r, lattice_float_quant q);
LATTICE_API lattice_quat lattice_br_read_quaternion(lattice_bitreader* r, uint32_t bits_per_comp);
LATTICE_API uint32_t     lattice_br_read_string(lattice_bitreader* r, char* out, uint32_t cap);  /* returns length, NUL-terminates */
LATTICE_API uint32_t     lattice_br_read_bytes(lattice_bitreader* r, uint8_t* out, uint32_t cap);/* returns length */
LATTICE_API uint32_t     lattice_br_read_bits(lattice_bitreader* r, uint32_t bitcount);

Always pass the SAME quantization / ranges on both ends

Read each field with the same min/max/lattice_float_quant/bits_per_comp you wrote it with. read_string / read_bytes write up to cap and return the full length (NUL-terminating strings when cap > 0); a binding must clamp to the written length to avoid an over-read.

Round-trip example

lattice_bitwriter* w = lattice_bw_create();
lattice_bw_write_ranged_int(w, weapon_id, 0, 255);
lattice_bw_write_byte(w, ammo);
lattice_bw_write_bool(w, has_shield);

lattice_bitreader* rd = lattice_br_create(lattice_bw_data(w), lattice_bw_byte_count(w));
int32_t weapon = lattice_br_read_ranged_int(rd, 0, 255);
uint8_t a      = lattice_br_read_byte(rd);
int      shld  = lattice_br_read_bool(rd);

lattice_br_destroy(rd);
lattice_bw_destroy(w);

Misc helper

LATTICE_API const char* lattice_result_str(lattice_result r);

Render a lattice_result code as a human string (e.g. for logs). See also lattice_type_content_hash.