UNPKG

json-joy

Version:

Collection of libraries for building collaborative editing apps.

185 lines (184 loc) 6.87 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Encoder = void 0; const tslib_1 = require("tslib"); const nodes = tslib_1.__importStar(require("../../../nodes")); const ClockEncoder_1 = require("../../../../json-crdt-patch/codec/clock/ClockEncoder"); const CrdtWriter_1 = require("../../../../json-crdt-patch/util/binary/CrdtWriter"); const clock_1 = require("../../../../json-crdt-patch/clock"); const CborEncoder_1 = require("@jsonjoy.com/json-pack/lib/cbor/CborEncoder"); const constants_1 = require("../../../../json-crdt-patch/constants"); const constants_2 = require("../../structural/binary/constants"); const insertion_1 = require("@jsonjoy.com/util/lib/sort/insertion"); const Model_1 = require("../../../model/Model"); class Encoder { constructor() { this.clockEncoder = new ClockEncoder_1.ClockEncoder(); this.time = 0; this.viewEncoder = new CborEncoder_1.CborEncoder(new CrdtWriter_1.CrdtWriter()); this.metaEncoder = new CborEncoder_1.CborEncoder(new CrdtWriter_1.CrdtWriter()); this.index = 0; this.cTableEntry = (entry) => { const clock = entry.clock; const writer = this.metaEncoder.writer; writer.vu57(clock.sid); writer.vu57(clock.time); }; this.ts = (ts) => { const relativeId = this.clockEncoder.append(ts); this.metaEncoder.writer.id(relativeId.sessionIndex, relativeId.timeDiff); }; } encode(doc) { this.doc = doc; this.index = 0; this.metaEncoder.writer.reset(); this.encodeLogical(doc); return [this.viewEncoder.writer.flush(), this.metaEncoder.writer.flush()]; } encodeLogical(model) { const writer = this.metaEncoder.writer; this.clockEncoder.reset(model.clock); writer.ensureCapacity(4); const x0 = writer.x0; const x = writer.x; writer.x += 4; this.cRoot(model.root); this.encodeClockTable(x0, x); } encodeClockTable(x0, x) { const writer = this.metaEncoder.writer; const shift = writer.x0 - x0; writer.view.setUint32(writer.x0 + (x - x0), writer.x - x - shift - 4); const clockEncoder = this.clockEncoder; const table = clockEncoder.table; const length = table.size; writer.vu57(length); table.forEach(this.cTableEntry); } cRoot(root) { const val = root.val; if (val.sid === constants_1.SESSION.SYSTEM) this.metaEncoder.writer.u8(0); else this.cNode(root.node()); } writeTL(majorOverlay, length) { const writer = this.metaEncoder.writer; if (length < 24) writer.u8(majorOverlay + length); else if (length <= 0xff) writer.u16(((majorOverlay + 24) << 8) + length); else if (length <= 0xffff) writer.u8u16(majorOverlay + 25, length); else writer.u8u32(majorOverlay + 26, length); } cNode(node) { // TODO: PERF: use a switch? if (node instanceof nodes.ConNode) this.cCon(node); else if (node instanceof nodes.ValNode) this.cVal(node); else if (node instanceof nodes.StrNode) this.cStr(node); else if (node instanceof nodes.ObjNode) this.cObj(node); else if (node instanceof nodes.VecNode) this.cVec(node); else if (node instanceof nodes.ArrNode) this.cArr(node); else if (node instanceof nodes.BinNode) this.cBin(node); } cCon(node) { const val = node.val; this.ts(node.id); const metaEncoder = this.metaEncoder; if (val instanceof clock_1.Timestamp) { this.viewEncoder.writeNull(); metaEncoder.writer.u8(1); // this.writeTL(CRDT_MAJOR_OVERLAY.CON, 1); this.ts(val); } else { this.viewEncoder.writeAny(val); metaEncoder.writer.u8(0); // this.writeTL(CRDT_MAJOR_OVERLAY.CON, 0); } } cVal(node) { this.ts(node.id); this.metaEncoder.writer.u8(0b00100000); // this.writeTL(CRDT_MAJOR_OVERLAY.VAL, 0); this.cNode(node.node()); } cObj(node) { this.ts(node.id); const keys = (0, insertion_1.sort)([...node.keys.keys()]); const size = keys.length; this.writeTL(constants_2.CRDT_MAJOR_OVERLAY.OBJ, size); const viewEncoder = this.viewEncoder; viewEncoder.writeObjHdr(size); for (let i = 0; i < size; i++) { const key = keys[i]; viewEncoder.writeStr(key); this.cNode(node.get(key)); } } cVec(node) { this.ts(node.id); const elements = node.elements; const length = elements.length; this.writeTL(constants_2.CRDT_MAJOR_OVERLAY.VEC, length); this.viewEncoder.writeArrHdr(length); const index = this.doc.index; for (let i = 0; i < length; i++) { const elementId = elements[i]; if (!elementId) this.cCon(Model_1.UNDEFINED); else this.cNode(index.get(elementId)); } } cStr(node) { const ts = this.ts; ts(node.id); this.writeTL(constants_2.CRDT_MAJOR_OVERLAY.STR, node.count); this.viewEncoder.writeStr(node.view()); const writer = this.metaEncoder.writer; for (let chunk = node.first(); chunk; chunk = node.next(chunk)) { ts(chunk.id); writer.b1vu56(~~chunk.del, chunk.span); } } cBin(node) { const ts = this.ts; ts(node.id); this.writeTL(constants_2.CRDT_MAJOR_OVERLAY.BIN, node.count); this.viewEncoder.writeBin(node.view()); const writer = this.metaEncoder.writer; for (let chunk = node.first(); chunk; chunk = node.next(chunk)) { ts(chunk.id); writer.b1vu56(~~chunk.del, chunk.span); } } cArr(node) { const ts = this.ts; ts(node.id); this.writeTL(constants_2.CRDT_MAJOR_OVERLAY.ARR, node.count); this.viewEncoder.writeArrHdr(node.length()); const writer = this.metaEncoder.writer; const index = this.doc.index; for (let chunk = node.first(); chunk; chunk = node.next(chunk)) { ts(chunk.id); const deleted = chunk.del; const span = chunk.span; writer.b1vu56(~~deleted, span); if (!deleted) { const elements = chunk.data; const elementsLength = elements.length; for (let i = 0; i < elementsLength; i++) this.cNode(index.get(elements[i])); } } } } exports.Encoder = Encoder;