Skip to content

Commit

Permalink
rf
Browse files Browse the repository at this point in the history
  • Loading branch information
abhishiv committed Sep 3, 2024
1 parent 83d0ec0 commit c4fb8b8
Show file tree
Hide file tree
Showing 7 changed files with 239 additions and 161 deletions.
1 change: 1 addition & 0 deletions src/core/state.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ describe("Basic Implementation of Stores & Wires", (test) => {
});
expect(changes.length).toBe(2);
changes.forEach((change) => {
console.log("1", change);
applyStoreChange(store2, change);
});
const store2Value = reify(store2);
Expand Down
132 changes: 102 additions & 30 deletions src/core/state/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,13 @@ function createStoreSubscription<T>(
set.add(encodedCursor);
wire.storesRS.set(manager, set);
}
const v = getValueUsingPath(manager.value as any, cursorPath);
return v;
try {
const v = getValueUsingPath(manager.value as any, cursorPath);
return v;
} catch (e) {
console.log(wire, wire.storesRS, encodedCursor, manager.value);
throw e;
}
}

// Handle changes in the store and trigger associated tasks and wires
Expand All @@ -61,11 +66,11 @@ export function handleStoreChange(
oldValue: any,
changeData: ApplyData
) {
// console.log("handleStoreChange", path, newValue, oldValue, changeData);
const changePath = path as string[];
adjustCursorForArrayChange(manager, path as string[], changeData);
const wiresToRun = findMatchingWires(manager, changePath, changeData);

runWires(wiresToRun);

triggerStoreTasks(manager, changePath, newValue, changeData);
}

Expand Down Expand Up @@ -124,39 +129,106 @@ function triggerStoreTasks(
const isPathMatching =
changePath.slice(0, path.length).join("/") === path.join("/");
if (isPathMatching) {
observor({ data: changeData, path: changePath, value: newValue });
observor({
data: (changeData
? {
name: changeData.name,
args: changeData.args,
result: undefined,
}
: undefined) as any,
path: changePath,
value: newValue,
});
}
});
}

