json-joy
Version:
Collection of libraries for building collaborative editing apps.
191 lines (190 loc) • 6.46 kB
JavaScript
"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("./constants");
class Encoder extends CborEncoder_1.CborEncoder {
constructor(writer) {
super(writer || new CrdtWriter_1.CrdtWriter());
this.clockEncoder = new ClockEncoder_1.ClockEncoder();
this.time = 0;
this.cTableEntry = (entry) => {
const clock = entry.clock;
const writer = this.writer;
writer.vu57(clock.sid);
writer.vu57(clock.time);
};
this.tsLogical = (ts) => {
const relativeId = this.clockEncoder.append(ts);
this.writer.id(relativeId.sessionIndex, relativeId.timeDiff);
};
this.tsServer = (ts) => {
this.writer.vu57(ts.time);
};
this.ts = this.tsLogical;
this.cKey = (val, key) => {
this.writeStr(key);
this.cNode(this.doc.index.get(val));
};
}
encode(doc) {
this.doc = doc;
const writer = this.writer;
writer.reset();
if (doc.clock.sid === constants_1.SESSION.SERVER)
this.encodeServer(doc);
else
this.encodeLogical(doc);
return writer.flush();
}
encodeLogical(model) {
const writer = this.writer;
this.ts = this.tsLogical;
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);
}
encodeServer(model) {
this.ts = this.tsServer;
const writer = this.writer;
writer.u8(0b10000000);
writer.vu57((this.time = model.clock.time));
this.cRoot(model.root);
}
encodeClockTable(x0, x) {
const writer = this.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.writer.u8(0);
else
this.cNode(root.node());
}
writeTL(majorOverlay, length) {
const writer = this.writer;
if (length < 0b11111)
writer.u8(majorOverlay | length);
else {
writer.u8(majorOverlay | 0b11111);
writer.vu57(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);
if (val instanceof clock_1.Timestamp) {
this.writer.u8(1); // this.writeTL(CRDT_MAJOR_OVERLAY.CON, 1);
this.ts(val);
}
else {
this.writer.u8(0); // this.writeTL(CRDT_MAJOR_OVERLAY.CON, 0);
this.writeAny(val);
}
}
cVal(node) {
this.ts(node.id);
this.writer.u8(0b00100000); // this.writeTL(CRDT_MAJOR_OVERLAY.VAL, 0);
this.cNode(node.node());
}
cObj(node) {
this.ts(node.id);
const keys = node.keys;
this.writeTL(constants_2.CRDT_MAJOR_OVERLAY.OBJ, keys.size);
keys.forEach(this.cKey);
}
cVec(node) {
const elements = node.elements;
const length = elements.length;
this.ts(node.id);
this.writeTL(constants_2.CRDT_MAJOR_OVERLAY.VEC, length);
const index = this.doc.index;
for (let i = 0; i < length; i++) {
const elementId = elements[i];
if (!elementId)
this.writer.u8(0);
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);
for (let chunk = node.first(); chunk; chunk = node.next(chunk)) {
ts(chunk.id);
if (chunk.del)
this.writeUInteger(chunk.span);
else
this.writeStr(chunk.data);
}
}
cBin(node) {
const ts = this.ts;
const writer = this.writer;
ts(node.id);
this.writeTL(constants_2.CRDT_MAJOR_OVERLAY.BIN, node.count);
for (let chunk = node.first(); chunk; chunk = node.next(chunk)) {
ts(chunk.id);
const length = chunk.span;
const deleted = chunk.del;
writer.b1vu56(~~deleted, length);
if (deleted)
continue;
writer.buf(chunk.data, length);
}
}
cArr(node) {
const ts = this.ts;
const writer = this.writer;
ts(node.id);
this.writeTL(constants_2.CRDT_MAJOR_OVERLAY.ARR, node.count);
const index = this.doc.index;
for (let chunk = node.first(); chunk; chunk = node.next(chunk)) {
ts(chunk.id);
const span = chunk.span;
const deleted = chunk.del;
writer.b1vu56(~~deleted, span);
if (deleted)
continue;
const nodes = chunk.data;
for (let i = 0; i < span; i++)
this.cNode(index.get(nodes[i]));
}
}
}
exports.Encoder = Encoder;