From fc310da14d1a768fb2fac4b4bf4af2cfa56ad230 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Fri, 17 Jul 2026 22:53:35 -0400 Subject: [PATCH] chore(quark): sync vendored keyed and layout with standalone --- packages/quark/src/keyed.ts | 1 + packages/quark/src/layout.ts | 113 ++++++++++++++++++++--------------- 2 files changed, 65 insertions(+), 49 deletions(-) diff --git a/packages/quark/src/keyed.ts b/packages/quark/src/keyed.ts index 7468ef72da..32040703a5 100644 --- a/packages/quark/src/keyed.ts +++ b/packages/quark/src/keyed.ts @@ -133,6 +133,7 @@ export namespace Keyed { function publish(slot: Writable, value: A) { const current = slot() + // alien-signals uses SameValueZero-compatible identity for primitive writes. if (current === value || equivalent(current, value)) { if (options.metrics) options.metrics.equivalenceSuppressions++ return false diff --git a/packages/quark/src/layout.ts b/packages/quark/src/layout.ts index adb6fa1964..85677be2c8 100644 --- a/packages/quark/src/layout.ts +++ b/packages/quark/src/layout.ts @@ -41,8 +41,10 @@ export namespace Layout { readonly fields: StructFields } - export interface Union>>> - extends Field> { + export interface Union< + Tag extends PropertyKey, + Variants extends Readonly>>, + > extends Field> { readonly type: "union" readonly tag: Tag readonly variants: Variants @@ -66,7 +68,7 @@ export namespace Layout { readonly equivalent: (left: A, right: A) => boolean /** Bitmask of changed top-level fields; 0 means equivalent. Consistent with `equivalent`. */ readonly diff: (left: A, right: A) => number - /** Every known top-level property name to its change bit; immutable, key, and tag names map to 0. */ + /** Every known top-level property name to its change bit; immutable and key names map to 0. */ readonly bits: ReadonlyMap readonly keyOf: (value: A) => Key make(initial?: readonly A[], options?: { readonly metrics?: Keyed.Metrics }): Keyed.Keyed @@ -215,8 +217,7 @@ export namespace Layout { >(layout: KeyedUnion, options?: CompileOptions): Plan, A> export function compile(input: unknown, options: CompileOptions = {}): unknown { const layout = input as - | Struct - | KeyedUnion>>> + Struct | KeyedUnion>>> if (layout.type === "keyed-union") { const model = unionDiffModel(layout.key.name, layout.tag, layout.variants) return makePlan( @@ -311,17 +312,14 @@ export namespace Layout { initial: readonly A[], options?: { readonly metrics?: Keyed.Metrics }, ): Collection { - // The most recent publication's field diff, captured from the equivalence - // callback so index refresh can gate projections on it. `pending` hands a - // diff the collection already computed for a staged mutation to the - // comparator, so equivalence costs one comparison, not two. - let lastDiff = -1 - let pending = -1 + // `pending` hands a diff the collection already computed for a staged + // mutation to the comparator, so equivalence costs one comparison, not two. + let pending: number | ReadonlyMap | undefined const values = Keyed.make({ key: plan.keyOf, equivalent(left, right) { - lastDiff = pending !== -1 ? pending : plan.diff(left, right) - return lastDiff === 0 + const mask = typeof pending === "number" ? pending : pending?.get(plan.keyOf(left)) + return (mask ?? plan.diff(left, right)) === 0 }, metrics: options?.metrics, }) @@ -348,15 +346,20 @@ export namespace Layout { }, getOwnPropertyDescriptor(_, property) { trackMask = -1 - return Reflect.getOwnPropertyDescriptor(trackTarget!, property) + const descriptor = Reflect.getOwnPropertyDescriptor(trackTarget!, property) + return descriptor && { ...descriptor, configurable: true } }, }) function tracked(value: A, f: (value: A) => T) { trackTarget = value as Record trackMask = 0 - const result = f(trackProxy as A) - trackTarget = undefined - return result + try { + const result = f(trackProxy as A) + return { result, reads: trackMask } + } finally { + trackTarget = undefined + trackMask = 0 + } } // Each index entry stages user-code projections before any state mutation @@ -394,18 +397,22 @@ export namespace Layout { name, reads: (key) => readsByKey.get(key), stage(key, value) { - const source = tracked(value, extract) - const reads = trackMask const previous = byKey.get(key) - const members = source === previous?.source ? previous.members : new Set(source) - return () => { - readsByKey.set(key, reads) - if (!previous) members.forEach((member) => adjust(member, 1)) - if (previous && previous.members !== members) { - members.forEach((member) => !previous.members.has(member) && adjust(member, 1)) - previous.members.forEach((member) => !members.has(member) && adjust(member, -1)) + const trackedMembers = tracked(value, (candidate) => { + const source = extract(candidate) + return { + source, + members: source === previous?.source ? previous.members : new Set(source), } - byKey.set(key, { source, members }) + }) + return () => { + readsByKey.set(key, trackedMembers.reads) + if (!previous) trackedMembers.result.members.forEach((member) => adjust(member, 1)) + if (previous && previous.members !== trackedMembers.result.members) { + trackedMembers.result.members.forEach((member) => !previous.members.has(member) && adjust(member, 1)) + previous.members.forEach((member) => !trackedMembers.result.members.has(member) && adjust(member, -1)) + } + byKey.set(key, trackedMembers.result) } }, applyDelta(key, change) { @@ -468,18 +475,17 @@ export namespace Layout { reads: (key) => readsByKey.get(key), stage(key, value, mode) { const matched = tracked(value, matches) - const reads = trackMask return (valueSlot) => { - readsByKey.set(key, reads) + readsByKey.set(key, matched.reads) const previous = matching.has(key) - if (matched) matching.add(key) - if (!matched) matching.delete(key) + if (matched.result) matching.add(key) + if (!matched.result) matching.delete(key) if (mode === "add") return - if (slot === valueSlot && !matched) { + if (slot === valueSlot && !matched.result) { findFirst() return } - if (slot !== valueSlot && !previous && matched) afterPlacement(valueSlot) + if (slot !== valueSlot && !previous && matched.result) afterPlacement(valueSlot) } }, remove(key, removedSlot) { @@ -524,19 +530,25 @@ export namespace Layout { // Indexes are plain data, not reactive state; the transaction exists so // subscribers cannot observe published values with stale indexes. With // no staged commits there is nothing to observe out of order. - if (!staged) { - pending = mask - const changed = values.update(value) - pending = -1 - return changed - } + if (!staged) return publishValue() return Transaction.run(() => { - pending = mask - const changed = values.update(value) - pending = -1 + const changed = publishValue() if (changed) staged.forEach((commit) => commit(slot)) return changed }) + + function publishValue() { + return withPending(mask, () => values.update(value)) + } + } + + function withPending(mask: number | ReadonlyMap, f: () => T) { + pending = mask + try { + return f() + } finally { + pending = undefined + } } const collection: Collection = { @@ -549,6 +561,7 @@ export namespace Layout { const value = slot() existing.set(plan.keyOf(value), value) }) + const masks = new Map() // Stage user-code projections for new and changed values only; // retained equivalent values keep their index state and reads. const staged: Array<{ readonly key: Key; readonly commits: readonly Commit[] }> = [] @@ -559,13 +572,14 @@ export namespace Layout { return } const mask = plan.diff(existing.get(key)!, value) + masks.set(key, mask) if (mask === 0) return const commits = stageRefresh(key, value, mask) if (commits) staged.push({ key, commits }) }) const retained = new Set(keys) return Transaction.run(() => { - const changed = values.set(next) + const changed = withPending(masks, () => values.set(next)) existing.forEach((_value, key) => { if (!retained.has(key)) entries.forEach((entry) => entry.remove(key)) }) @@ -713,7 +727,7 @@ export namespace Layout { variants: Readonly>>, ): UnionDiffModel { const bits = new Map() - bits.set(tag, 0) + bits.set(tag, 1) bits.set(keyName, 0) const assigned = new Map() const perVariant = new Map | undefined>() @@ -731,7 +745,7 @@ export namespace Layout { if (!assigned.has(name) && !bits.has(name)) bits.set(name, 0) continue } - const bit = assigned.get(name) ?? 1 << Math.min(count++, 30) + const bit = assigned.get(name) ?? 1 << Math.min(count++ + 1, 30) assigned.set(name, bit) bits.set(name, bit) fields.push({ name, field, bit }) @@ -777,7 +791,8 @@ export namespace Layout { const label = JSON.stringify(name) const fields = model.perVariant.get(name) if (!fields) { - const index = emitter.custom.push(variants[name].equivalent) - 1 + const variant = variants[name] + const index = emitter.custom.push((left, right) => variant.equivalent(left, right)) - 1 return `case ${label}: return custom[${index}](left, right) ? 0 : -1` } const statements = fields.map((field) => { @@ -841,7 +856,7 @@ export namespace Layout { function expression(emitter: Emitter, field: Field, left: string, right: string): string { if (field.immutable) return "true" - if (field.primitive) return `Object.is(${left}, ${right})` + if (field.primitive && field.equivalent === Object.is) return `Object.is(${left}, ${right})` const layout = field as Field & { readonly type?: "struct" | "union" | "keyed-union" | "array" readonly fields?: Fields @@ -876,12 +891,12 @@ export namespace Layout { const name = declare(emitter, layout, (fn) => { const property = JSON.stringify(String(layout.key!.name)) const key = expression(emitter, layout.key!.field, `l[${property}]`, `r[${property}]`) - const union = declareUnion(emitter, layout.variants, layout.tag!, layout.variants!) + const union = declareUnion(emitter, {}, layout.tag!, layout.variants!) return `function ${fn}(l, r) { return ${key === "true" ? "" : `${key} && `}${union}(l, r) }` }) return `${name}(${left}, ${right})` } - const index = emitter.custom.push(field.equivalent) - 1 + const index = emitter.custom.push((left, right) => field.equivalent(left, right)) - 1 return `custom[${index}](${left}, ${right})` }