UNPKG

webr

Version:

The statistical programming language R compiled into WASM for use in a web browser and node.

4 lines 309 kB
{ "version": 3, "sources": ["../node_modules/@msgpack/msgpack/src/utils/int.ts", "../node_modules/@msgpack/msgpack/src/utils/utf8.ts", "../node_modules/@msgpack/msgpack/src/ExtData.ts", "../node_modules/@msgpack/msgpack/src/DecodeError.ts", "../node_modules/@msgpack/msgpack/src/timestamp.ts", "../node_modules/@msgpack/msgpack/src/ExtensionCodec.ts", "../node_modules/@msgpack/msgpack/src/utils/typedArrays.ts", "../node_modules/@msgpack/msgpack/src/Encoder.ts", "../node_modules/@msgpack/msgpack/src/encode.ts", "../node_modules/@msgpack/msgpack/src/utils/prettyByte.ts", "../node_modules/@msgpack/msgpack/src/CachedKeyDecoder.ts", "../node_modules/@msgpack/msgpack/src/Decoder.ts", "../node_modules/@msgpack/msgpack/src/decode.ts", "../node_modules/@msgpack/msgpack/src/utils/stream.ts", "../node_modules/@msgpack/msgpack/src/decodeAsync.ts", "../node_modules/@msgpack/msgpack/src/index.ts", "../webR/webr-main.ts", "../webR/error.ts", "../webR/compat.ts", "../webR/robj.ts", "../webR/emscripten.ts", "../webR/utils-r.ts", "../webR/chan/task-common.ts", "../webR/robj-worker.ts", "../webR/utils.ts", "../webR/chan/task-main.ts", "../webR/chan/queue.ts", "../webR/chan/message.ts", "../webR/payload.ts", "../webR/chan/channel.ts", "../webR/chan/task-worker.ts", "../webR/chan/websocket.ts", "../webR/chan/channel-shared.ts", "../webR/chan/channel-postmessage.ts", "../webR/chan/channel-common.ts", "../webR/config.ts", "../webR/robj-main.ts", "../webR/proxy.ts", "../webR/console.ts"], "sourcesContent": ["// Integer Utility\n\nexport const UINT32_MAX = 0xffff_ffff;\n\n// DataView extension to handle int64 / uint64,\n// where the actual range is 53-bits integer (a.k.a. safe integer)\n\nexport function setUint64(view: DataView, offset: number, value: number): void {\n const high = value / 0x1_0000_0000;\n const low = value; // high bits are truncated by DataView\n view.setUint32(offset, high);\n view.setUint32(offset + 4, low);\n}\n\nexport function setInt64(view: DataView, offset: number, value: number): void {\n const high = Math.floor(value / 0x1_0000_0000);\n const low = value; // high bits are truncated by DataView\n view.setUint32(offset, high);\n view.setUint32(offset + 4, low);\n}\n\nexport function getInt64(view: DataView, offset: number): number {\n const high = view.getInt32(offset);\n const low = view.getUint32(offset + 4);\n return high * 0x1_0000_0000 + low;\n}\n\nexport function getUint64(view: DataView, offset: number): number {\n const high = view.getUint32(offset);\n const low = view.getUint32(offset + 4);\n return high * 0x1_0000_0000 + low;\n}\n", "/* eslint-disable @typescript-eslint/no-unnecessary-condition */\nimport { UINT32_MAX } from \"./int\";\n\nconst TEXT_ENCODING_AVAILABLE =\n (typeof process === \"undefined\" || process?.env?.[\"TEXT_ENCODING\"] !== \"never\") &&\n typeof TextEncoder !== \"undefined\" &&\n typeof TextDecoder !== \"undefined\";\n\nexport function utf8Count(str: string): number {\n const strLength = str.length;\n\n let byteLength = 0;\n let pos = 0;\n while (pos < strLength) {\n let value = str.charCodeAt(pos++);\n\n if ((value & 0xffffff80) === 0) {\n // 1-byte\n byteLength++;\n continue;\n } else if ((value & 0xfffff800) === 0) {\n // 2-bytes\n byteLength += 2;\n } else {\n // handle surrogate pair\n if (value >= 0xd800 && value <= 0xdbff) {\n // high surrogate\n if (pos < strLength) {\n const extra = str.charCodeAt(pos);\n if ((extra & 0xfc00) === 0xdc00) {\n ++pos;\n value = ((value & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000;\n }\n }\n }\n\n if ((value & 0xffff0000) === 0) {\n // 3-byte\n byteLength += 3;\n } else {\n // 4-byte\n byteLength += 4;\n }\n }\n }\n return byteLength;\n}\n\nexport function utf8EncodeJs(str: string, output: Uint8Array, outputOffset: number): void {\n const strLength = str.length;\n let offset = outputOffset;\n let pos = 0;\n while (pos < strLength) {\n let value = str.charCodeAt(pos++);\n\n if ((value & 0xffffff80) === 0) {\n // 1-byte\n output[offset++] = value;\n continue;\n } else if ((value & 0xfffff800) === 0) {\n // 2-bytes\n output[offset++] = ((value >> 6) & 0x1f) | 0xc0;\n } else {\n // handle surrogate pair\n if (value >= 0xd800 && value <= 0xdbff) {\n // high surrogate\n if (pos < strLength) {\n const extra = str.charCodeAt(pos);\n if ((extra & 0xfc00) === 0xdc00) {\n ++pos;\n value = ((value & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000;\n }\n }\n }\n\n if ((value & 0xffff0000) === 0) {\n // 3-byte\n output[offset++] = ((value >> 12) & 0x0f) | 0xe0;\n output[offset++] = ((value >> 6) & 0x3f) | 0x80;\n } else {\n // 4-byte\n output[offset++] = ((value >> 18) & 0x07) | 0xf0;\n output[offset++] = ((value >> 12) & 0x3f) | 0x80;\n output[offset++] = ((value >> 6) & 0x3f) | 0x80;\n }\n }\n\n output[offset++] = (value & 0x3f) | 0x80;\n }\n}\n\nconst sharedTextEncoder = TEXT_ENCODING_AVAILABLE ? new TextEncoder() : undefined;\nexport const TEXT_ENCODER_THRESHOLD = !TEXT_ENCODING_AVAILABLE\n ? UINT32_MAX\n : typeof process !== \"undefined\" && process?.env?.[\"TEXT_ENCODING\"] !== \"force\"\n ? 200\n : 0;\n\nfunction utf8EncodeTEencode(str: string, output: Uint8Array, outputOffset: number): void {\n output.set(sharedTextEncoder!.encode(str), outputOffset);\n}\n\nfunction utf8EncodeTEencodeInto(str: string, output: Uint8Array, outputOffset: number): void {\n sharedTextEncoder!.encodeInto(str, output.subarray(outputOffset));\n}\n\nexport const utf8EncodeTE = sharedTextEncoder?.encodeInto ? utf8EncodeTEencodeInto : utf8EncodeTEencode;\n\nconst CHUNK_SIZE = 0x1_000;\n\nexport function utf8DecodeJs(bytes: Uint8Array, inputOffset: number, byteLength: number): string {\n let offset = inputOffset;\n const end = offset + byteLength;\n\n const units: Array<number> = [];\n let result = \"\";\n while (offset < end) {\n const byte1 = bytes[offset++]!;\n if ((byte1 & 0x80) === 0) {\n // 1 byte\n units.push(byte1);\n } else if ((byte1 & 0xe0) === 0xc0) {\n // 2 bytes\n const byte2 = bytes[offset++]! & 0x3f;\n units.push(((byte1 & 0x1f) << 6) | byte2);\n } else if ((byte1 & 0xf0) === 0xe0) {\n // 3 bytes\n const byte2 = bytes[offset++]! & 0x3f;\n const byte3 = bytes[offset++]! & 0x3f;\n units.push(((byte1 & 0x1f) << 12) | (byte2 << 6) | byte3);\n } else if ((byte1 & 0xf8) === 0xf0) {\n // 4 bytes\n const byte2 = bytes[offset++]! & 0x3f;\n const byte3 = bytes[offset++]! & 0x3f;\n const byte4 = bytes[offset++]! & 0x3f;\n let unit = ((byte1 & 0x07) << 0x12) | (byte2 << 0x0c) | (byte3 << 0x06) | byte4;\n if (unit > 0xffff) {\n unit -= 0x10000;\n units.push(((unit >>> 10) & 0x3ff) | 0xd800);\n unit = 0xdc00 | (unit & 0x3ff);\n }\n units.push(unit);\n } else {\n units.push(byte1);\n }\n\n if (units.length >= CHUNK_SIZE) {\n result += String.fromCharCode(...units);\n units.length = 0;\n }\n }\n\n if (units.length > 0) {\n result += String.fromCharCode(...units);\n }\n\n return result;\n}\n\nconst sharedTextDecoder = TEXT_ENCODING_AVAILABLE ? new TextDecoder() : null;\nexport const TEXT_DECODER_THRESHOLD = !TEXT_ENCODING_AVAILABLE\n ? UINT32_MAX\n : typeof process !== \"undefined\" && process?.env?.[\"TEXT_DECODER\"] !== \"force\"\n ? 200\n : 0;\n\nexport function utf8DecodeTD(bytes: Uint8Array, inputOffset: number, byteLength: number): string {\n const stringBytes = bytes.subarray(inputOffset, inputOffset + byteLength);\n return sharedTextDecoder!.decode(stringBytes);\n}\n", "/**\n * ExtData is used to handle Extension Types that are not registered to ExtensionCodec.\n */\nexport class ExtData {\n constructor(readonly type: number, readonly data: Uint8Array) {}\n}\n", "export class DecodeError extends Error {\n constructor(message: string) {\n super(message);\n\n // fix the prototype chain in a cross-platform way\n const proto: typeof DecodeError.prototype = Object.create(DecodeError.prototype);\n Object.setPrototypeOf(this, proto);\n\n Object.defineProperty(this, \"name\", {\n configurable: true,\n enumerable: false,\n value: DecodeError.name,\n });\n }\n}\n", "// https://github.com/msgpack/msgpack/blob/master/spec.md#timestamp-extension-type\nimport { DecodeError } from \"./DecodeError\";\nimport { getInt64, setInt64 } from \"./utils/int\";\n\nexport const EXT_TIMESTAMP = -1;\n\nexport type TimeSpec = {\n sec: number;\n nsec: number;\n};\n\nconst TIMESTAMP32_MAX_SEC = 0x100000000 - 1; // 32-bit unsigned int\nconst TIMESTAMP64_MAX_SEC = 0x400000000 - 1; // 34-bit unsigned int\n\nexport function encodeTimeSpecToTimestamp({ sec, nsec }: TimeSpec): Uint8Array {\n if (sec >= 0 && nsec >= 0 && sec <= TIMESTAMP64_MAX_SEC) {\n // Here sec >= 0 && nsec >= 0\n if (nsec === 0 && sec <= TIMESTAMP32_MAX_SEC) {\n // timestamp 32 = { sec32 (unsigned) }\n const rv = new Uint8Array(4);\n const view = new DataView(rv.buffer);\n view.setUint32(0, sec);\n return rv;\n } else {\n // timestamp 64 = { nsec30 (unsigned), sec34 (unsigned) }\n const secHigh = sec / 0x100000000;\n const secLow = sec & 0xffffffff;\n const rv = new Uint8Array(8);\n const view = new DataView(rv.buffer);\n // nsec30 | secHigh2\n view.setUint32(0, (nsec << 2) | (secHigh & 0x3));\n // secLow32\n view.setUint32(4, secLow);\n return rv;\n }\n } else {\n // timestamp 96 = { nsec32 (unsigned), sec64 (signed) }\n const rv = new Uint8Array(12);\n const view = new DataView(rv.buffer);\n view.setUint32(0, nsec);\n setInt64(view, 4, sec);\n return rv;\n }\n}\n\nexport function encodeDateToTimeSpec(date: Date): TimeSpec {\n const msec = date.getTime();\n const sec = Math.floor(msec / 1e3);\n const nsec = (msec - sec * 1e3) * 1e6;\n\n // Normalizes { sec, nsec } to ensure nsec is unsigned.\n const nsecInSec = Math.floor(nsec / 1e9);\n return {\n sec: sec + nsecInSec,\n nsec: nsec - nsecInSec * 1e9,\n };\n}\n\nexport function encodeTimestampExtension(object: unknown): Uint8Array | null {\n if (object instanceof Date) {\n const timeSpec = encodeDateToTimeSpec(object);\n return encodeTimeSpecToTimestamp(timeSpec);\n } else {\n return null;\n }\n}\n\nexport function decodeTimestampToTimeSpec(data: Uint8Array): TimeSpec {\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n\n // data may be 32, 64, or 96 bits\n switch (data.byteLength) {\n case 4: {\n // timestamp 32 = { sec32 }\n const sec = view.getUint32(0);\n const nsec = 0;\n return { sec, nsec };\n }\n case 8: {\n // timestamp 64 = { nsec30, sec34 }\n const nsec30AndSecHigh2 = view.getUint32(0);\n const secLow32 = view.getUint32(4);\n const sec = (nsec30AndSecHigh2 & 0x3) * 0x100000000 + secLow32;\n const nsec = nsec30AndSecHigh2 >>> 2;\n return { sec, nsec };\n }\n case 12: {\n // timestamp 96 = { nsec32 (unsigned), sec64 (signed) }\n\n const sec = getInt64(view, 4);\n const nsec = view.getUint32(0);\n return { sec, nsec };\n }\n default:\n throw new DecodeError(`Unrecognized data size for timestamp (expected 4, 8, or 12): ${data.length}`);\n }\n}\n\nexport function decodeTimestampExtension(data: Uint8Array): Date {\n const timeSpec = decodeTimestampToTimeSpec(data);\n return new Date(timeSpec.sec * 1e3 + timeSpec.nsec / 1e6);\n}\n\nexport const timestampExtension = {\n type: EXT_TIMESTAMP,\n encode: encodeTimestampExtension,\n decode: decodeTimestampExtension,\n};\n", "// ExtensionCodec to handle MessagePack extensions\n\nimport { ExtData } from \"./ExtData\";\nimport { timestampExtension } from \"./timestamp\";\n\nexport type ExtensionDecoderType<ContextType> = (\n data: Uint8Array,\n extensionType: number,\n context: ContextType,\n) => unknown;\n\nexport type ExtensionEncoderType<ContextType> = (input: unknown, context: ContextType) => Uint8Array | null;\n\n// immutable interface to ExtensionCodec\nexport type ExtensionCodecType<ContextType> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n __brand?: ContextType;\n tryToEncode(object: unknown, context: ContextType): ExtData | null;\n decode(data: Uint8Array, extType: number, context: ContextType): unknown;\n};\n\nexport class ExtensionCodec<ContextType = undefined> implements ExtensionCodecType<ContextType> {\n public static readonly defaultCodec: ExtensionCodecType<undefined> = new ExtensionCodec();\n\n // ensures ExtensionCodecType<X> matches ExtensionCodec<X>\n // this will make type errors a lot more clear\n // eslint-disable-next-line @typescript-eslint/naming-convention\n __brand?: ContextType;\n\n // built-in extensions\n private readonly builtInEncoders: Array<ExtensionEncoderType<ContextType> | undefined | null> = [];\n private readonly builtInDecoders: Array<ExtensionDecoderType<ContextType> | undefined | null> = [];\n\n // custom extensions\n private readonly encoders: Array<ExtensionEncoderType<ContextType> | undefined | null> = [];\n private readonly decoders: Array<ExtensionDecoderType<ContextType> | undefined | null> = [];\n\n public constructor() {\n this.register(timestampExtension);\n }\n\n public register({\n type,\n encode,\n decode,\n }: {\n type: number;\n encode: ExtensionEncoderType<ContextType>;\n decode: ExtensionDecoderType<ContextType>;\n }): void {\n if (type >= 0) {\n // custom extensions\n this.encoders[type] = encode;\n this.decoders[type] = decode;\n } else {\n // built-in extensions\n const index = 1 + type;\n this.builtInEncoders[index] = encode;\n this.builtInDecoders[index] = decode;\n }\n }\n\n public tryToEncode(object: unknown, context: ContextType): ExtData | null {\n // built-in extensions\n for (let i = 0; i < this.builtInEncoders.length; i++) {\n const encodeExt = this.builtInEncoders[i];\n if (encodeExt != null) {\n const data = encodeExt(object, context);\n if (data != null) {\n const type = -1 - i;\n return new ExtData(type, data);\n }\n }\n }\n\n // custom extensions\n for (let i = 0; i < this.encoders.length; i++) {\n const encodeExt = this.encoders[i];\n if (encodeExt != null) {\n const data = encodeExt(object, context);\n if (data != null) {\n const type = i;\n return new ExtData(type, data);\n }\n }\n }\n\n if (object instanceof ExtData) {\n // to keep ExtData as is\n return object;\n }\n return null;\n }\n\n public decode(data: Uint8Array, type: number, context: ContextType): unknown {\n const decodeExt = type < 0 ? this.builtInDecoders[-1 - type] : this.decoders[type];\n if (decodeExt) {\n return decodeExt(data, type, context);\n } else {\n // decode() does not fail, returns ExtData instead.\n return new ExtData(type, data);\n }\n }\n}\n", "export function ensureUint8Array(buffer: ArrayLike<number> | Uint8Array | ArrayBufferView | ArrayBuffer): Uint8Array {\n if (buffer instanceof Uint8Array) {\n return buffer;\n } else if (ArrayBuffer.isView(buffer)) {\n return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);\n } else if (buffer instanceof ArrayBuffer) {\n return new Uint8Array(buffer);\n } else {\n // ArrayLike<number>\n return Uint8Array.from(buffer);\n }\n}\n\nexport function createDataView(buffer: ArrayLike<number> | ArrayBufferView | ArrayBuffer): DataView {\n if (buffer instanceof ArrayBuffer) {\n return new DataView(buffer);\n }\n\n const bufferView = ensureUint8Array(buffer);\n return new DataView(bufferView.buffer, bufferView.byteOffset, bufferView.byteLength);\n}\n", "import { utf8EncodeJs, utf8Count, TEXT_ENCODER_THRESHOLD, utf8EncodeTE } from \"./utils/utf8\";\nimport { ExtensionCodec, ExtensionCodecType } from \"./ExtensionCodec\";\nimport { setInt64, setUint64 } from \"./utils/int\";\nimport { ensureUint8Array } from \"./utils/typedArrays\";\nimport type { ExtData } from \"./ExtData\";\n\nexport const DEFAULT_MAX_DEPTH = 100;\nexport const DEFAULT_INITIAL_BUFFER_SIZE = 2048;\n\nexport class Encoder<ContextType = undefined> {\n private pos = 0;\n private view = new DataView(new ArrayBuffer(this.initialBufferSize));\n private bytes = new Uint8Array(this.view.buffer);\n\n public constructor(\n private readonly extensionCodec: ExtensionCodecType<ContextType> = ExtensionCodec.defaultCodec as any,\n private readonly context: ContextType = undefined as any,\n private readonly maxDepth = DEFAULT_MAX_DEPTH,\n private readonly initialBufferSize = DEFAULT_INITIAL_BUFFER_SIZE,\n private readonly sortKeys = false,\n private readonly forceFloat32 = false,\n private readonly ignoreUndefined = false,\n private readonly forceIntegerToFloat = false,\n ) {}\n\n private reinitializeState() {\n this.pos = 0;\n }\n\n /**\n * This is almost equivalent to {@link Encoder#encode}, but it returns an reference of the encoder's internal buffer and thus much faster than {@link Encoder#encode}.\n *\n * @returns Encodes the object and returns a shared reference the encoder's internal buffer.\n */\n public encodeSharedRef(object: unknown): Uint8Array {\n this.reinitializeState();\n this.doEncode(object, 1);\n return this.bytes.subarray(0, this.pos);\n }\n\n /**\n * @returns Encodes the object and returns a copy of the encoder's internal buffer.\n */\n public encode(object: unknown): Uint8Array {\n this.reinitializeState();\n this.doEncode(object, 1);\n return this.bytes.slice(0, this.pos);\n }\n\n private doEncode(object: unknown, depth: number): void {\n if (depth > this.maxDepth) {\n throw new Error(`Too deep objects in depth ${depth}`);\n }\n\n if (object == null) {\n this.encodeNil();\n } else if (typeof object === \"boolean\") {\n this.encodeBoolean(object);\n } else if (typeof object === \"number\") {\n this.encodeNumber(object);\n } else if (typeof object === \"string\") {\n this.encodeString(object);\n } else {\n this.encodeObject(object, depth);\n }\n }\n\n private ensureBufferSizeToWrite(sizeToWrite: number) {\n const requiredSize = this.pos + sizeToWrite;\n\n if (this.view.byteLength < requiredSize) {\n this.resizeBuffer(requiredSize * 2);\n }\n }\n\n private resizeBuffer(newSize: number) {\n const newBuffer = new ArrayBuffer(newSize);\n const newBytes = new Uint8Array(newBuffer);\n const newView = new DataView(newBuffer);\n\n newBytes.set(this.bytes);\n\n this.view = newView;\n this.bytes = newBytes;\n }\n\n private encodeNil() {\n this.writeU8(0xc0);\n }\n\n private encodeBoolean(object: boolean) {\n if (object === false) {\n this.writeU8(0xc2);\n } else {\n this.writeU8(0xc3);\n }\n }\n private encodeNumber(object: number) {\n if (Number.isSafeInteger(object) && !this.forceIntegerToFloat) {\n if (object >= 0) {\n if (object < 0x80) {\n // positive fixint\n this.writeU8(object);\n } else if (object < 0x100) {\n // uint 8\n this.writeU8(0xcc);\n this.writeU8(object);\n } else if (object < 0x10000) {\n // uint 16\n this.writeU8(0xcd);\n this.writeU16(object);\n } else if (object < 0x100000000) {\n // uint 32\n this.writeU8(0xce);\n this.writeU32(object);\n } else {\n // uint 64\n this.writeU8(0xcf);\n this.writeU64(object);\n }\n } else {\n if (object >= -0x20) {\n // negative fixint\n this.writeU8(0xe0 | (object + 0x20));\n } else if (object >= -0x80) {\n // int 8\n this.writeU8(0xd0);\n this.writeI8(object);\n } else if (object >= -0x8000) {\n // int 16\n this.writeU8(0xd1);\n this.writeI16(object);\n } else if (object >= -0x80000000) {\n // int 32\n this.writeU8(0xd2);\n this.writeI32(object);\n } else {\n // int 64\n this.writeU8(0xd3);\n this.writeI64(object);\n }\n }\n } else {\n // non-integer numbers\n if (this.forceFloat32) {\n // float 32\n this.writeU8(0xca);\n this.writeF32(object);\n } else {\n // float 64\n this.writeU8(0xcb);\n this.writeF64(object);\n }\n }\n }\n\n private writeStringHeader(byteLength: number) {\n if (byteLength < 32) {\n // fixstr\n this.writeU8(0xa0 + byteLength);\n } else if (byteLength < 0x100) {\n // str 8\n this.writeU8(0xd9);\n this.writeU8(byteLength);\n } else if (byteLength < 0x10000) {\n // str 16\n this.writeU8(0xda);\n this.writeU16(byteLength);\n } else if (byteLength < 0x100000000) {\n // str 32\n this.writeU8(0xdb);\n this.writeU32(byteLength);\n } else {\n throw new Error(`Too long string: ${byteLength} bytes in UTF-8`);\n }\n }\n\n private encodeString(object: string) {\n const maxHeaderSize = 1 + 4;\n const strLength = object.length;\n\n if (strLength > TEXT_ENCODER_THRESHOLD) {\n const byteLength = utf8Count(object);\n this.ensureBufferSizeToWrite(maxHeaderSize + byteLength);\n this.writeStringHeader(byteLength);\n utf8EncodeTE(object, this.bytes, this.pos);\n this.pos += byteLength;\n } else {\n const byteLength = utf8Count(object);\n this.ensureBufferSizeToWrite(maxHeaderSize + byteLength);\n this.writeStringHeader(byteLength);\n utf8EncodeJs(object, this.bytes, this.pos);\n this.pos += byteLength;\n }\n }\n\n private encodeObject(object: unknown, depth: number) {\n // try to encode objects with custom codec first of non-primitives\n const ext = this.extensionCodec.tryToEncode(object, this.context);\n if (ext != null) {\n this.encodeExtension(ext);\n } else if (Array.isArray(object)) {\n this.encodeArray(object, depth);\n } else if (ArrayBuffer.isView(object)) {\n this.encodeBinary(object);\n } else if (typeof object === \"object\") {\n this.encodeMap(object as Record<string, unknown>, depth);\n } else {\n // symbol, function and other special object come here unless extensionCodec handles them.\n throw new Error(`Unrecognized object: ${Object.prototype.toString.apply(object)}`);\n }\n }\n\n private encodeBinary(object: ArrayBufferView) {\n const size = object.byteLength;\n if (size < 0x100) {\n // bin 8\n this.writeU8(0xc4);\n this.writeU8(size);\n } else if (size < 0x10000) {\n // bin 16\n this.writeU8(0xc5);\n this.writeU16(size);\n } else if (size < 0x100000000) {\n // bin 32\n this.writeU8(0xc6);\n this.writeU32(size);\n } else {\n throw new Error(`Too large binary: ${size}`);\n }\n const bytes = ensureUint8Array(object);\n this.writeU8a(bytes);\n }\n\n private encodeArray(object: Array<unknown>, depth: number) {\n const size = object.length;\n if (size < 16) {\n // fixarray\n this.writeU8(0x90 + size);\n } else if (size < 0x10000) {\n // array 16\n this.writeU8(0xdc);\n this.writeU16(size);\n } else if (size < 0x100000000) {\n // array 32\n this.writeU8(0xdd);\n this.writeU32(size);\n } else {\n throw new Error(`Too large array: ${size}`);\n }\n for (const item of object) {\n this.doEncode(item, depth + 1);\n }\n }\n\n private countWithoutUndefined(object: Record<string, unknown>, keys: ReadonlyArray<string>): number {\n let count = 0;\n\n for (const key of keys) {\n if (object[key] !== undefined) {\n count++;\n }\n }\n\n return count;\n }\n\n private encodeMap(object: Record<string, unknown>, depth: number) {\n const keys = Object.keys(object);\n if (this.sortKeys) {\n keys.sort();\n }\n\n const size = this.ignoreUndefined ? this.countWithoutUndefined(object, keys) : keys.length;\n\n if (size < 16) {\n // fixmap\n this.writeU8(0x80 + size);\n } else if (size < 0x10000) {\n // map 16\n this.writeU8(0xde);\n this.writeU16(size);\n } else if (size < 0x100000000) {\n // map 32\n this.writeU8(0xdf);\n this.writeU32(size);\n } else {\n throw new Error(`Too large map object: ${size}`);\n }\n\n for (const key of keys) {\n const value = object[key];\n\n if (!(this.ignoreUndefined && value === undefined)) {\n this.encodeString(key);\n this.doEncode(value, depth + 1);\n }\n }\n }\n\n private encodeExtension(ext: ExtData) {\n const size = ext.data.length;\n if (size === 1) {\n // fixext 1\n this.writeU8(0xd4);\n } else if (size === 2) {\n // fixext 2\n this.writeU8(0xd5);\n } else if (size === 4) {\n // fixext 4\n this.writeU8(0xd6);\n } else if (size === 8) {\n // fixext 8\n this.writeU8(0xd7);\n } else if (size === 16) {\n // fixext 16\n this.writeU8(0xd8);\n } else if (size < 0x100) {\n // ext 8\n this.writeU8(0xc7);\n this.writeU8(size);\n } else if (size < 0x10000) {\n // ext 16\n this.writeU8(0xc8);\n this.writeU16(size);\n } else if (size < 0x100000000) {\n // ext 32\n this.writeU8(0xc9);\n this.writeU32(size);\n } else {\n throw new Error(`Too large extension object: ${size}`);\n }\n this.writeI8(ext.type);\n this.writeU8a(ext.data);\n }\n\n private writeU8(value: number) {\n this.ensureBufferSizeToWrite(1);\n\n this.view.setUint8(this.pos, value);\n this.pos++;\n }\n\n private writeU8a(values: ArrayLike<number>) {\n const size = values.length;\n this.ensureBufferSizeToWrite(size);\n\n this.bytes.set(values, this.pos);\n this.pos += size;\n }\n\n private writeI8(value: number) {\n this.ensureBufferSizeToWrite(1);\n\n this.view.setInt8(this.pos, value);\n this.pos++;\n }\n\n private writeU16(value: number) {\n this.ensureBufferSizeToWrite(2);\n\n this.view.setUint16(this.pos, value);\n this.pos += 2;\n }\n\n private writeI16(value: number) {\n this.ensureBufferSizeToWrite(2);\n\n this.view.setInt16(this.pos, value);\n this.pos += 2;\n }\n\n private writeU32(value: number) {\n this.ensureBufferSizeToWrite(4);\n\n this.view.setUint32(this.pos, value);\n this.pos += 4;\n }\n\n private writeI32(value: number) {\n this.ensureBufferSizeToWrite(4);\n\n this.view.setInt32(this.pos, value);\n this.pos += 4;\n }\n\n private writeF32(value: number) {\n this.ensureBufferSizeToWrite(4);\n this.view.setFloat32(this.pos, value);\n this.pos += 4;\n }\n\n private writeF64(value: number) {\n this.ensureBufferSizeToWrite(8);\n this.view.setFloat64(this.pos, value);\n this.pos += 8;\n }\n\n private writeU64(value: number) {\n this.ensureBufferSizeToWrite(8);\n\n setUint64(this.view, this.pos, value);\n this.pos += 8;\n }\n\n private writeI64(value: number) {\n this.ensureBufferSizeToWrite(8);\n\n setInt64(this.view, this.pos, value);\n this.pos += 8;\n }\n}\n", "import { Encoder } from \"./Encoder\";\nimport type { ExtensionCodecType } from \"./ExtensionCodec\";\nimport type { ContextOf, SplitUndefined } from \"./context\";\n\nexport type EncodeOptions<ContextType = undefined> = Partial<\n Readonly<{\n extensionCodec: ExtensionCodecType<ContextType>;\n\n /**\n * The maximum depth in nested objects and arrays.\n *\n * Defaults to 100.\n */\n maxDepth: number;\n\n /**\n * The initial size of the internal buffer.\n *\n * Defaults to 2048.\n */\n initialBufferSize: number;\n\n /**\n * If `true`, the keys of an object is sorted. In other words, the encoded\n * binary is canonical and thus comparable to another encoded binary.\n *\n * Defaults to `false`. If enabled, it spends more time in encoding objects.\n */\n sortKeys: boolean;\n /**\n * If `true`, non-integer numbers are encoded in float32, not in float64 (the default).\n *\n * Only use it if precisions don't matter.\n *\n * Defaults to `false`.\n */\n forceFloat32: boolean;\n\n /**\n * If `true`, an object property with `undefined` value are ignored.\n * e.g. `{ foo: undefined }` will be encoded as `{}`, as `JSON.stringify()` does.\n *\n * Defaults to `false`. If enabled, it spends more time in encoding objects.\n */\n ignoreUndefined: boolean;\n\n /**\n * If `true`, integer numbers are encoded as floating point numbers,\n * with the `forceFloat32` option taken into account.\n *\n * Defaults to `false`.\n */\n forceIntegerToFloat: boolean;\n }>\n> &\n ContextOf<ContextType>;\n\nconst defaultEncodeOptions: EncodeOptions = {};\n\n/**\n * It encodes `value` in the MessagePack format and\n * returns a byte buffer.\n *\n * The returned buffer is a slice of a larger `ArrayBuffer`, so you have to use its `#byteOffset` and `#byteLength` in order to convert it to another typed arrays including NodeJS `Buffer`.\n */\nexport function encode<ContextType = undefined>(\n value: unknown,\n options: EncodeOptions<SplitUndefined<ContextType>> = defaultEncodeOptions as any,\n): Uint8Array {\n const encoder = new Encoder(\n options.extensionCodec,\n (options as typeof options & { context: any }).context,\n options.maxDepth,\n options.initialBufferSize,\n options.sortKeys,\n options.forceFloat32,\n options.ignoreUndefined,\n options.forceIntegerToFloat,\n );\n return encoder.encodeSharedRef(value);\n}\n", "export function prettyByte(byte: number): string {\n return `${byte < 0 ? \"-\" : \"\"}0x${Math.abs(byte).toString(16).padStart(2, \"0\")}`;\n}\n", "import { utf8DecodeJs } from \"./utils/utf8\";\n\nconst DEFAULT_MAX_KEY_LENGTH = 16;\nconst DEFAULT_MAX_LENGTH_PER_KEY = 16;\n\nexport interface KeyDecoder {\n canBeCached(byteLength: number): boolean;\n decode(bytes: Uint8Array, inputOffset: number, byteLength: number): string;\n}\ninterface KeyCacheRecord {\n readonly bytes: Uint8Array;\n readonly str: string;\n}\n\nexport class CachedKeyDecoder implements KeyDecoder {\n hit = 0;\n miss = 0;\n private readonly caches: Array<Array<KeyCacheRecord>>;\n\n constructor(readonly maxKeyLength = DEFAULT_MAX_KEY_LENGTH, readonly maxLengthPerKey = DEFAULT_MAX_LENGTH_PER_KEY) {\n // avoid `new Array(N)`, which makes a sparse array,\n // because a sparse array is typically slower than a non-sparse array.\n this.caches = [];\n for (let i = 0; i < this.maxKeyLength; i++) {\n this.caches.push([]);\n }\n }\n\n public canBeCached(byteLength: number): boolean {\n return byteLength > 0 && byteLength <= this.maxKeyLength;\n }\n\n private find(bytes: Uint8Array, inputOffset: number, byteLength: number): string | null {\n const records = this.caches[byteLength - 1]!;\n\n FIND_CHUNK: for (const record of records) {\n const recordBytes = record.bytes;\n\n for (let j = 0; j < byteLength; j++) {\n if (recordBytes[j] !== bytes[inputOffset + j]) {\n continue FIND_CHUNK;\n }\n }\n return record.str;\n }\n return null;\n }\n\n private store(bytes: Uint8Array, value: string) {\n const records = this.caches[bytes.length - 1]!;\n const record: KeyCacheRecord = { bytes, str: value };\n\n if (records.length >= this.maxLengthPerKey) {\n // `records` are full!\n // Set `record` to an arbitrary position.\n records[(Math.random() * records.length) | 0] = record;\n } else {\n records.push(record);\n }\n }\n\n public decode(bytes: Uint8Array, inputOffset: number, byteLength: number): string {\n const cachedValue = this.find(bytes, inputOffset, byteLength);\n if (cachedValue != null) {\n this.hit++;\n return cachedValue;\n }\n this.miss++;\n\n const str = utf8DecodeJs(bytes, inputOffset, byteLength);\n // Ensure to copy a slice of bytes because the byte may be NodeJS Buffer and Buffer#slice() returns a reference to its internal ArrayBuffer.\n const slicedCopyOfBytes = Uint8Array.prototype.slice.call(bytes, inputOffset, inputOffset + byteLength);\n this.store(slicedCopyOfBytes, str);\n return str;\n }\n}\n", "import { prettyByte } from \"./utils/prettyByte\";\nimport { ExtensionCodec, ExtensionCodecType } from \"./ExtensionCodec\";\nimport { getInt64, getUint64, UINT32_MAX } from \"./utils/int\";\nimport { utf8DecodeJs, TEXT_DECODER_THRESHOLD, utf8DecodeTD } from \"./utils/utf8\";\nimport { createDataView, ensureUint8Array } from \"./utils/typedArrays\";\nimport { CachedKeyDecoder, KeyDecoder } from \"./CachedKeyDecoder\";\nimport { DecodeError } from \"./DecodeError\";\n\nconst enum State {\n ARRAY,\n MAP_KEY,\n MAP_VALUE,\n}\n\ntype MapKeyType = string | number;\n\nconst isValidMapKeyType = (key: unknown): key is MapKeyType => {\n const keyType = typeof key;\n\n return keyType === \"string\" || keyType === \"number\";\n};\n\ntype StackMapState = {\n type: State.MAP_KEY | State.MAP_VALUE;\n size: number;\n key: MapKeyType | null;\n readCount: number;\n map: Record<string, unknown>;\n};\n\ntype StackArrayState = {\n type: State.ARRAY;\n size: number;\n array: Array<unknown>;\n position: number;\n};\n\ntype StackState = StackArrayState | StackMapState;\n\nconst HEAD_BYTE_REQUIRED = -1;\n\nconst EMPTY_VIEW = new DataView(new ArrayBuffer(0));\nconst EMPTY_BYTES = new Uint8Array(EMPTY_VIEW.buffer);\n\n// IE11: Hack to support IE11.\n// IE11: Drop this hack and just use RangeError when IE11 is obsolete.\nexport const DataViewIndexOutOfBoundsError: typeof Error = (() => {\n try {\n // IE11: The spec says it should throw RangeError,\n // IE11: but in IE11 it throws TypeError.\n EMPTY_VIEW.getInt8(0);\n } catch (e: any) {\n return e.constructor;\n }\n throw new Error(\"never reached\");\n})();\n\nconst MORE_DATA = new DataViewIndexOutOfBoundsError(\"Insufficient data\");\n\nconst sharedCachedKeyDecoder = new CachedKeyDecoder();\n\nexport class Decoder<ContextType = undefined> {\n private totalPos = 0;\n private pos = 0;\n\n private view = EMPTY_VIEW;\n private bytes = EMPTY_BYTES;\n private headByte = HEAD_BYTE_REQUIRED;\n private readonly stack: Array<StackState> = [];\n\n public constructor(\n private readonly extensionCodec: ExtensionCodecType<ContextType> = ExtensionCodec.defaultCodec as any,\n private readonly context: ContextType = undefined as any,\n private readonly maxStrLength = UINT32_MAX,\n private readonly maxBinLength = UINT32_MAX,\n private readonly maxArrayLength = UINT32_MAX,\n private readonly maxMapLength = UINT32_MAX,\n private readonly maxExtLength = UINT32_MAX,\n private readonly keyDecoder: KeyDecoder | null = sharedCachedKeyDecoder,\n ) {}\n\n private reinitializeState() {\n this.totalPos = 0;\n this.headByte = HEAD_BYTE_REQUIRED;\n this.stack.length = 0;\n\n // view, bytes, and pos will be re-initialized in setBuffer()\n }\n\n private setBuffer(buffer: ArrayLike<number> | BufferSource): void {\n this.bytes = ensureUint8Array(buffer);\n this.view = createDataView(this.bytes);\n this.pos = 0;\n }\n\n private appendBuffer(buffer: ArrayLike<number> | BufferSource) {\n if (this.headByte === HEAD_BYTE_REQUIRED && !this.hasRemaining(1)) {\n this.setBuffer(buffer);\n } else {\n const remainingData = this.bytes.subarray(this.pos);\n const newData = ensureUint8Array(buffer);\n\n // concat remainingData + newData\n const newBuffer = new Uint8Array(remainingData.length + newData.length);\n newBuffer.set(remainingData);\n newBuffer.set(newData, remainingData.length);\n this.setBuffer(newBuffer);\n }\n }\n\n private hasRemaining(size: number) {\n return this.view.byteLength - this.pos >= size;\n }\n\n private createExtraByteError(posToShow: number): Error {\n const { view, pos } = this;\n return new RangeError(`Extra ${view.byteLength - pos} of ${view.byteLength} byte(s) found at buffer[${posToShow}]`);\n }\n\n /**\n * @throws {@link DecodeError}\n * @throws {@link RangeError}\n */\n public decode(buffer: ArrayLike<number> | BufferSource): unknown {\n this.reinitializeState();\n this.setBuffer(buffer);\n\n const object = this.doDecodeSync();\n if (this.hasRemaining(1)) {\n throw this.createExtraByteError(this.pos);\n }\n return object;\n }\n\n public *decodeMulti(buffer: ArrayLike<number> | BufferSource): Generator<unknown, void, unknown> {\n this.reinitializeState();\n this.setBuffer(buffer);\n\n while (this.hasRemaining(1)) {\n yield this.doDecodeSync();\n }\n }\n\n public async decodeAsync(stream: AsyncIterable<ArrayLike<number> | BufferSource>): Promise<unknown> {\n let decoded = false;\n let object: unknown;\n for await (const buffer of stream) {\n if (decoded) {\n throw this.createExtraByteError(this.totalPos);\n }\n\n this.appendBuffer(buffer);\n\n try {\n object = this.doDecodeSync();\n decoded = true;\n } catch (e) {\n if (!(e instanceof DataViewIndexOutOfBoundsError)) {\n throw e; // rethrow\n }\n // fallthrough\n }\n this.totalPos += this.pos;\n }\n\n if (decoded) {\n if (this.hasRemaining(1)) {\n throw this.createExtraByteError(this.totalPos);\n }\n return object;\n }\n\n const { headByte, pos, totalPos } = this;\n throw new RangeError(\n `Insufficient data in parsing ${prettyByte(headByte)} at ${totalPos} (${pos} in the current buffer)`,\n );\n }\n\n public decodeArrayStream(\n stream: AsyncIterable<ArrayLike<number> | BufferSource>,\n ): AsyncGenerator<unknown, void, unknown> {\n return this.decodeMultiAsync(stream, true);\n }\n\n public decodeStream(stream: AsyncIterable<ArrayLike<number> | BufferSource>): AsyncGenerator<unknown, void, unknown> {\n return this.decodeMultiAsync(stream, false);\n }\n\n private async *decodeMultiAsync(stream: AsyncIterable<ArrayLike<number> | BufferSource>, isArray: boolean) {\n let isArrayHeaderRequired = isArray;\n let arrayItemsLeft = -1;\n\n for await (const buffer of stream) {\n if (isArray && arrayItemsLeft === 0) {\n throw this.createExtraByteError(this.totalPos);\n }\n\n this.appendBuffer(buffer);\n\n if (isArrayHeaderRequired) {\n arrayItemsLeft = this.readArraySize();\n isArrayHeaderRequired = false;\n this.complete();\n }\n\n try {\n while (true) {\n yield this.doDecodeSync();\n if (--arrayItemsLeft === 0) {\n break;\n }\n }\n } catch (e) {\n if (!(e instanceof DataViewIndexOutOfBoundsError)) {\n throw e; // rethrow\n }\n // fallthrough\n }\n this.totalPos += this.pos;\n }\n }\n\n private doDecodeSync(): unknown {\n DECODE: while (true) {\n const headByte = this.readHeadByte();\n let object: unknown;\n\n if (headByte >= 0xe0) {\n // negative fixint (111x xxxx) 0xe0 - 0xff\n object = headByte - 0x100;\n } else if (headByte < 0xc0) {\n if (headByte < 0x80) {\n // positive fixint (0xxx xxxx) 0x00 - 0x7f\n object = headByte;\n } else if (headByte < 0x90) {\n // fixmap (1000 xxxx) 0x80 - 0x8f\n const size = headByte - 0x80;\n if (size !== 0) {\n this.pushMapState(size);\n this.complete();\n continue DECODE;\n } else {\n object = {};\n }\n } else if (headByte < 0xa0) {\n // fixarray (1001 xxxx) 0x90 - 0x9f\n const size = headByte - 0x90;\n if (size !== 0) {\n this.pushArrayState(size);\n this.complete();\n continue DECODE;\n } else {\n object = [];\n }\n } else {\n // fixstr (101x xxxx) 0xa0 - 0xbf\n const byteLength = headByte - 0xa0;\n object = this.decodeUtf8String(byteLength, 0);\n }\n } else if (headByte === 0xc0) {\n // nil\n object = null;\n } else if (headByte === 0xc2) {\n // false\n object = false;\n } else if (headByte === 0xc3) {\n // true\n object = true;\n } else if (headByte === 0xca) {\n // float 32\n object = this.readF32();\n } else if (headByte === 0xcb) {\n // float 64\n object = this.readF64();\n } else if (headByte === 0xcc) {\n // uint 8\n object = this.readU8();\n } else if (headByte === 0xcd) {\n // uint 16\n object = this.readU16();\n } else if (headByte === 0xce) {\n // uint 32\n object = this.readU32();\n } else if (headByte === 0xcf) {\n // uint 64\n object = this.readU64();\n } else if (headByte === 0xd0) {\n // int 8\n object = this.readI8();\n } else if (headByte === 0xd1) {\n // int 16\n object = this.readI16();\n } else if (headByte === 0xd2) {\n // int 32\n object = this.readI32();\n } else if (headByte === 0xd3) {\n // int 64\n object = this.readI64();\n } else if (headByte === 0xd9) {\n // str 8\n const byteLength = this.lookU8();\n object = this.decodeUtf8String(byteLength, 1);\n } else if (headByte === 0xda) {\n // str 16\n const byteLength = this.lookU16();\n object = this.decodeUtf8String(byteLength, 2);\n } else if (headByte === 0xdb) {\n // str 32\n const byteLength = this.lookU32();\n object = this.decodeUtf8String(byteLength, 4);\n } else if (headByte === 0xdc) {\n // array 16\n const size = this.readU16();\n if (size !== 0) {\n this.pushArrayState(size);\n this.complete();\n continue DECODE;\n } else {\n object = [];\n }\n } else if (headByte === 0xdd) {\n // array 32\n const size = this.readU32();\n if (size !== 0) {\n this.pushArrayState(size);\n this.complete();\n continue DECODE;\n } else {\n object = [];\n }\n } else if (headByte === 0xde) {\n // map 16\n const size = this.readU16();\n if (size !== 0) {\n this.pushMapState(size);\n this.complete();\n continue DECODE;\n } else {\n object = {};\n }\n } else if (headByte === 0xdf) {\n // map 32\n const size = this.readU32();\n if (size !== 0) {\n this.pushMapState(size);\n this.complete();\n continue DECODE;\n } else {\n object = {};\n }\n } else if (headByte === 0xc4) {\n // bin 8\n const size = this.lookU8();\n object = this.decodeBinary(size, 1);\n } else if (headByte === 0xc5) {\n // bin 16\n const size = this.lookU16();\n object = this.decodeBinary(size, 2);\n } else if (headByte === 0xc6) {\n // bin 32\n const size = this.lookU32();\n object = this.decodeBinary(size, 4);\n } else if (headByte === 0xd4) {\n // fixext 1\n object = this.decodeExtension(1, 0);\n } else if (headByte === 0xd5) {\n // fixext 2\n object = this.decodeExtension(2, 0);\n } else if (headByte === 0xd6) {\n // fixext 4\n object = this.decodeExtension(4, 0);\n } else if (headByte === 0xd7) {\n // fixext 8\n object = this.decodeExtension(8, 0);\n } else if (headByte === 0xd8) {\n // fixext 16\n object = this.decodeExtension(16, 0);\n } else if (headByte === 0xc7) {\n // ext 8\n const size = this.lookU8();\n object = this.decodeExtension(size, 1);\n } else if (headByte === 0xc8) {\n // ext 16\n const size = this.lookU16();\n object = this.decodeExtension(size, 2);\n } else if (headByte === 0xc9) {\n // ext 32\n const size = this.lookU32();\n object = this.decodeExtension(size, 4);\n } else {\n throw new DecodeError(`Unrecognized type byte: ${prettyByte(headByte)}`);\n }\n\n this.complete();\n\n const stack = this.stack;\n while (stack.length > 0) {\n // arrays and maps\n const state = stack[stack.length - 1]!;\n if (state.type === State.ARRAY) {\n state.array[state.position] = object;\n state.position++;\n if (state.position === state.size) {\n stack.pop();\n object = state.array;\n } else {\n continue DECODE;\n }\n } else if (state.type === State.MAP_KEY) {\n if (!isValidMapKeyType(object)) {\n throw new DecodeError(\"The type of key must be string or number but \" + typeof object);\n }\n if (object === \"__proto__\") {\n throw new DecodeError(\"The key __proto__ is not allowed\");\n }\n\n state.key = object;\n state.type = State.MAP_VALUE;\n continue DECODE;\n } else {\n // it must be `state.type === State.MAP_VALUE` here\n\n state.map[state.key!] = object;\n state.readCount++;\n\n if (state.readCount === state.size) {\n stack.pop();\n object = state.map;\n } else {\n state.key = null;\n state.type = State.MAP_KEY;\n continue DECODE;\n }\n }\n }\n\n return object;\n }\n }\n\n private readHeadByte(): number {\n if (this.headByte === HEAD_BYTE_REQUIRED) {\n this.headByte = this.readU8();\n // console.log(\"headByte\", prettyByte(this.headByte));\n }\n\n return this.headByte;\n }\n\n private complete(): void {\n this.headByte = HEAD_BYTE_REQUIRED;\n }\n\n private readArraySize(): number {\n const headByte = this.readHeadByte();\n\n switch (headByte) {\n case 0xdc:\n return this.readU16();\n case 0xdd:\n return this.readU32();\n default: {\n if (headByte < 0xa0) {\n return headByte - 0x90;\n } else {\n throw new DecodeError(`Unrecognized array type byte: ${prettyByte(headByte)}`);\n }\n }\n }\n }\n\n private pushMapState(size: number) {\n if (size > this.maxMapLength) {\n throw new DecodeError(`Max length exceeded: map length (${size}) > maxMapLengthLength (${this.maxMapLength})`);\n }\n\n this.stack.push({\n type: State.MAP_KEY,\n size,\n key: null,\n readCount: 0,\n map: {},\n });\n }\n\n private pushArrayState(size: number) {\n if (size > this.maxArrayLength) {\n throw new DecodeError(`Max length exceeded: array length (${size}) > maxArrayLength (${this.maxArrayLength})`);\n }\n\n this.stack.push({\n type: State.ARRAY,\n size,\n array: new Array<unknown>(size),\n position: 0,\n });\n }\n\n private decodeUtf8String(byteLength: number, headerOffset: number): string {\n if (byteLength > this.maxStrLength) {\n throw new DecodeError(\n `Max length exceeded: UTF-8 byte length (${byteLength}) > maxStrLength (${this.maxStrLength})`,\n );\n }\n\n if (this.bytes.byteLength < this.pos + headerOffset + byteLength) {\n throw MORE_DATA;\n }\n\n const offset = this.pos + headerOffset;\n let object: string;\n if (this.stateIsMapKey() && this.keyDecoder?.canBeCached(byteLength)) {\n object = this.keyDecoder.decode(this.bytes, offset, byteLength);\n } else if (byteLength > TEXT_DECODER_THRESHOLD) {\n object = utf8DecodeTD(this.bytes, offset, byteLength);\n } else {\n object = utf8DecodeJs(this.bytes, offset, byteLength);\n }\n this.pos += headerOffset + byteLength;\n return object;\n }\n\n private stateIsMapKey(): boolean {\n if (this.stack.length > 0) {\n const state = this.stack[this.stack.length - 1]!;\n return state.type === State.MAP_KEY;\n }\n return false;\n }\n\n private decodeBinary(byteLength: number, headOffset: number): Uint8Array {\n if (byteLength > this.maxBinLength) {\n throw new DecodeError(`Max length exceeded: bin length (${byteLength}) > maxBinLength (${this.maxBinLength})`);\n }\n\n if (!this.hasRemaining(byteLength + headOffset)) {\n throw MORE_DATA;\n }\n\n const offset = this.pos + headOffset;\n const object = this.bytes.subarray(offset, offset + byteLength);\n this.pos += headOffset + byteLength;\n return object;\n }\n\n private decodeExtension(size: number, headOffset: number): unknown {\n if (size > this.maxExtLength) {\n throw new DecodeError(`Max length exceeded: ext length (${size}) > maxExtLength (${this.maxExtLength})`);\n }\n\n const extType = this.view.getInt8(this.pos + headOffset);\n const data = this.decodeBinary(size, headOffset + 1 /* extType */);\n return this.extensionCodec.decode(data, extType, this.context);\n }\n\n private lookU8() {\n return this.view.getUint8(this.pos);\n }\n\n pr