@dlenroc/binary-decoder · 
A library for implementing incremental binary data parsers using generators.
Installation
npm install @dlenroc/binary-decoder
Usage
The BinaryDecoder
class enables streaming binary decoding using a generator
function. It leverages yield
to read bytes, return unused data, and produce
the decoded result.
import { BinaryDecoder } from '@dlenroc/binary-decoder';
const decoder = new BinaryDecoder(function* () {
const fixedLengthBytes: Uint8Array = yield 2;
const variableLengthBytes: Uint8Array = yield -2;
yield Uint8Array.of(40, 50);
yield { fixedLengthBytes, variableLengthBytes, extraBytes: yield -Infinity };
});
console.log([...decoder.decode(Uint8Array.of(10, 20, 30))]);
Examples
Stateful Parsing
Suppose we need to parse a simple protocol defined as follows:
4 | U32 | length |
length | U8 array | text |
import type { Decoder } from '@dlenroc/binary-decoder';
import { BinaryDecoder, getUint32 } from '@dlenroc/binary-decoder';
function* parse(): Decoder<string> {
while (true) {
const length = yield* getUint32();
const bytes = yield length;
yield new TextDecoder().decode(bytes);
}
}
const decoder = new BinaryDecoder(parse);
const textBytes = new TextEncoder().encode('Hello, World!');
const chunk = new Uint8Array([...new Uint8Array(4), ...textBytes]);
new DataView(chunk.buffer).setUint32(0, textBytes.byteLength);
console.log([...decoder.decode(chunk)]);
console.log([...decoder.decode(Uint8Array.of(...chunk, ...chunk))]);
console.log([...decoder.decode(chunk.subarray(0, 3))]);
console.log([...decoder.decode(chunk.subarray(3, 5))]);
console.log([...decoder.decode(chunk.subarray(5))]);
Handling Large Messages
Update the decoder to stream decoded chunks directly, avoiding buffering.
import { getUint32, streamBytes } from '@dlenroc/binary-decoder';
function* parse(): Decoder<TextDecoderStream> {
while (true) {
const length = yield* getUint32();
const stream = new TextDecoderStream();
const writer = stream.writable.getWriter();
try {
yield stream;
yield* streamBytes(length, (chunk) => writer.write(chunk));
} finally {
writer.close();
}
}
}
console.log([...decoder.decode(chunk.subarray(0, 3))]);
console.log([...decoder.decode(chunk.subarray(3, 5))]);
console.log([...decoder.decode(chunk.subarray(5))]);