//
// Function to adjust cursor paths for array changes
function adjustCursorForArrayChange(cursor: string[], change: any): string[] {
const newCursor = [...cursor];
const index = parseInt(change.path[change.path.length - 1], 10);

switch (change.type) {
case "insert":
if (index <= cursor.length) {
newCursor.push(String(index));
}
break;
case "delete":
if (index < cursor.length) {
newCursor.splice(index, 1);
function adjustCursorForArrayChange(
manager: StoreManager,
changePath: string[],
change: ApplyData
): void {
if (!change || change.name !== "splice") {
return;
}
const args = change.args as [string, string];
const start = parseInt(args[0]);
const deleteCount = parseInt(args[1]);

// console.log("adjustCursorForArrayChange", { start, deleteCount });

manager.wires.forEach((wire) => {
wire.storesRS.forEach((cursorSet) => {
const { toRemove, toAdd } = adjustCursorsInSet(
cursorSet,
changePath,
start,
deleteCount
);

toRemove.forEach((cursor) => cursorSet.delete(cursor));
toAdd.forEach((cursor) => cursorSet.add(cursor));

//console.log({ toRemove, toAdd }, wire.storesRS);
});
});

manager.tasks.forEach((task) => {
if (isPathAffected(task.path, changePath)) {
const listenerIndex = getListenerIndex(task.path, changePath.length);

if (start + deleteCount <= listenerIndex) {
const newIndex = listenerIndex - deleteCount;
task.path[changePath.length] = newIndex.toString();
//console.log("Updated task path", encodeCursor(task.path));
}
break;
case "splice":
const { index: spliceIndex, removed, added } = change;
if (spliceIndex <= cursor.length) {
newCursor.splice(
spliceIndex,
removed.length,
...added.map((_: any, i: any) => String(spliceIndex + i))
);
}
});
}

function adjustCursorsInSet(
cursorSet: Set<string>,
changePath: string[],
start: number,
deleteCount: number
): { toRemove: string[]; toAdd: string[] } {
const toRemove: string[] = [];
const toAdd: string[] = [];

cursorSet.forEach((cursorString) => {
const cursor = decodeCursor(cursorString);
if (isPathMatching(cursor, changePath)) {
const listenerIndex = getListenerIndex(cursor, changePath.length);

if (start + deleteCount <= listenerIndex) {
toRemove.push(cursorString);
cursor[changePath.length] = (listenerIndex - deleteCount).toString();
toAdd.push(encodeCursor(cursor));
}
break;
}
}
});

return { toRemove, toAdd };
}

function isPathMatching(cursor: string[], changePath: string[]): boolean {
return (
encodeCursor(changePath) ===
encodeCursor(cursor.slice(0, changePath.length))
);
}

function getListenerIndex(cursor: string[], pathLength: number): number {
return parseInt(cursor[pathLength]);
}

return newCursor;
function isPathAffected(path: string[], changePath: string[]): boolean {
return (
encodeCursor(changePath) ===
encodeCursor(path.slice(0, changePath.length)) &&
path.length > changePath.length
);
}
10 changes: 3 additions & 7 deletions src/core/state/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,9 @@ export type Signal<T = unknown> = SignalAPI & {
};

export type ExtractElement<ArrayType extends ArrayOrObject> =
ArrayType extends readonly (infer ElementType)[]
? ElementType
: ArrayType extends { [key: string]: infer ElementType2 }
? ElementType2
: never;
ArrayType extends readonly (infer ElementType)[] ? ElementType : never;

export type ArrayOrObject = Array<unknown> | Record<string, unknown>;
export type ArrayOrObject = Array<unknown>;

export type StoreCursor<T = unknown, TRoot = T> = T extends ArrayOrObject
? {
Expand Down Expand Up @@ -90,7 +86,7 @@ export type Wire<T = unknown> = {

// Signals/Stores read-subscribed last run
sigRS: Set<Signal>;
storesRS: WeakMap<StoreManager, Set<string>>;
storesRS: Map<StoreManager, Set<string>>;

// Post-run tasks
tasks: Set<(nextValue: T) => void>;
Expand Down
4 changes: 2 additions & 2 deletions src/core/state/wire.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const createWire: WireFactory = (arg: WireFunction): Wire => {
type: Constants.WIRE,
fn: arg,
sigRS: new Set(),
storesRS: new WeakMap(),
storesRS: new Map(),
tasks: new Set(),
state: S_NEEDS_RUN,
upper: undefined,
Expand Down Expand Up @@ -120,7 +120,7 @@ const _initWire = (wire: Wire<any>): void => {
wire.lower = new Set();
// Drop all signals now that they have been unlinked
wire.sigRS = new Set();
wire.storesRS = new WeakMap();
wire.storesRS = new Map();
};

// Pauses a wire so signal writes won't cause runs. Affects nested wires
Expand Down
18 changes: 17 additions & 1 deletion src/dom/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const insertElement = (
el: VElement,
after?: string
) => {
console.log("insert", parentPath, el, after);
// console.log("insert", parentPath, el, after);

const step = parentPath.reduce<TreeStep | undefined>((step, key) => {
if (!step) return;
Expand Down Expand Up @@ -176,6 +176,22 @@ export const removeNode = (renderCtx: RenderContext, node: TreeStep) => {
const nodes = getDescendants(node);
// console.log("removeNode nodes", node, nodes);
nodes.forEach((step) => {
if (step.type === DOMConstants.ComponentTreeStep) {
//step.wires.length && console.log("s", step, step.wires.length);
step.wires.forEach((w) => {
w.storesRS.forEach((s, manager) => {
if (manager.wires.has(w)) {
//console.log("removing wire", s, manager);
manager.wires.delete(w);
}
});
w.sigRS.forEach((sig) => {
sig.wires.delete(w);
});
w.tasks.clear();
});
step.wires = [];
}
if (step.dom) {
if (
step.type === DOMConstants.ComponentTreeStep &&
Expand Down
Loading

0 comments on commit c4fb8b8

Please sign in to comment.