Files
2026-05-27 23:47:53 +01:00

3.2 KiB

bitset

Purpose

Implements the wire-format bitset codec for the mesh protocol. Bitsets carry chunk presence (cd:advertise) and chunk-need maps (cd:request kind:'bitset'); their on-wire representation is a deterministic, magic-prefixed, length-tagged envelope so receivers can detect and reject payloads that bypassed the mandated framing layer (DMP-21). This module also provides the raw bit-manipulation helpers (chunkIdsToRawBitset, rawBitsetToChunkIds, popcount) that the rest of the package consumes.

Features

  • BITSET_MAGIC (4-byte "DMPB" prefix) + BITSET_HEADER_SIZE (12-byte fixed header).
  • encodeBitset(rawBytes, bitLength) — wraps a raw bit-packed buffer with the header.
  • decodeBitset(wire) — verifies magic, decodes header, returns { raw, bitLength }; throws DMP.CODEC_MISMATCH for missing magic / truncated headers / length mismatches.
  • chunkIdsToRawBitset(ids, bitLength) — packs a chunk-id list into a raw bit-packed buffer with strict bounds checking.
  • rawBitsetToChunkIds(bytes, bitLength) — inverse, with padding-zero enforcement (DMP-08).
  • popcount(bytes) — population count (Hamming weight) over a raw byte array; used by trust accounting.
  • All length / padding violations raise DMP.BITSET_LENGTH_MISMATCH or DMP.BITSET_PADDING_NONZERO.

Usage: Basic Example

import {
    chunkIdsToRawBitset,
    decodeBitset,
    encodeBitset,
    rawBitsetToChunkIds,
} from "@suaveplan/drive-mesh-protocol";

const raw = chunkIdsToRawBitset([0, 5, 17], 18);
const wire = encodeBitset(raw, 18);
const back = decodeBitset(wire);
const ids = rawBitsetToChunkIds(back.raw, back.bitLength); // [0, 5, 17]

Usage: Advanced Example

import {
    BITSET_HEADER_SIZE,
    BITSET_MAGIC,
    encodeBitset,
    popcount,
} from "@suaveplan/drive-mesh-protocol";

function buildPresence(present: number[], totalChunks: number): Uint8Array {
    const raw = chunkIdsToRawBitset(present, totalChunks);
    const wire = encodeBitset(raw, totalChunks);
    console.log(
        `${present.length}/${totalChunks} chunks; ${popcount(raw)} set bits;` +
        ` wire size ${wire.length} (${BITSET_HEADER_SIZE}-byte header)`
    );
    return wire;
}

API Reference

  • BITSET_MAGIC: Uint8Array — 4-byte prefix 0x44 0x4d 0x50 0x42.
  • BITSET_HEADER_SIZE: 12 — magic + bitLength + rawByteLen.
  • encodeBitset(rawBytes: Uint8Array, bitLength: number): Uint8Array.
  • decodeBitset(wire: Uint8Array): { raw: Uint8Array; bitLength: number }.
  • chunkIdsToRawBitset(chunkIds: readonly number[], bitLength: number): Uint8Array.
  • rawBitsetToChunkIds(bytes: Uint8Array, bitLength: number): number[].
  • popcount(bytes: Uint8Array): number.

Implementation Notes

The wire format does NOT compress the bitset body — the documented bitpacker-compressed mandate is satisfied by the magic + length envelope, which is itself a length-prefixed, self-describing frame. The compressRle fast path in @suaveplan/bitpacker-compressed is non-bijective on inputs containing isolated [X, 0, …] triples and is therefore unsuitable for arbitrary bitset bytes; switching to gzip would force the codec async and break the hot path. The trade-off is intentional and documented inline in the source.