UNPKG

obj-codec

Version:

Encode objects into binary and decode binary back into objects, supporting nested references, custom object encoding/decoding, unique pointers...

903 lines (883 loc) 25.4 kB
//#region src/codec/base/flexible-unsigned-integer.ts const flexUintCodec = { encode(data) { const bufferLength = Math.ceil(data.toString(2).length / 7); const buffer = new Uint8Array(bufferLength); for (let i = 0; i < bufferLength; i++) buffer[bufferLength - i - 1] = data >> i * 7 | 128; buffer[bufferLength - 1] &= 127; return buffer; }, getBuffer(buffer) { let complete = false; let i = 0; while (i < buffer.length) { i++; if (buffer[i - 1] & 128) continue; complete = true; break; } return complete ? buffer.slice(0, i) : null; }, decode(encoded) { let data = 0; for (let i = 0; i < encoded.length; i++) { data |= encoded[i] & 127; if (i < encoded.length - 1) data <<= 7; } return data; } }; //#endregion //#region src/codec/base/string.ts const stringCodec = { encode(data) { return new TextEncoder().encode(data); }, decode(encoded) { return new TextDecoder().decode(encoded); } }; //#endregion //#region src/codec/base/bigint.ts const bigintCodec = { encode(data) { const byteLength = Math.ceil((data < 0n ? data : -data).toString(16).length / 2); const buffer = new Uint8Array(byteLength); for (let i = 0; i < byteLength; i++) buffer[i] = Number(data >> BigInt(i * 8) & 0xffn); return buffer; }, decode(encoded) { let result = 0n; for (let i = 0; i < encoded.byteLength; i++) result |= BigInt(encoded[i]) << BigInt(i * 8); if (encoded[encoded.byteLength - 1] & 128) { const mask = (1n << BigInt(encoded.byteLength * 8)) - 1n; result |= ~mask; } return result; } }; //#endregion //#region src/utils.ts var Queue = class { #head; #tail; #size = 0; get size() { return this.#size; } enqueue(value) { const node = { value }; if (this.#head) { this.#tail.next = node; this.#tail = node; } else { this.#head = node; this.#tail = node; } this.#size++; return this.#size; } dequeue() { if (!this.#head) return; const removed = this.#head; this.#head = this.#head.next; if (!this.#head) this.#tail = void 0; this.#size--; return removed.value; } *iter() { while (true) { const value = this.dequeue(); if (value === void 0) return; yield value; } } }; /** 合并缓冲区 */ function concatBuffers(...buffers) { let totalLength = 0; for (const buffer of buffers) totalLength += buffer.length; const result = new Uint8Array(totalLength); let offset = 0; for (const buffer of buffers) { result.set(buffer, offset); offset += buffer.length; } return result; } /** 转 Uint8Array */ function bufferToUint8Array(buffer) { if (buffer instanceof ArrayBuffer) return new Uint8Array(buffer); return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength); } const BINARY_TYPES = [ globalThis.ArrayBuffer, globalThis.Int8Array, globalThis.Uint8Array, globalThis.Uint8ClampedArray, globalThis.Int16Array, globalThis.Uint16Array, globalThis.Int32Array, globalThis.Uint32Array, globalThis.Float16Array, globalThis.Float32Array, globalThis.Float64Array, globalThis.BigInt64Array, globalThis.BigUint64Array, globalThis.DataView ]; function getBinaryTypeId(data) { return BINARY_TYPES.findIndex((type) => typeof type === "function" && data instanceof type); } function isBinary(data) { for (const type of BINARY_TYPES) { if (typeof type !== "function") continue; if (data instanceof type) return true; } return false; } var Pointer = class { #id; #pointers; constructor(id, pointers) { this.#id = id; this.#pointers = pointers; } /** 解引用 */ deref() { if (this.#id >= this.#pointers.length) throw new Error(`Unknown pointer: ${this.#id}`); return this.#pointers[this.#id][1]; } }; function registerCodec(scope, codec) { if (typeof codec !== "object") throw new TypeError("codec must be an object"); if (typeof codec.name !== "string") throw new TypeError("codec.name must be a string"); if (typeof codec.decode !== "function") throw new TypeError("codec.decode must be a function"); if (typeof codec.encode !== "function") throw new TypeError("codec.encode must be a function"); if (typeof codec.class !== "function") throw new TypeError("codec.class must be a function"); if (codec.parentClasses) { if (!Array.isArray(codec.parentClasses)) throw new TypeError("codec.parentClasses must be a array"); for (const p of codec.parentClasses) if (typeof p !== "function") throw new TypeError("parentClasses must be a function"); } if (scope.has(codec.name)) console.warn(`Codec ${codec.name} already exists, overwriting`); scope.set(codec.name, codec); } function mergeCodecs(...codecsList) { const result = /* @__PURE__ */ new Map(); for (const codecs of codecsList) for (const [k, v] of codecs) result.set(k, v); return result; } //#endregion //#region src/codec/base/binary.ts const binaryCodec = { encode(data) { return concatBuffers([getBinaryTypeId(data)], bufferToUint8Array(data)); }, decode(encoded) { const binaryType = encoded[0]; const buffer = encoded.slice(1).buffer; if (binaryType === 0) return buffer; return new BINARY_TYPES[binaryType](buffer); } }; //#endregion //#region src/codec/base/boolean.ts const falseCodec = { bufferLength: 0, encode: () => new Uint8Array([]), decode: () => false }; const trueCodec = { bufferLength: 0, encode: () => new Uint8Array([]), decode: () => true }; //#endregion //#region src/codec/base/null.ts const nullCodec = { bufferLength: 0, encode: () => new Uint8Array([]), decode: () => null }; //#endregion //#region src/codec/base/number.ts const numberCodec = { bufferLength: 8, encode(data) { const buffer = new Uint8Array(8); const view = new DataView(buffer.buffer); view.setFloat64(0, data); return buffer; }, decode(encoded) { const view = new DataView(encoded.buffer); return view.getFloat64(0); } }; //#endregion //#region src/codec/base/undefined.ts const undefinedCodec = { bufferLength: 0, encode: () => new Uint8Array([]), decode: () => void 0 }; //#endregion //#region src/codec/internal/array.ts const arrayCodec = { encode(data, serialize) { return concatBuffers(...data.map((item) => serialize(item))); }, decode(encoded, deserialize) { return deserialize(encoded); }, deref(data) { for (let i = 0; i < data.length; i++) { const item = data[i]; if (item instanceof Pointer) data[i] = item.deref(); } } }; //#endregion //#region src/codec/internal/date.ts const dateCodec = { bufferLength: 8, encode(data) { const buffer = new Uint8Array(8); const view = new DataView(buffer.buffer); view.setFloat64(0, data.getTime()); return buffer; }, decode(encoded) { const view = new DataView(encoded.buffer); return new Date(view.getFloat64(0)); } }; //#endregion //#region src/codec/internal/map.ts const mapCodec = { encode(data, serialize) { return concatBuffers(...[...data].flatMap(([k, v]) => [serialize(k), serialize(v)])); }, decode(encoded, deserialize) { const pairs = deserialize(encoded); const map = /* @__PURE__ */ new Map(); for (let i = 0; i < pairs.length; i += 2) map.set(pairs[i], pairs[i + 1]); return map; }, deref(data) { for (let [key, value] of [...data]) { if (key instanceof Pointer) { data.delete(key); key = key.deref(); } if (value instanceof Pointer) value = value.deref(); data.set(key, value); } } }; //#endregion //#region src/codec/internal/object.ts const objectCodec = { encode(data, serialize) { const buffers = []; for (const key in data) { if (!Object.hasOwn(data, key)) continue; buffers.push(serialize(key), serialize(data[key])); } return concatBuffers(...buffers); }, decode(encoded, deserialize) { return { _pairs: deserialize(encoded) }; }, deref(data) { const pairs = data._pairs; delete data._pairs; for (let i = 0; i < pairs.length; i += 2) { let key = pairs[i]; let value = pairs[i + 1]; if (key instanceof Pointer) key = key.deref(); if (value instanceof Pointer) value = value.deref(); data[key] = value; } } }; //#endregion //#region src/codec/internal/regexp.ts const regexpCodec = { encode(data) { return new TextEncoder().encode(data.toString().slice(1)); }, decode(encoded) { const token = new TextDecoder().decode(encoded); const flagsIndex = token.lastIndexOf("/"); const flags = token.slice(flagsIndex + 1); return new RegExp(token.slice(0, flagsIndex), flags); } }; //#endregion //#region src/codec/internal/set.ts const setCodec = { encode(data, serialize) { return concatBuffers(...[...data].map((item) => serialize(item))); }, decode(encoded, deserialize) { return new Set(deserialize(encoded)); }, deref(data) { const items = [...data]; data.clear(); for (const item of items) if (item instanceof Pointer) data.add(item.deref()); else data.add(item); } }; //#endregion //#region src/codec/internal/symbol.ts const symbolCodec = { encode(data) { const key = data.description; if (key === void 0) return new Uint8Array([0]); return new TextEncoder().encode(key); }, decode(encoded) { if (encoded.length === 1 && encoded[0] === 0) return Symbol(); return Symbol(new TextDecoder().decode(encoded)); } }; //#endregion //#region src/global.ts /** 内置编解码器 */ const INTERNAL_CODEC_MAP = Object.freeze({ POINTER: flexUintCodec, BINARY: binaryCodec, NUMBER: numberCodec, BIGINT: bigintCodec, STRING: stringCodec, FALSE: falseCodec, TRUE: trueCodec, NULL: nullCodec, UNDEFINED: undefinedCodec, OBJECT: objectCodec, ARRAY: arrayCodec, SET: setCodec, MAP: mapCodec, DATE: dateCodec, REGEXP: regexpCodec, SYMBOL: symbolCodec, UNIQUE_POINTER: flexUintCodec }); const INTERNAL_CODEC = Object.freeze([ flexUintCodec, binaryCodec, numberCodec, bigintCodec, stringCodec, falseCodec, trueCodec, nullCodec, undefinedCodec, objectCodec, arrayCodec, setCodec, mapCodec, dateCodec, regexpCodec, symbolCodec, flexUintCodec ]); /** 内置类型 ID */ const INTERNAL_TYPE_ID = Object.freeze({ POINTER: 0, BINARY: 1, NUMBER: 2, BIGINT: 3, STRING: 4, FALSE: 5, TRUE: 6, NULL: 7, UNDEFINED: 8, OBJECT: 9, ARRAY: 10, SET: 11, MAP: 12, DATE: 13, REGEXP: 14, SYMBOL: 15, UNIQUE_POINTER: 16 }); /** 自定义类型起始 ID */ const CUSTOM_TYPE_ID_BEGIN = 17; /** 数据结构版本号 */ const VERSION = 1; const globalCodecs = /* @__PURE__ */ new Map(); var IObjCodec = class { _codecs = /* @__PURE__ */ new Map(); /** * 唯一值 * @description * 该唯一值数组在该 `ObjCodec` 实例中生效, * 调用 `encode`/`decode` 方法时可覆盖该值。 * * 唯一指针指向该数组中指定下标的值, * 需确保编解码时该数组内容和顺序不变。 */ uniqueValues; constructor(uniqueValues) { this.uniqueValues = uniqueValues; } /** 注册全局编解码器 */ static register(codec) { registerCodec(globalCodecs, codec); } /** 注册编解码器 */ register(codec) { registerCodec(this._codecs, codec); } }; //#endregion //#region src/decoder.ts const REFERABLE_TYPE_ID = new Set([ INTERNAL_TYPE_ID.BINARY, INTERNAL_TYPE_ID.STRING, INTERNAL_TYPE_ID.OBJECT, INTERNAL_TYPE_ID.ARRAY, INTERNAL_TYPE_ID.SET, INTERNAL_TYPE_ID.MAP, INTERNAL_TYPE_ID.DATE, INTERNAL_TYPE_ID.REGEXP, INTERNAL_TYPE_ID.SYMBOL ]); function isReferable(id) { if (id >= CUSTOM_TYPE_ID_BEGIN) return true; return REFERABLE_TYPE_ID.has(id); } const UNINITIALIZED = Symbol("uninitialized"); var Decoder = class { #codec; #uniqueValues; #ignoreMissedCodec; #ignoreMissedUniqueValue; #allowIncompleteDecoding; #pointers = []; #buffer = new Uint8Array(); #version; #codecMapLength; #codecMap = []; #types = []; #length; #root = UNINITIALIZED; #complete = false; constructor({ codec, uniqueValues, ignoreMissedCodec, ignoreMissedUniqueValue, allowIncompleteDecoding }) { this.#codec = codec; this.#uniqueValues = uniqueValues ?? []; this.#ignoreMissedCodec = !!ignoreMissedCodec; this.#ignoreMissedUniqueValue = !!ignoreMissedUniqueValue; this.#allowIncompleteDecoding = !!allowIncompleteDecoding; } #consume(length) { this.#buffer = this.#buffer.slice(length); } #getCodec(id) { if (id < CUSTOM_TYPE_ID_BEGIN) return INTERNAL_CODEC[id]; return this.#codecMap[id - CUSTOM_TYPE_ID_BEGIN]; } #deserializeType(box) { let { buffer } = box; const types = []; while (!this.#isTypeResolvable(types.at(-1))) { const typeBuffer = flexUintCodec.getBuffer(buffer); if (!typeBuffer) throw new Error("Failed to deserialize while deserialize types"); const type = flexUintCodec.decode(typeBuffer); this.#assertTypeExists(type); types.push(type); buffer = buffer.slice(typeBuffer.length); } box.buffer = buffer; return types; } #deserializeLength(types, box) { const innerType = types.at(-1); if (innerType === INTERNAL_TYPE_ID.POINTER || innerType === INTERNAL_TYPE_ID.UNIQUE_POINTER) { const lengthBuffer$1 = flexUintCodec.getBuffer(box.buffer); if (!lengthBuffer$1) throw new Error("Failed to read pointer"); return lengthBuffer$1.length; } let length = INTERNAL_CODEC[innerType].bufferLength; if (length !== void 0) return length; const lengthBuffer = flexUintCodec.getBuffer(box.buffer); if (!lengthBuffer) throw new Error("Failed to deserialize while deserialize length"); length = flexUintCodec.decode(lengthBuffer); box.buffer = box.buffer.slice(lengthBuffer.length); return length; } #deserializeBody(types, buffer) { const innerType = types.pop(); const pointers = []; let data = INTERNAL_CODEC[innerType].decode(buffer, this.#deserialize); if (innerType === INTERNAL_TYPE_ID.POINTER) data = new Pointer(data, this.#pointers); else if (innerType === INTERNAL_TYPE_ID.UNIQUE_POINTER) { if (data >= this.#uniqueValues.length && !this.#ignoreMissedUniqueValue) throw new Error(`Missing unique value: ${data}`); data = this.#uniqueValues[data]; } if (isReferable(innerType)) pointers.push([this.#getCodec(innerType), data]); while (true) { const type = types.pop(); if (type === void 0) break; const codec = this.#getCodec(type); if (!codec) throw new Error(`Unknown codec: ${type}`); data = codec.decode(data); pointers.push([codec, data]); } this.#pointers.push(...pointers.reverse()); return data; } #deserialize = (buffer) => { const data = []; const box = { buffer }; while (box.buffer.length > 0) { const types = this.#deserializeType(box); const length = this.#deserializeLength(types, box); data.push(this.#deserializeBody(types, box.buffer.slice(0, length))); box.buffer = box.buffer.slice(length); } return data; }; #isTypeResolvable(type = this.#types.at(-1)) { return type !== void 0 && type < CUSTOM_TYPE_ID_BEGIN; } #assertTypeExists(id) { if (id < CUSTOM_TYPE_ID_BEGIN) return; if (id - CUSTOM_TYPE_ID_BEGIN >= this.#codecMap.length) throw new Error(`Unknown codec: ${id}`); } #decodeVersion() { if (this.#version !== void 0) return true; if (this.#buffer.length === 0) return false; this.#version = this.#buffer[0]; this.#consume(1); if (this.#version === 1) return true; throw new Error(`Unsupported version: ${this.#version}`); } #decodeCodecMap() { if (this.#codecMapLength === void 0) { const lengthBuffer = flexUintCodec.getBuffer(this.#buffer); if (!lengthBuffer) return false; this.#codecMapLength = flexUintCodec.decode(lengthBuffer); this.#consume(lengthBuffer.length); } while (this.#codecMap.length < this.#codecMapLength) { const lengthBuffer = flexUintCodec.getBuffer(this.#buffer); if (!lengthBuffer) return false; const length = flexUintCodec.decode(lengthBuffer); if (this.#buffer.length < lengthBuffer.length + length) return false; this.#consume(lengthBuffer.length); const name = stringCodec.decode(this.#buffer.slice(0, length)); const codec = this.#codec.get(name); if (codec) { this.#codecMap.push(codec); this.#consume(length); continue; } if (this.#ignoreMissedCodec) continue; throw new Error(`Missing codec: ${name}`); } return this.#codecMap.length === this.#codecMapLength; } #decodeType() { while (!this.#isTypeResolvable()) { const typeBuffer = flexUintCodec.getBuffer(this.#buffer); if (!typeBuffer) return false; const type = flexUintCodec.decode(typeBuffer); this.#assertTypeExists(type); this.#types.push(type); this.#consume(typeBuffer.length); } return true; } #decodeLength() { if (this.#length !== void 0) return true; const innerType = this.#types.at(-1); if (innerType === INTERNAL_TYPE_ID.POINTER || innerType === INTERNAL_TYPE_ID.UNIQUE_POINTER) { const lengthBuffer$1 = flexUintCodec.getBuffer(this.#buffer); if (!lengthBuffer$1) return false; this.#length = lengthBuffer$1.length; return true; } this.#length = INTERNAL_CODEC[innerType].bufferLength; if (this.#length !== void 0) return true; const lengthBuffer = flexUintCodec.getBuffer(this.#buffer); if (!lengthBuffer) return false; this.#length = flexUintCodec.decode(lengthBuffer); this.#consume(lengthBuffer.length); return true; } #decodeBody() { if (this.#buffer.length < this.#length) return false; const innerType = this.#types.pop(); const pointers = []; let data = INTERNAL_CODEC[innerType].decode(this.#buffer.slice(0, this.#length), this.#deserialize); this.#consume(this.#length); if (innerType === INTERNAL_TYPE_ID.POINTER) data = new Pointer(data, this.#pointers); else if (innerType === INTERNAL_TYPE_ID.UNIQUE_POINTER) { if (data >= this.#uniqueValues.length && !this.#ignoreMissedUniqueValue) throw new Error(`Missing unique value: ${data}`); data = this.#uniqueValues[data]; } if (isReferable(innerType)) pointers.push([this.#getCodec(innerType), data]); while (true) { const type = this.#types.pop(); if (type === void 0) break; const codec = this.#getCodec(type); if (!codec) throw new Error(`Unknown codec: ${type}`); data = codec.decode(data); pointers.push([codec, data]); } pointers.reverse(); this.#pointers.push(...pointers); if (this.#root === UNINITIALIZED) this.#root = pointers.length === 0 ? data : pointers[0][1]; return true; } #decode() { if (!this.#decodeVersion()) return; if (!this.#decodeCodecMap()) return; while (this.#buffer.length > 0) { if (!this.#decodeType()) return; if (!this.#decodeLength()) return; if (!this.#decodeBody()) return; this.#length = void 0; } } decode(buffer) { if (this.#complete) return; if (!isBinary(buffer)) throw new Error(`Require a buffer but receive ${typeof buffer}`); this.#buffer = concatBuffers(this.#buffer, bufferToUint8Array(buffer)); this.#decode(); } getResult() { if (this.#complete) return this.#root; if (!this.#allowIncompleteDecoding && (this.#types.length > 0 || this.#buffer.length > 0)) throw new Error("Failure to decode in full"); const customCodecPointers = []; for (const [codec, data] of this.#pointers) { if (!codec.deref) continue; if (!INTERNAL_CODEC.includes(codec)) { customCodecPointers.push([codec, data]); continue; } codec.deref(data); } for (const [codec, data] of customCodecPointers) codec.deref(data); this.#complete = true; return this.#root; } }; //#endregion //#region src/encoder.ts const INTERNAL_TYPES = [ [RegExp, "REGEXP"], [Date, "DATE"], [Map, "MAP"], [Set, "SET"] ]; var Encoder = class { #codec; #uniqueValues; #ignoreUnsupportedTypes; #queue = new Queue(); #pointers = []; constructor({ codec, uniqueValues, ignoreUnsupportedTypes, root }) { this.#codec = [...codec.entries()]; this.#uniqueValues = uniqueValues ?? []; this.#ignoreUnsupportedTypes = !!ignoreUnsupportedTypes; this.#queue.enqueue(root); } #assertSupported(data) { if (this.#ignoreUnsupportedTypes) return; if (typeof data !== "function") return; if (this.#uniqueValues.includes(data)) return; throw new Error(`Unsupported type:\n${data}`); } #innerSerialize = (data) => { let index = this.#uniqueValues.indexOf(data); if (index !== -1) return concatBuffers([INTERNAL_TYPE_ID.UNIQUE_POINTER], flexUintCodec.encode(index)); const buffer = this.#serializeBasicValue(data); if (buffer) return buffer; index = this.#pointers.indexOf(data); if (index === -1) { index = this.#pointers.length; this.#pointers.push(data); this.#queue.enqueue(data); } return concatBuffers([INTERNAL_TYPE_ID.POINTER], flexUintCodec.encode(index)); }; #runInternalCodec(type, data) { const head = [INTERNAL_TYPE_ID[type]]; const body = INTERNAL_CODEC_MAP[type].encode(data, this.#innerSerialize); if (typeof INTERNAL_CODEC_MAP[type].bufferLength === "number") return concatBuffers(head, body); return concatBuffers(head, flexUintCodec.encode(body.length), body); } #serializeUniqueValue(data) { const index = this.#uniqueValues.indexOf(data); if (index === -1) return null; return concatBuffers([INTERNAL_TYPE_ID.UNIQUE_POINTER], flexUintCodec.encode(index)); } #serializeBasicValue(data) { const type = (typeof data).toUpperCase(); switch (type) { case "NUMBER": case "BIGINT": case "UNDEFINED": return this.#runInternalCodec(type, data); case "BOOLEAN": return this.#runInternalCodec(data ? "TRUE" : "FALSE", data); } if (data !== null) return null; return this.#runInternalCodec("NULL", data); } #serializeReferableValue(data, atRoot) { const index = this.#pointers.indexOf(data); if (index === -1) this.#pointers.push(data); else if (!atRoot) return concatBuffers([INTERNAL_TYPE_ID.POINTER], flexUintCodec.encode(index)); const type = (typeof data).toUpperCase(); switch (type) { case "STRING": case "SYMBOL": return this.#runInternalCodec(type, data); } return null; } #serializeBinaryValue(data) { if (!isBinary(data)) return null; return this.#runInternalCodec("BINARY", data); } #serializeCustomValue(data) { for (const [id, [_, codec]] of this.#codec.entries()) { if (!(data instanceof codec.class)) continue; const body = this.#serialize(codec.encode(data)); return concatBuffers(flexUintCodec.encode(id + CUSTOM_TYPE_ID_BEGIN), body); } return null; } #serializeInternalValue(data) { for (const [type, name] of INTERNAL_TYPES) { if (!(data instanceof type)) continue; return this.#runInternalCodec(name, data); } return null; } #serializeFallbackValue(data) { if (Array.isArray(data)) return this.#runInternalCodec("ARRAY", data); return this.#runInternalCodec("OBJECT", data); } #serialize(data, atRoot) { this.#assertSupported(data); let buffer = this.#serializeUniqueValue(data); if (buffer) return buffer; buffer = this.#serializeBasicValue(data); if (buffer) return buffer; buffer = this.#serializeReferableValue(data, atRoot); if (buffer) return buffer; buffer = this.#serializeBinaryValue(data); if (buffer) return buffer; buffer = this.#serializeCustomValue(data); if (buffer) return buffer; buffer = this.#serializeInternalValue(data); if (buffer) return buffer; return this.#serializeFallbackValue(data); } *encode() { yield new Uint8Array([VERSION]); this.#codec.sort(([_, a], [__, b]) => (a.parentClasses ?? []).includes(b.class) ? -1 : 1); yield flexUintCodec.encode(this.#codec.length); for (const [name] of this.#codec) { const buffer = stringCodec.encode(name); yield flexUintCodec.encode(buffer.length); yield buffer; } for (const data of this.#queue.iter()) yield this.#serialize(data, true); } }; //#endregion //#region src/web.ts var ObjEncoder = class extends ReadableStream { #encoder; #generator; constructor(options) { super({ pull: (controller) => { try { const { value, done } = this.#generator.next(); if (done) controller.close(); else controller.enqueue(value); } catch (error) { controller.error(error); } }, cancel: () => { this.#generator.return(); } }); this.#encoder = new Encoder(options); this.#generator = this.#encoder.encode(); } /** 启动编码 */ encode() { return this.#generator; } }; var ObjDecoder = class extends WritableStream { #decoder; constructor(options) { super({ write: (chunk, controller) => { try { this.#decoder.decode(chunk); } catch (error) { controller.error(error); } } }); this.#decoder = new Decoder(options); } /** 解码 */ decode(buffer) { this.#decoder.decode(buffer); } /** * 获取结果 * @description * 调用此方法将结束解码 */ getResult() { return this.#decoder.getResult(); } }; var ObjCodec = class extends IObjCodec { /** * 编码 * @param root 编码根对象 */ static encode(root, options) { return new ObjEncoder({ ...options, root, codec: globalCodecs }); } /** 解码 */ static decode(options) { return new ObjDecoder({ ...options, codec: globalCodecs }); } encode(root, options) { return new ObjEncoder({ uniqueValues: this.uniqueValues, ...options, root, codec: mergeCodecs(globalCodecs, this._codecs) }); } decode(options) { return new ObjDecoder({ uniqueValues: this.uniqueValues, ...options, codec: mergeCodecs(globalCodecs, this._codecs) }); } }; //#endregion export { CUSTOM_TYPE_ID_BEGIN, INTERNAL_CODEC, INTERNAL_CODEC_MAP, INTERNAL_TYPE_ID, ObjCodec, Pointer, VERSION, bufferToUint8Array, concatBuffers, isBinary }; //# sourceMappingURL=web.esm.js.map