import { ValueType } from "./encode.ts";
export function decode(uint8: Uint8Array) { const pointer = { consumed: 0 }; const dataView = new DataView( uint8.buffer, uint8.byteOffset, uint8.byteLength, ); const value = decodeSlice(uint8, dataView, pointer);
if (pointer.consumed < uint8.length) { throw new EvalError("Messagepack decode did not consume whole array"); }
return value;}
function decodeString( uint8: Uint8Array, size: number, pointer: { consumed: number },) { pointer.consumed += size; return decoder.decode( uint8.subarray(pointer.consumed - size, pointer.consumed), );}
function decodeArray( uint8: Uint8Array, dataView: DataView, size: number, pointer: { consumed: number },) { const arr: ValueType[] = [];
for (let i = 0; i < size; i++) { const value = decodeSlice(uint8, dataView, pointer); arr.push(value); }
return arr;}
function decodeMap( uint8: Uint8Array, dataView: DataView, size: number, pointer: { consumed: number },) { const map: Record<number | string, ValueType> = {};
for (let i = 0; i < size; i++) { const key = decodeSlice(uint8, dataView, pointer); const value = decodeSlice(uint8, dataView, pointer);
if (typeof key !== "number" && typeof key !== "string") { throw new EvalError( "Messagepack decode came across an invalid type for a key of a map", ); }
map[key] = value; }
return map;}
const decoder = new TextDecoder();
const FIXMAP_BITS = 0b1000_0000;const FIXMAP_MASK = 0b1111_0000;const FIXARRAY_BITS = 0b1001_0000;const FIXARRAY_MASK = 0b1111_0000;const FIXSTR_BITS = 0b1010_0000;const FIXSTR_MASK = 0b1110_0000;
function decodeSlice( uint8: Uint8Array, dataView: DataView, pointer: { consumed: number },): ValueType { const type = dataView.getUint8(pointer.consumed); pointer.consumed++;
if (type <= 0x7f) { return type; }
if ((type & FIXMAP_MASK) === FIXMAP_BITS) { const size = type & ~FIXMAP_MASK; return decodeMap(uint8, dataView, size, pointer); }
if ((type & FIXARRAY_MASK) === FIXARRAY_BITS) { const size = type & ~FIXARRAY_MASK; return decodeArray(uint8, dataView, size, pointer); }
if ((type & FIXSTR_MASK) === FIXSTR_BITS) { const size = type & ~FIXSTR_MASK; return decodeString(uint8, size, pointer); }
if (type >= 0xe0) { return type - 256; }
switch (type) { case 0xc0: return null; case 0xc1: throw new Error( "Messagepack decode encountered a type that is never used", ); case 0xc2: return false; case 0xc3: return true; case 0xc4: { const length = dataView.getUint8(pointer.consumed); pointer.consumed++; const u8 = uint8.subarray(pointer.consumed, pointer.consumed + length); pointer.consumed += length; return u8; } case 0xc5: { const length = dataView.getUint16(pointer.consumed); pointer.consumed += 2; const u8 = uint8.subarray(pointer.consumed, pointer.consumed + length); pointer.consumed += length; return u8; } case 0xc6: { const length = dataView.getUint32(pointer.consumed); pointer.consumed += 4; const u8 = uint8.subarray(pointer.consumed, pointer.consumed + length); pointer.consumed += length; return u8; } case 0xc7: case 0xc8: case 0xc9: throw new Error("ext not implemented yet"); case 0xca: { const value = dataView.getFloat32(pointer.consumed); pointer.consumed += 4; return value; } case 0xcb: { const value = dataView.getFloat64(pointer.consumed); pointer.consumed += 8; return value; } case 0xcc: { const value = dataView.getUint8(pointer.consumed); pointer.consumed += 1; return value; } case 0xcd: { const value = dataView.getUint16(pointer.consumed); pointer.consumed += 2; return value; } case 0xce: { const value = dataView.getUint32(pointer.consumed); pointer.consumed += 4; return value; } case 0xcf: { const value = dataView.getBigUint64(pointer.consumed); pointer.consumed += 8; return value; } case 0xd0: { const value = dataView.getInt8(pointer.consumed); pointer.consumed += 1; return value; } case 0xd1: { const value = dataView.getInt16(pointer.consumed); pointer.consumed += 2; return value; } case 0xd2: { const value = dataView.getInt32(pointer.consumed); pointer.consumed += 4; return value; } case 0xd3: { const value = dataView.getBigInt64(pointer.consumed); pointer.consumed += 8; return value; } case 0xd4: case 0xd5: case 0xd6: case 0xd7: case 0xd8: throw new Error("fixext not implemented yet"); case 0xd9: { const length = dataView.getUint8(pointer.consumed); pointer.consumed += 1; return decodeString(uint8, length, pointer); } case 0xda: { const length = dataView.getUint16(pointer.consumed); pointer.consumed += 2; return decodeString(uint8, length, pointer); } case 0xdb: { const length = dataView.getUint32(pointer.consumed); pointer.consumed += 4; return decodeString(uint8, length, pointer); } case 0xdc: { const length = dataView.getUint16(pointer.consumed); pointer.consumed += 2; return decodeArray(uint8, dataView, length, pointer); } case 0xdd: { const length = dataView.getUint32(pointer.consumed); pointer.consumed += 4; return decodeArray(uint8, dataView, length, pointer); } case 0xde: { const length = dataView.getUint16(pointer.consumed); pointer.consumed += 2; return decodeMap(uint8, dataView, length, pointer); } case 0xdf: { const length = dataView.getUint32(pointer.consumed); pointer.consumed += 4; return decodeMap(uint8, dataView, length, pointer); } }
throw new Error("Unreachable");}