json-joy
Version:
Collection of libraries for building collaborative editing apps.
140 lines (139 loc) • 3.99 kB
JavaScript
import { CborDecoderBase } from '@jsonjoy.com/json-pack/lib/cbor/CborDecoderBase';
import { CrdtReader } from '../../../../json-crdt-patch/util/binary/CrdtReader';
import { CRDT_MAJOR } from './constants';
export class ViewDecoder extends CborDecoderBase {
time = -1;
constructor() {
super(new CrdtReader());
}
decode(data) {
const reader = this.reader;
this.time = -1;
reader.reset(data);
const isServerTime = reader.peak() & 0b10000000;
if (isServerTime) {
reader.x++;
this.time = reader.vu57();
}
else {
reader.x += 4;
}
return this.cRoot();
}
ts() {
if (this.time < 0)
this.reader.idSkip();
else
this.reader.vu57Skip();
}
cRoot() {
const reader = this.reader;
const peek = reader.uint8[reader.x];
return !peek ? undefined : this.cNode();
}
cNode() {
const reader = this.reader;
this.ts();
const octet = reader.u8();
const major = octet >> 5;
const minor = octet & 0b11111;
const length = minor < 0b11111 ? minor : reader.vu57();
switch (major) {
case CRDT_MAJOR.CON:
return this.cCon(length);
case CRDT_MAJOR.VAL:
return this.cNode();
case CRDT_MAJOR.VEC:
return this.cVec(length);
case CRDT_MAJOR.OBJ:
return this.cObj(length);
case CRDT_MAJOR.STR:
return this.cStr(length);
case CRDT_MAJOR.BIN:
return this.cBin(length);
case CRDT_MAJOR.ARR:
return this.cArr(length);
}
return undefined;
}
cCon(length) {
return !length ? this.val() : (this.ts(), null);
}
cObj(length) {
const obj = {};
for (let i = 0; i < length; i++) {
const key = this.key();
const value = this.cNode();
if (value !== undefined)
obj[key] = value;
}
return obj;
}
cVec(length) {
const reader = this.reader;
const obj = [];
for (let i = 0; i < length; i++) {
const octet = reader.peak();
if (!octet) {
reader.x++;
obj.push(undefined);
}
else
obj.push(this.cNode());
}
return obj;
}
cStr(length) {
let str = '';
for (let i = 0; i < length; i++) {
this.ts();
const val = this.val();
if (typeof val === 'string')
str += val;
}
return str;
}
cBin(length) {
const reader = this.reader;
const buffers = [];
let totalLength = 0;
for (let i = 0; i < length; i++) {
this.ts();
const [deleted, length] = reader.b1vu56();
if (deleted)
continue;
buffers.push(reader.buf(length));
totalLength += length;
}
const res = new Uint8Array(totalLength);
let offset = 0;
for (let i = 0; i < buffers.length; i++) {
const byteLength = buffers[i].length;
res.set(buffers[i], offset);
offset += byteLength;
}
return res;
}
cArr(length) {
const arr = [];
for (let i = 0; i < length; i++) {
const values = this.cArrChunk();
if (values && values.length)
arr.push(...values);
}
return arr;
}
cArrChunk() {
this.ts();
const [deleted, length] = this.reader.b1vu56();
if (deleted) {
return undefined;
}
else {
const values = [];
for (let i = 0; i < length; i++)
values.push(this.cNode());
return values;
}
}
}