UNPKG

@jsonjoy.com/json-pack

Version:

High-performance JSON serialization library

442 lines 14.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RespEncoder = void 0; const Writer_1 = require("@jsonjoy.com/buffers/lib/Writer"); const utf8_1 = require("@jsonjoy.com/util/lib/strings/utf8"); const extensions_1 = require("./extensions"); const JsonPackExtension_1 = require("../JsonPackExtension"); const REG_RN = /[\r\n]/; const isSafeInteger = Number.isSafeInteger; /** * Implements RESP3 encoding. */ class RespEncoder { constructor(writer = new Writer_1.Writer()) { this.writer = writer; } encode(value) { this.writeAny(value); return this.writer.flush(); } encodeToSlice(value) { this.writeAny(value); return this.writer.flushSlice(); } writeAny(value) { switch (typeof value) { case 'number': return this.writeNumber(value); case 'string': return this.writeStr(value); case 'boolean': return this.writeBoolean(value); case 'object': { if (!value) return this.writeNull(); if (value instanceof Array) return this.writeArr(value); if (value instanceof Uint8Array) return this.writeBin(value); if (value instanceof Error) return this.writeErr(value.message); if (value instanceof Set) return this.writeSet(value); if (value instanceof JsonPackExtension_1.JsonPackExtension) { if (value instanceof extensions_1.RespPush) return this.writePush(value.val); if (value instanceof extensions_1.RespVerbatimString) return this.writeVerbatimStr('txt', value.val); if (value instanceof extensions_1.RespAttributes) return this.writeAttr(value.val); } return this.writeObj(value); } case 'undefined': return this.writeUndef(); case 'bigint': return this.writeBigInt(value); default: return this.writeUnknown(value); } } writeLength(length) { const writer = this.writer; if (length < 100) { if (length < 10) { writer.u8(length + 48); return; } const octet1 = length % 10; const octet2 = (length - octet1) / 10; writer.u16(((octet2 + 48) << 8) + octet1 + 48); return; } let digits = 1; let pow = 10; while (length >= pow) { digits++; pow *= 10; } writer.ensureCapacity(digits); const uint8 = writer.uint8; const x = writer.x; const newX = x + digits; let i = newX - 1; while (i >= x) { const remainder = length % 10; uint8[i--] = remainder + 48; length = (length - remainder) / 10; } writer.x = newX; } encodeCmd(args) { this.writeCmd(args); return this.writer.flush(); } writeCmd(args) { const length = args.length; this.writeArrHdr(length); for (let i = 0; i < length; i++) { const arg = args[i]; if (arg instanceof Uint8Array) this.writeBin(arg); else this.writeBulkStrAscii(arg + ''); } } encodeCmdUtf8(args) { this.writeCmdUtf8(args); return this.writer.flush(); } writeCmdUtf8(args) { const length = args.length; this.writeArrHdr(length); for (let i = 0; i < length; i++) this.writeArgUtf8(args[i]); } writeArgUtf8(arg) { if (arg instanceof Uint8Array) return this.writeBin(arg); else this.writeBulkStr(arg + ''); } writeNull() { this.writer.u8u16(95 /* RESP.NULL */, // _ 3338 /* RESP.RN */); } writeNullStr() { this.writer.u8u32(36 /* RESP.STR_BULK */, // $ 45 * 0x1000000 + // - 49 * 0x10000 + // 1 3338 /* RESP.RN */); } writeNullArr() { this.writer.u8u32(42 /* RESP.ARR */, // * 45 * 0x1000000 + // - 49 * 0x10000 + // 1 3338 /* RESP.RN */); } writeBoolean(bool) { this.writer.u32(bool ? 35 /* RESP.BOOL */ * 0x1000000 + // # 116 * 0x10000 + // t 3338 /* RESP.RN */ // \r\n : 35 /* RESP.BOOL */ * 0x1000000 + // # 102 * 0x10000 + // f 3338 /* RESP.RN */); } writeNumber(num) { if (isSafeInteger(num)) this.writeInteger(num); else if (typeof num === 'bigint') this.writeBigInt(num); else this.writeFloat(num); } writeBigInt(int) { const writer = this.writer; writer.u8(40 /* RESP.BIG */); // ( writer.ascii(int + ''); writer.u16(3338 /* RESP.RN */); // \r\n } writeInteger(int) { const writer = this.writer; writer.u8(58 /* RESP.INT */); // : writer.ascii(int + ''); writer.u16(3338 /* RESP.RN */); // \r\n } writeUInteger(uint) { this.writeInteger(uint); } writeFloat(float) { const writer = this.writer; writer.u8(44 /* RESP.FLOAT */); // , switch (float) { case Infinity: writer.u8u16(105, // i (110 << 8) | // n 102); break; case -Infinity: writer.u32((45 * 0x1000000 + // - 105 * 0x10000 + // i (110 << 8)) | // n 102); break; default: if (float !== float) writer.u8u16(110, // n (97 << 8) | // a 110); else writer.ascii(float + ''); break; } writer.u16(3338 /* RESP.RN */); // \r\n } writeBin(buf) { const writer = this.writer; const length = buf.length; writer.u8(36 /* RESP.STR_BULK */); // $ this.writeLength(length); writer.u16(3338 /* RESP.RN */); // \r\n writer.buf(buf, length); writer.u16(3338 /* RESP.RN */); // \r\n } writeBinHdr(length) { throw new Error('Not implemented'); // Because then we also need `.writeBinBody()` which would emit trailing `\r\n`. } writeStr(str) { const length = str.length; if (length < 64 && !REG_RN.test(str)) this.writeSimpleStr(str); else this.writeVerbatimStr('txt', str); } writeStrHdr(length) { throw new Error('Not implemented'); // Because then we also need `.writeBinBody()` which would emit trailing `\r\n`. } writeSimpleStr(str) { const writer = this.writer; writer.u8(43 /* RESP.STR_SIMPLE */); // + writer.ensureCapacity(str.length << 2); writer.utf8(str); writer.u16(3338 /* RESP.RN */); // \r\n } writeSimpleStrAscii(str) { const writer = this.writer; writer.u8(43 /* RESP.STR_SIMPLE */); // + writer.ascii(str); writer.u16(3338 /* RESP.RN */); // \r\n } writeBulkStr(str) { const writer = this.writer; const size = (0, utf8_1.utf8Size)(str); writer.u8(36 /* RESP.STR_BULK */); // $ this.writeLength(size); writer.u16(3338 /* RESP.RN */); // \r\n writer.ensureCapacity(size); writer.utf8(str); writer.u16(3338 /* RESP.RN */); // \r\n } writeBulkStrAscii(str) { const writer = this.writer; writer.u8(36 /* RESP.STR_BULK */); // $ this.writeLength(str.length); writer.u16(3338 /* RESP.RN */); // \r\n writer.ascii(str); writer.u16(3338 /* RESP.RN */); // \r\n } writeAsciiStr(str) { const isSimple = !REG_RN.test(str); if (isSimple) this.writeSimpleStr(str); else this.writeBulkStrAscii(str); } writeVerbatimStr(encoding, str) { const writer = this.writer; const size = (0, utf8_1.utf8Size)(str); writer.u8(61 /* RESP.STR_VERBATIM */); // = this.writeLength(size + 4); writer.u16(3338 /* RESP.RN */); // \r\n writer.u32(encoding.charCodeAt(0) * 0x1000000 + // t (encoding.charCodeAt(1) << 16) + // x (encoding.charCodeAt(2) << 8) + // t 58); writer.ensureCapacity(size); writer.utf8(str); writer.u16(3338 /* RESP.RN */); // \r\n } writeErr(str) { if (str.length < 64 && !REG_RN.test(str)) this.writeSimpleErr(str); else this.writeBulkErr(str); } writeSimpleErr(str) { const writer = this.writer; writer.u8(45 /* RESP.ERR_SIMPLE */); // - writer.ensureCapacity(str.length << 2); writer.utf8(str); writer.u16(3338 /* RESP.RN */); // \r\n } writeBulkErr(str) { const writer = this.writer; const size = (0, utf8_1.utf8Size)(str); writer.u8(33 /* RESP.ERR_BULK */); // ! this.writeLength(size); writer.u16(3338 /* RESP.RN */); // \r\n writer.ensureCapacity(size); writer.utf8(str); writer.u16(3338 /* RESP.RN */); // \r\n } writeArr(arr) { const writer = this.writer; const length = arr.length; writer.u8(42 /* RESP.ARR */); // * this.writeLength(length); writer.u16(3338 /* RESP.RN */); // \r\n for (let i = 0; i < length; i++) this.writeAny(arr[i]); } writeArrHdr(length) { const writer = this.writer; writer.u8(42 /* RESP.ARR */); // * this.writeLength(length); writer.u16(3338 /* RESP.RN */); // \r\n } writeObj(obj) { const writer = this.writer; const keys = Object.keys(obj); const length = keys.length; writer.u8(37 /* RESP.OBJ */); // % this.writeLength(length); writer.u16(3338 /* RESP.RN */); // \r\n for (let i = 0; i < length; i++) { const key = keys[i]; this.writeStr(key); this.writeAny(obj[key]); } } writeObjHdr(length) { const writer = this.writer; writer.u8(37 /* RESP.OBJ */); // % this.writeLength(length); writer.u16(3338 /* RESP.RN */); // \r\n } writeAttr(obj) { const writer = this.writer; const keys = Object.keys(obj); const length = keys.length; writer.u8(124 /* RESP.ATTR */); // | this.writeLength(length); writer.u16(3338 /* RESP.RN */); // \r\n for (let i = 0; i < length; i++) { const key = keys[i]; this.writeStr(key); this.writeAny(obj[key]); } } writeSet(set) { const writer = this.writer; const length = set.size; writer.u8(126 /* RESP.SET */); // ~ this.writeLength(length); writer.u16(3338 /* RESP.RN */); // \r\n for (let i = 0; i < length; i++) set.forEach((value) => this.writeAny(value)); } writePush(elements) { const writer = this.writer; const length = elements.length; writer.u8(62 /* RESP.PUSH */); // > this.writeLength(length); writer.u16(3338 /* RESP.RN */); // \r\n for (let i = 0; i < length; i++) this.writeAny(elements[i]); } /** * Called when the encoder encounters a value that it does not know how to encode. * * @param value Some JavaScript value. */ writeUnknown(value) { this.writeNull(); } writeUndef() { this.writeNull(); } writeRn() { this.writer.u16(3338 /* RESP.RN */); // \r\n } // ---------------------------------------------------------- Stream encoding writeStartStr() { this.writer.u32(36 /* RESP.STR_BULK */ * 0x1000000 + // $ (63 << 16) + // ? 3338 /* RESP.RN */); } writeStrChunk(str) { const writer = this.writer; writer.u8(59); // ; const size = (0, utf8_1.utf8Size)(str); this.writeLength(size); writer.u16(3338 /* RESP.RN */); // \r\n writer.ensureCapacity(size); writer.utf8(str); writer.u16(3338 /* RESP.RN */); // \r\n } writeEndStr() { this.writer.u32(59 * 0x1000000 + // ; (48 << 16) + // 0 3338 /* RESP.RN */); } writeStartBin() { this.writer.u32(36 * 0x1000000 + // $ (63 << 16) + // ? 3338 /* RESP.RN */); } writeBinChunk(buf) { const writer = this.writer; const length = buf.length; writer.u8(59); // ; this.writeLength(length); writer.u16(3338 /* RESP.RN */); // \r\n writer.buf(buf, length); writer.u16(3338 /* RESP.RN */); // \r\n } writeEndBin() { this.writer.u32(59 * 0x1000000 + // ; (48 << 16) + // 0 3338 /* RESP.RN */); } writeStartArr() { this.writer.u32(42 /* RESP.ARR */ * 0x1000000 + // * (63 << 16) + // ? 3338 /* RESP.RN */); } writeArrChunk(item) { this.writeAny(item); } writeEndArr() { this.writer.u8u16(46, // . 3338 /* RESP.RN */); } writeStartObj() { this.writer.u32(37 * 0x1000000 + // % (63 << 16) + // ? 3338 /* RESP.RN */); } writeObjChunk(key, value) { this.writeStr(key); this.writeAny(value); } writeEndObj() { this.writer.u8u16(46, // . 3338 /* RESP.RN */); } } exports.RespEncoder = RespEncoder; //# sourceMappingURL=RespEncoder.js.map