Skip to content

Commit

Permalink
feat(json-crdt): 🎸 start debug file format implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
streamich committed Dec 3, 2023
1 parent 1796627 commit c24cea3
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 0 deletions.
92 changes: 92 additions & 0 deletions src/json-crdt/file/File.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import {Model} from "../model";
import {PatchLog} from "./PatchLog";
import {FileModelEncoding} from "./constants";
import {Encoder as SidecarEncoder} from '../codec/sidecar/binary/Encoder';
import {Encoder as StructuralEncoderCompact} from '../codec/structural/compact/Encoder';
import {Encoder as StructuralEncoderVerbose} from '../codec/structural/verbose/Encoder';
import {encode as encodeCompact} from '../../json-crdt-patch/codec/compact/encode';
import {encode as encodeVerbose} from '../../json-crdt-patch/codec/verbose/encode';
import type * as types from "./types";

export class File {
public static fromModel(model: Model): File {
return new File(model, PatchLog.fromModel(model));
}

constructor(
public readonly model: Model,
public readonly history: PatchLog,
) {}

public serialize(params: types.FileSerializeParams = {}): types.FileWriteSequence {
const view = this.model.view();
const metadata: types.FileMetadata = [
{},
FileModelEncoding.SidecarBinary,
];
let model: Uint8Array | unknown | null = null;
const modelFormat = params.model ?? 'sidecar';
switch (modelFormat) {
case 'sidecar': {
metadata[1] = FileModelEncoding.SidecarBinary;
const encoder = new SidecarEncoder();
const [, uint8] = encoder.encode(this.model);
model = uint8;
break;
}
case 'binary': {
metadata[1] = FileModelEncoding.StructuralBinary;
model = this.model.toBinary();
break;
}
case 'compact': {
metadata[1] = FileModelEncoding.StructuralCompact;
model = new StructuralEncoderCompact().encode(this.model);
break;
}
case 'verbose': {
metadata[1] = FileModelEncoding.StructuralVerbose;
model = new StructuralEncoderVerbose().encode(this.model);
break;
}
default:
throw new Error(`Invalid model format: ${modelFormat}`);
}
const history: types.FileWriteSequenceHistory = [
null,
[],
];
const patchFormat = params.history ?? 'binary';
switch (patchFormat) {
case 'binary': {
history[0] = this.history.start.toBinary();
this.history.patches.forEach(({v}) => {
history[1].push(v.toBinary());
});
break;
}
case 'compact': {
history[0] = new StructuralEncoderCompact().encode(this.history.start);
this.history.patches.forEach(({v}) => {
history[1].push(encodeCompact(v));
});
break;
}
case 'verbose': {
history[0] = new StructuralEncoderVerbose().encode(this.history.start);
this.history.patches.forEach(({v}) => {
history[1].push(encodeVerbose(v));
});
break;
}
default:
throw new Error(`Invalid history format: ${patchFormat}`);
}
return [
view,
metadata,
model,
history,
];
}
}
25 changes: 25 additions & 0 deletions src/json-crdt/file/PatchLog.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import {ITimestampStruct, Patch, ServerClockVector, compare} from "../../json-crdt-patch";
import {AvlMap} from "../../util/trees/avl/AvlMap";
import {Model} from "../model";

export class PatchLog {
public static fromModel (model: Model): PatchLog {
const start = new Model(model.clock.clone());
const log = new PatchLog(start);
if (model.api.builder.patch.ops.length) {
const patch = model.api.flush();
log.push(patch);
}
return log;
}

public readonly patches = new AvlMap<ITimestampStruct, Patch>(compare);

constructor (public readonly start: Model) {}

public push(patch: Patch): void {
const id = patch.getId();
if (!id) return;
this.patches.set(id, patch);
}
}
7 changes: 7 additions & 0 deletions src/json-crdt/file/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const enum FileModelEncoding {
None = 0,
SidecarBinary = 1,
StructuralBinary = 5,
StructuralCompact = 6,
StructuralVerbose = 7,
}
29 changes: 29 additions & 0 deletions src/json-crdt/file/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type {FileModelEncoding} from "./constants";

export type FileMetadata = [
map: {},
modelFormat: FileModelEncoding,
];

export type FileWriteSequence = [
view: unknown | null,
metadata: FileMetadata,
model: Uint8Array | unknown | null,
history: FileWriteSequenceHistory,
];

export type FileWriteSequenceHistory = [
model: Uint8Array | unknown | null,
patches: Array<Uint8Array | unknown>,
];

export type FileReadSequence = [
...FileWriteSequence,
...frontier: Array<Uint8Array | unknown>,
];

export interface FileSerializeParams {
noView?: boolean;
model?: 'sidecar' | 'binary' | 'compact' | 'verbose';
history?: 'binary' | 'compact' | 'verbose';
}

0 comments on commit c24cea3

Please sign in to comment.