zon-format
Version:
ZON: The most token-efficient serialization format for LLMs - beats CSV, TOON, JSON, and all competitors
184 lines (183 loc) • 6.1 kB
JavaScript
"use strict";
/**
* Binary ZON Decoder
*
* Decodes binary ZON format back to JavaScript values
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.BinaryZonDecoder = void 0;
exports.decodeBinary = decodeBinary;
const constants_1 = require("./constants");
/**
* Binary ZON Decoder
*/
class BinaryZonDecoder {
/**
* Decode binary ZON format to JavaScript value
*/
decode(buffer) {
this.buffer = buffer;
this.offset = 0;
this.verifyMagicHeader();
return this.decodeValue();
}
/**
* Verify magic header
*/
verifyMagicHeader() {
for (let i = 0; i < constants_1.MAGIC_HEADER.length; i++) {
if (this.buffer[this.offset++] !== constants_1.MAGIC_HEADER[i]) {
throw new Error('Invalid binary ZON format: magic header mismatch');
}
}
}
/**
* Decode a single value
*/
decodeValue() {
const marker = this.buffer[this.offset++];
if ((0, constants_1.isPositiveFixint)(marker)) {
return marker;
}
if ((0, constants_1.isNegativeFixint)(marker)) {
return marker - 256;
}
if ((0, constants_1.isFixmap)(marker)) {
return this.decodeMap((0, constants_1.getFixmapSize)(marker));
}
if ((0, constants_1.isFixarray)(marker)) {
return this.decodeArray((0, constants_1.getFixarraySize)(marker));
}
if ((0, constants_1.isFixstr)(marker)) {
return this.decodeString((0, constants_1.getFixstrSize)(marker));
}
switch (marker) {
case constants_1.TypeMarker.NIL:
return null;
case constants_1.TypeMarker.FALSE:
return false;
case constants_1.TypeMarker.TRUE:
return true;
case constants_1.TypeMarker.UINT8:
return this.readUint8();
case constants_1.TypeMarker.UINT16:
return this.readUint16();
case constants_1.TypeMarker.UINT32:
return this.readUint32();
case constants_1.TypeMarker.INT8:
return this.readInt8();
case constants_1.TypeMarker.INT16:
return this.readInt16();
case constants_1.TypeMarker.INT32:
return this.readInt32();
case constants_1.TypeMarker.FLOAT32:
return this.readFloat32();
case constants_1.TypeMarker.FLOAT64:
return this.readFloat64();
case constants_1.TypeMarker.STR8:
return this.decodeString(this.readUint8());
case constants_1.TypeMarker.STR16:
return this.decodeString(this.readUint16());
case constants_1.TypeMarker.STR32:
return this.decodeString(this.readUint32());
case constants_1.TypeMarker.ARRAY16:
return this.decodeArray(this.readUint16());
case constants_1.TypeMarker.ARRAY32:
return this.decodeArray(this.readUint32());
case constants_1.TypeMarker.MAP16:
return this.decodeMap(this.readUint16());
case constants_1.TypeMarker.MAP32:
return this.decodeMap(this.readUint32());
default:
throw new Error(`Unknown type marker: 0x${marker.toString(16)}`);
}
}
/**
* Decode a string of known length
*/
decodeString(length) {
const bytes = this.buffer.slice(this.offset, this.offset + length);
this.offset += length;
return new TextDecoder().decode(bytes);
}
/**
* Decode an array of known length
*/
decodeArray(length) {
const array = [];
for (let i = 0; i < length; i++) {
array.push(this.decodeValue());
}
return array;
}
/**
* Decode a map/object of known length
*/
decodeMap(length) {
const map = {};
for (let i = 0; i < length; i++) {
const key = this.decodeValue();
const value = this.decodeValue();
map[key] = value;
}
return map;
}
// Helper methods for reading multi-byte values
readUint8() {
return this.buffer[this.offset++];
}
readUint16() {
const value = (this.buffer[this.offset] << 8) | this.buffer[this.offset + 1];
this.offset += 2;
return value;
}
readUint32() {
const value = ((this.buffer[this.offset] << 24) |
(this.buffer[this.offset + 1] << 16) |
(this.buffer[this.offset + 2] << 8) |
this.buffer[this.offset + 3]) >>> 0;
this.offset += 4;
return value;
}
readInt8() {
const value = this.buffer[this.offset++];
return value > 127 ? value - 256 : value;
}
readInt16() {
const value = (this.buffer[this.offset] << 8) | this.buffer[this.offset + 1];
this.offset += 2;
return value > 32767 ? value - 65536 : value;
}
readInt32() {
const value = ((this.buffer[this.offset] << 24) |
(this.buffer[this.offset + 1] << 16) |
(this.buffer[this.offset + 2] << 8) |
this.buffer[this.offset + 3]);
this.offset += 4;
return value;
}
readFloat32() {
const buffer = new ArrayBuffer(4);
const view = new DataView(buffer);
for (let i = 0; i < 4; i++) {
view.setUint8(i, this.buffer[this.offset++]);
}
return view.getFloat32(0, false);
}
readFloat64() {
const buffer = new ArrayBuffer(8);
const view = new DataView(buffer);
for (let i = 0; i < 8; i++) {
view.setUint8(i, this.buffer[this.offset++]);
}
return view.getFloat64(0, false);
}
}
exports.BinaryZonDecoder = BinaryZonDecoder;
/**
* Decode binary ZON format to JavaScript value
*/
function decodeBinary(buffer) {
const decoder = new BinaryZonDecoder();
return decoder.decode(buffer);
}