Skip to content

Commit

Permalink
Merge branch 'clock' of github.com:okcontract/cells into add-mapArrayRec
Browse files Browse the repository at this point in the history
  • Loading branch information
xikimay committed Mar 28, 2024
2 parents b876525 + e6eadbc commit fb62762
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 5 deletions.
95 changes: 93 additions & 2 deletions src/clock.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { writeFileSync } from "fs";
import { expect, test } from "vitest";
import { clock, clockWork } from "./clock";
import { sleep } from "./promise";
import { Debugger } from "./debug";
import { delayed, sleep } from "./promise";
import { SheetProxy } from "./proxy";
import { Sheet } from "./sheet";

Expand Down Expand Up @@ -52,7 +54,9 @@ test("wait list", async () => {
(_q: string[], prev: M) =>
({
...(prev || ({} as M)),
...Object.fromEntries(_q.map((elt) => [elt, elt.length]))
...Object.fromEntries(
_q.filter((elt) => !prev?.[elt]).map((elt) => [elt, elt.length])
)
}) as M,
"m"
);
Expand All @@ -66,3 +70,90 @@ test("wait list", async () => {
await sleep(10);
await expect(m.get()).resolves.toEqual({ foo: 3, bar: 3, test: 4 });
});

test("wait list self update fails", async () => {
const sheet = new Sheet();
const proxy = new SheetProxy(sheet);
const live = proxy.new(true);
const cl = clock(proxy, live, 10);
const q = proxy.new([] as string[], "q");
const m = cl.work(
[q],
(_q: string[], prev: M) => {
if (_q.includes("test")) q.set(["win"]);
return {
...(prev || ({} as M)),
...Object.fromEntries(
_q.filter((elt) => !prev?.[elt]).map((elt) => [elt, elt.length])
)
} as M;
},
"m"
);
await expect(m.get()).resolves.toEqual({});
q.set(["foo", "bar"]);
await expect(m.get()).resolves.toEqual({});
await sleep(15);
await expect(m.get()).resolves.toEqual({ foo: 3, bar: 3 });
q.set(["test"]);
await expect(m.get()).resolves.toEqual({ foo: 3, bar: 3 });
await sleep(10);
// fails: test is never updated because of the cancellation
await expect(m.get()).resolves.toEqual({ foo: 3, bar: 3 });
});

test("wait list self update with subscription", async () => {
const sheet = new Sheet();
const debug = new Debugger(sheet);
const proxy = new SheetProxy(sheet);
const live = proxy.new(true, "live");
const cl = clock(proxy, live, 10);
const q = proxy.new([] as string[], "q");
const remote = proxy.new(null as string[] | null, "remote");
remote.subscribe((l) => {
if (l) {
console.log({ remote: l });
q.set(l);
}
});
const m = cl.work(
[q],
async (_q: string[], prev: M) => {
if (_q.includes("test")) {
console.log({ test: "found" });
sheet.queue(remote, ["win"]);
}
const next = {
...(prev || ({} as M)),
...Object.fromEntries(
_q.filter((elt) => !prev?.[elt]).map((elt) => [elt, elt.length])
)
} as M;
console.log({ _q, prev, next });
return delayed(next, 10);
},
"m"
);
// debug.w(4);
writeFileSync("clock.dot", debug.dot("clockWork with remote"));
await expect(m.consolidatedValue).resolves.toEqual({});
q.set(["foo", "bar"]);
expect(m.consolidatedValue).toEqual({});
await sleep(15);
await expect(m.consolidatedValue).resolves.toEqual({ foo: 3, bar: 3 });
q.set(["test"]);
expect(m.consolidatedValue).toEqual({ foo: 3, bar: 3 });
await sleep(10);
await expect(m.consolidatedValue).resolves.toEqual({
foo: 3,
bar: 3,
test: 4
});
await sleep(10);
await expect(m.consolidatedValue).resolves.toEqual({
foo: 3,
bar: 3,
test: 4,
win: 3
});
});
4 changes: 2 additions & 2 deletions src/clock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export type Clock = ValueCell<number> & {
work: <T, NF extends boolean = false>(
cells: AnyCell<unknown>[],
fn: (...args: unknown[]) => T,
name: string,
name?: string,
nf?: NF
) => MapCell<T, NF>;
};
Expand Down Expand Up @@ -47,7 +47,7 @@ export const clockWork = <T, NF extends boolean = false>(
proxy: SheetProxy,
clock: Clock,
cells: AnyCell<unknown>[],
fn: (...args: unknown[]) => T,
fn: (...args: unknown[]) => T | Promise<T>,
name = "work",
nf?: NF
) => {
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export {
reduce,
sort
} from "./array";
export { clock, clockWork } from "./clock";
export { clock, clockWork, type Clock } from "./clock";
export { Debugger } from "./debug";
export { jsonStringify } from "./json";
export { nextSubscriber } from "./next";
Expand Down
19 changes: 19 additions & 0 deletions src/sheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ export class Sheet {
/** Cell holding all the current "initial" errors of the sheet */
public errors: CellErrors;

/** Queued updates */
private _queue: [number, unknown | Promise<unknown>][];
/** Cells that can be garbage collected */
private _gc: Set<number>;

Expand All @@ -112,6 +114,7 @@ export class Sheet {

this.errors = new CellErrors();
this._gc = new Set();
this._queue = [];
}

bless(id: number, name: string) {
Expand Down Expand Up @@ -564,6 +567,18 @@ export class Sheet {

// End of the update
release();

// Queued updates
// @todo transactions
for (const [id, v] of this._queue) {
const cell = this._cells[id];
if (!cell || !(cell instanceof ValueCell)) {
console.error(`cell ${id} is not a ValueCell`);
return;
}
cell.set(v);
}
this._queue = [];
}
);
}
Expand Down Expand Up @@ -943,4 +958,8 @@ export class Sheet {
const ids = input.map((v) => (typeof v === "number" ? v : v.id));
for (const id of ids) this._gc.add(id);
}

queue<T>(cell: number | AnyCell<T>, v: T | Promise<T>) {
this._queue.push([typeof cell === "number" ? cell : cell.id, v]);
}
}

0 comments on commit fb62762

Please sign in to comment.