@solidjs/signals 2.0.0-rc.19 → 2.0.0-rc.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dev-shared.js +553 -264
- package/dist/dev.attribution.js +18 -18
- package/dist/dev.js +1030 -439
- package/dist/observe/affects.js +12 -2
- package/dist/observe/boundaries.js +168 -115
- package/dist/observe/core/async.js +57 -37
- package/dist/observe/core/attribution.js +6 -6
- package/dist/observe/core/constants.js +9 -1
- package/dist/observe/core/copies.js +10 -0
- package/dist/observe/core/core.js +261 -181
- package/dist/observe/core/effect.js +32 -27
- package/dist/observe/core/graph.js +7 -7
- package/dist/observe/core/heap.js +29 -29
- package/dist/observe/core/lanes.js +301 -101
- package/dist/observe/core/owner.js +13 -13
- package/dist/observe/core/scheduler.js +124 -69
- package/dist/observe/core/truth.js +9 -7
- package/dist/observe/core/verdict.js +160 -98
- package/dist/observe/deferred.js +1 -1
- package/dist/observe/index.js +2 -0
- package/dist/observe/map.js +120 -116
- package/dist/observe/reveal.js +48 -48
- package/dist/observe/signals.js +5 -5
- package/dist/observe/store/affects.js +2 -2
- package/dist/observe/store/optimistic.js +272 -176
- package/dist/observe/store/projection.js +21 -10
- package/dist/observe/store/reconcile.js +8 -2
- package/dist/observe/store/store.js +91 -55
- package/dist/observe/store/types.js +11 -1
- package/dist/observe/store/utils.js +1 -1
- package/dist/prod/affects.js +12 -2
- package/dist/prod/boundaries.js +164 -109
- package/dist/prod/core/async.js +201 -181
- package/dist/prod/core/constants.js +9 -1
- package/dist/prod/core/copies.js +10 -0
- package/dist/prod/core/core.js +244 -164
- package/dist/prod/core/dev.js +108 -3
- package/dist/prod/core/effect.js +28 -23
- package/dist/prod/core/graph.js +9 -9
- package/dist/prod/core/heap.js +16 -16
- package/dist/prod/core/identities.js +1 -1
- package/dist/prod/core/lanes.js +307 -95
- package/dist/prod/core/owner.js +22 -22
- package/dist/prod/core/scheduler.js +266 -211
- package/dist/prod/core/truth.js +9 -7
- package/dist/prod/core/verdict.js +161 -99
- package/dist/prod/deferred.js +1 -1
- package/dist/prod/index.js +2 -0
- package/dist/prod/map.js +78 -74
- package/dist/prod/reveal.js +34 -34
- package/dist/prod/signals.js +3 -3
- package/dist/prod/store/affects.js +15 -15
- package/dist/prod/store/optimistic.js +185 -89
- package/dist/prod/store/projection.js +49 -38
- package/dist/prod/store/reconcile.js +8 -2
- package/dist/prod/store/store.js +99 -63
- package/dist/prod/store/types.js +11 -1
- package/dist/types/affects.d.ts +3 -2
- package/dist/types/boundaries.d.ts +14 -2
- package/dist/types/core/async.d.ts +2 -1
- package/dist/types/core/constants.d.ts +8 -0
- package/dist/types/core/copies.d.ts +54 -0
- package/dist/types/core/core.d.ts +15 -0
- package/dist/types/core/dev.d.ts +1 -1
- package/dist/types/core/lanes.d.ts +8 -1
- package/dist/types/core/scheduler.d.ts +36 -4
- package/dist/types/core/truth.d.ts +3 -1
- package/dist/types/core/types.d.ts +6 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/store/hooks.d.ts +15 -1
- package/dist/types/store/store.d.ts +2 -1
- package/dist/types/store/target.d.ts +5 -0
- package/dist/types/store/types.d.ts +7 -0
- package/package.json +1 -1
|
@@ -1,20 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CONFIG_GUESS, CONFIG_OVERRIDE, EFFECT_RENDER, CONFIG_CHILDREN_FORBIDDEN, NOT_PENDING, CONFIG_SLOT_NODE, CONFIG_AUTO_DISPOSE, REACTIVE_REASK } from "../core/constants.js";
|
|
2
2
|
|
|
3
|
-
import { computed, joinPassAt, ext, untrack, read
|
|
3
|
+
import { computed, isEqual, joinPassAt, ext, untrack, read } from "../core/core.js";
|
|
4
4
|
|
|
5
|
-
import { pendingGuessOf, optimisticWrite } from "../core/lanes.js";
|
|
5
|
+
import { take, pendingGuessOf, optimisticWrite } from "../core/lanes.js";
|
|
6
6
|
|
|
7
7
|
import { getOwner } from "../core/owner.js";
|
|
8
8
|
|
|
9
|
-
import { GlobalQueue, txOf, insertSubs, joinFuture, resolveTx, passLane, list, laneDirty, notifyEpoch, schedule } from "../core/scheduler.js";
|
|
9
|
+
import { GlobalQueue, txOf, insertSubs, joinFuture, resolveTx, passLane, list, laneDirty, clock, merge, notifyEpoch, schedule } from "../core/scheduler.js";
|
|
10
10
|
|
|
11
11
|
import { runProjectionComputed } from "./projection.js";
|
|
12
12
|
|
|
13
|
-
import {
|
|
13
|
+
import { reconcileState } from "./reconcile.js";
|
|
14
|
+
|
|
15
|
+
import { wrap, storeSetter, getContainerNode, getHasNode, getNode, LaneView, committed, unwrapValue, sameKey, resolveChainedRaw, targetsEqual, cloneRaw } from "./store.js";
|
|
14
16
|
|
|
15
17
|
import { installOptHooks } from "./hooks.js";
|
|
16
18
|
|
|
17
|
-
import { $OWNER } from "./target.js";
|
|
19
|
+
import { $OWNER, lookupTarget } from "./target.js";
|
|
18
20
|
|
|
19
21
|
import { $TARGET, markRawIngest, $TRACK, isWrappable } from "./types.js";
|
|
20
22
|
|
|
@@ -93,17 +95,17 @@ function notifyOptimisticWrites(e, n) {
|
|
|
93
95
|
// A chained draft holds the inner store's raws; a raw is the inner slot it
|
|
94
96
|
// resolves to (as a read of it serves) — the row a held write staged is
|
|
95
97
|
// the same row, not a guess over the slot (#3796).
|
|
96
|
-
const
|
|
97
|
-
const
|
|
98
|
+
const f = n[t];
|
|
99
|
+
const a = unwrapValue(o && f ? resolveChainedRaw(e, t, f) : f);
|
|
98
100
|
if (!(t in i)) {
|
|
99
|
-
guess(getNode(e, t), t, false,
|
|
101
|
+
guess(getNode(e, t), t, false, a);
|
|
100
102
|
guess(getHasNode(e, t), t, true, true);
|
|
101
103
|
s = true;
|
|
102
104
|
} else {
|
|
103
105
|
const n = i[t];
|
|
104
|
-
const
|
|
105
|
-
if (!isEqual(
|
|
106
|
-
guess(getNode(e, t), t, false,
|
|
106
|
+
const f = unwrapValue(o && n ? resolveChainedRaw(e, t, n) : n);
|
|
107
|
+
if (!isEqual(f, a) && !targetsEqual(f, a)) {
|
|
108
|
+
guess(getNode(e, t), t, false, a);
|
|
107
109
|
if (r) s = true;
|
|
108
110
|
}
|
|
109
111
|
}
|
|
@@ -125,17 +127,17 @@ function notifyOptimisticWrites(e, n) {
|
|
|
125
127
|
// re-base over another action's truth must not bring them back. A set
|
|
126
128
|
// (empty or not) marks a keyed arrangement guess (`fold`).
|
|
127
129
|
let s = null;
|
|
128
|
-
const
|
|
129
|
-
if (r &&
|
|
130
|
+
const f = e.fam.key;
|
|
131
|
+
if (r && f !== null && f !== undefined) {
|
|
130
132
|
s = new Set;
|
|
131
133
|
const e = new Set;
|
|
132
134
|
for (let n = 0; n < o.length; n++) {
|
|
133
|
-
const t = isWrappable(o[n]) ?
|
|
135
|
+
const t = isWrappable(o[n]) ? f(o[n]) : undefined;
|
|
134
136
|
if (t !== undefined) e.add(t);
|
|
135
137
|
}
|
|
136
138
|
for (let n = 0; n < i.length; n++) {
|
|
137
139
|
const t = unwrapValue(i[n]);
|
|
138
|
-
const r = isWrappable(t) ?
|
|
140
|
+
const r = isWrappable(t) ? f(t) : undefined;
|
|
139
141
|
if (r !== undefined && !e.has(r)) s.add(r);
|
|
140
142
|
}
|
|
141
143
|
}
|
|
@@ -143,10 +145,10 @@ function notifyOptimisticWrites(e, n) {
|
|
|
143
145
|
}
|
|
144
146
|
if (e.dk !== null) optimisticWrite(e.dk, {});
|
|
145
147
|
markOverlaid(e);
|
|
146
|
-
const
|
|
147
|
-
if (
|
|
148
|
+
const f = optStaged.get(e);
|
|
149
|
+
if (f === undefined) return null;
|
|
148
150
|
optStaged.delete(e);
|
|
149
|
-
return
|
|
151
|
+
return f;
|
|
150
152
|
}
|
|
151
153
|
|
|
152
154
|
/** The container comparator's lane arm (store.ts `containerEquals`): an
|
|
@@ -155,22 +157,24 @@ function notifyOptimisticWrites(e, n) {
|
|
|
155
157
|
const i = n instanceof LaneView;
|
|
156
158
|
const r = t instanceof LaneView;
|
|
157
159
|
if (!i && !r) return false;
|
|
158
|
-
return arrangementEqual(i ? n.rows : n, r ? t.rows : t, e.fam
|
|
160
|
+
return arrangementEqual(i ? n.rows : n, r ? t.rows : t, e.fam);
|
|
159
161
|
}
|
|
160
162
|
|
|
161
163
|
function rowSame(e, n, t) {
|
|
162
164
|
if (isEqual(e, n) || targetsEqual(e, n)) return true;
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
//
|
|
167
|
-
//
|
|
168
|
-
//
|
|
169
|
-
//
|
|
170
|
-
//
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
165
|
+
const i = t.key;
|
|
166
|
+
if (!i || !isWrappable(e) || !isWrappable(n)) return false;
|
|
167
|
+
// A row the store already serves is its proxy's row: a reader (a list)
|
|
168
|
+
// holds that proxy, so another object at the index is another row, by key
|
|
169
|
+
// or contents alike — a guess's fresh object wraps a new proxy. A landing's
|
|
170
|
+
// object has been adopted by the row it pairs with, so it serves that
|
|
171
|
+
// row's proxy. Only rows no proxy serves yet pair by key, keyless rows by
|
|
172
|
+
// position — reconcile's fallback (#3898).
|
|
173
|
+
const r = lookupTarget(e = unwrapValue(e), t);
|
|
174
|
+
const o = lookupTarget(n = unwrapValue(n), t);
|
|
175
|
+
if (r || o) return r === o;
|
|
176
|
+
// (Two keyless rows: `undefined` is the same key.)
|
|
177
|
+
return sameKey(i(e), i(n));
|
|
174
178
|
}
|
|
175
179
|
|
|
176
180
|
/** Whether reconcile would write anything into `a` from `b`: wrappable
|
|
@@ -230,18 +234,18 @@ function arrangementEqual(e, n, t) {
|
|
|
230
234
|
}
|
|
231
235
|
}
|
|
232
236
|
for (let s = 0; s < n.length; s++) {
|
|
233
|
-
const
|
|
234
|
-
let
|
|
235
|
-
if (isWrappable(
|
|
237
|
+
const f = n[s];
|
|
238
|
+
let a;
|
|
239
|
+
if (isWrappable(f)) {
|
|
236
240
|
if (o !== null) {
|
|
237
|
-
const e = t(
|
|
238
|
-
if (e !== undefined)
|
|
239
|
-
} else if (s < i && isWrappable(unwrapValue(r[s])))
|
|
241
|
+
const e = t(f);
|
|
242
|
+
if (e !== undefined) a = o.get(e);
|
|
243
|
+
} else if (s < i && isWrappable(unwrapValue(r[s]))) a = r[s];
|
|
240
244
|
}
|
|
241
|
-
if (
|
|
242
|
-
if (unwrapValue(
|
|
243
|
-
if (e[s] !==
|
|
244
|
-
} else if (unwrapValue(e[s]) !==
|
|
245
|
+
if (a !== undefined) {
|
|
246
|
+
if (unwrapValue(a) !== f) reconcileDraft(a, f, t);
|
|
247
|
+
if (e[s] !== a) e[s] = a;
|
|
248
|
+
} else if (unwrapValue(e[s]) !== f) e[s] = f;
|
|
245
249
|
}
|
|
246
250
|
if (e.length !== n.length) e.length = n.length;
|
|
247
251
|
return;
|
|
@@ -257,6 +261,29 @@ function arrangementEqual(e, n, t) {
|
|
|
257
261
|
for (const t of Object.keys(e)) if (!(t in n)) delete e[t];
|
|
258
262
|
}
|
|
259
263
|
|
|
264
|
+
/** Core asks (lanes `laneWrite`): the family's derive, re-asking in a lane of
|
|
265
|
+
* another action than the one that guessed this slot, writes it — that
|
|
266
|
+
* lane's new question, which the guess (over the old one) does not answer:
|
|
267
|
+
* the slot is the lane's derivation from here (F-6, #4336; lanes
|
|
268
|
+
* `laneStage` for a node's own pass). */ GlobalQueue.fn = (e, n) => {
|
|
269
|
+
const t = e.O;
|
|
270
|
+
if (n) {
|
|
271
|
+
// The guess comes back (lanes `endLanes`): on the slot's node now — the
|
|
272
|
+
// node itself, or the one a read made after it was released.
|
|
273
|
+
const n = e.Xe;
|
|
274
|
+
markOverlaid(t);
|
|
275
|
+
return n === $TRACK ? getContainerNode(t) : e.ye === isEqual ? getHasNode(t, n) : getNode(t, n);
|
|
276
|
+
}
|
|
277
|
+
const i = t?.fam?.node?.T?.Re;
|
|
278
|
+
const r = txOf(e);
|
|
279
|
+
if (!i?.P || sameAction(i, r)) return false;
|
|
280
|
+
// The re-ask takes the target's guess whole: the slot is the lane's
|
|
281
|
+
// derivation; its other guessed slots show their truth in the lane's
|
|
282
|
+
// world (lanes `take`).
|
|
283
|
+
for (const n of nodesOf(t)) if (n?.l & CONFIG_GUESS && txOf(n) === r) take(n, i, n !== e);
|
|
284
|
+
return true;
|
|
285
|
+
};
|
|
286
|
+
|
|
260
287
|
/** Q-D (plan sec. 39): an OLDER question's truth landed beneath an arrangement
|
|
261
288
|
* guess (`laneWrite` held it — another action's landing is not this guess's
|
|
262
289
|
* answer). The guess is re-based over it: order from the guess, rows from
|
|
@@ -270,10 +297,10 @@ function arrangementEqual(e, n, t) {
|
|
|
270
297
|
* node is born for it as the lane's derivation), on `length` only when the
|
|
271
298
|
* committed length differs, and as the `LaneView`'s base for structural
|
|
272
299
|
* reads. Unkeyed families compose
|
|
273
|
-
* positionally — the guess stands as written (the documented residue). */ GlobalQueue.
|
|
300
|
+
* positionally — the guess stands as written (the documented residue). */ GlobalQueue.Nn = (e, n, t) => {
|
|
274
301
|
if (!t) return fold(e, n);
|
|
275
302
|
const i = e.O;
|
|
276
|
-
if (i === undefined || e.
|
|
303
|
+
if (i === undefined || e.Xe !== $TRACK) return;
|
|
277
304
|
const r = e.T.P;
|
|
278
305
|
if (!(r instanceof LaneView)) return;
|
|
279
306
|
if (!Array.isArray(n) || !Array.isArray(r.rows)) {
|
|
@@ -288,46 +315,46 @@ function arrangementEqual(e, n, t) {
|
|
|
288
315
|
const i = isWrappable(t) ? o(t) : undefined;
|
|
289
316
|
if (i !== undefined && !s.has(i)) s.set(i, t);
|
|
290
317
|
}
|
|
291
|
-
const
|
|
292
|
-
const
|
|
293
|
-
const
|
|
294
|
-
for (let e = 0; e <
|
|
295
|
-
const n =
|
|
318
|
+
const f = new Set;
|
|
319
|
+
const a = [];
|
|
320
|
+
const l = r.rows;
|
|
321
|
+
for (let e = 0; e < l.length; e++) {
|
|
322
|
+
const n = l[e];
|
|
296
323
|
const t = isWrappable(n) ? o(n) : undefined;
|
|
297
324
|
const i = t !== undefined ? s.get(t) : undefined;
|
|
298
325
|
if (i !== undefined) {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
} else
|
|
326
|
+
a.push(i);
|
|
327
|
+
f.add(t);
|
|
328
|
+
} else a.push(n);
|
|
302
329
|
}
|
|
303
|
-
const
|
|
330
|
+
const u = r.removed;
|
|
304
331
|
for (let e = 0; e < n.length; e++) {
|
|
305
332
|
const t = n[e];
|
|
306
333
|
const i = isWrappable(t) ? o(t) : undefined;
|
|
307
|
-
if (i !== undefined && !
|
|
334
|
+
if (i !== undefined && !f.has(i) && (u === null || !u.has(i))) a.push(t);
|
|
308
335
|
}
|
|
309
|
-
r.rows =
|
|
310
|
-
r.base =
|
|
336
|
+
r.rows = a;
|
|
337
|
+
r.base = a;
|
|
311
338
|
const c = txOf(e);
|
|
312
339
|
const d = committed(i);
|
|
313
340
|
const p = i.n;
|
|
314
|
-
for (let e = 0; e <
|
|
341
|
+
for (let e = 0; e < a.length; e++) {
|
|
315
342
|
const n = p?.[e];
|
|
316
343
|
// A slot the lane does not own shows the committed row: it becomes the
|
|
317
344
|
// lane's only where the composed row is another row (by key — the same
|
|
318
345
|
// key's new object is the same row, its target adopted it).
|
|
319
346
|
if (n === undefined) {
|
|
320
|
-
if (!sameRow(d[e],
|
|
321
|
-
} else if (!sameRow(n.l & CONFIG_OVERRIDE ? n.T.P : d[e],
|
|
347
|
+
if (!sameRow(d[e], a[e], o)) laneSet(getNode(i, e), a[e], c);
|
|
348
|
+
} else if (!sameRow(n.l & CONFIG_OVERRIDE ? n.T.P : d[e], a[e], o)) laneSet(n, a[e], c);
|
|
322
349
|
}
|
|
323
350
|
if (p !== null) {
|
|
324
|
-
for (let e =
|
|
351
|
+
for (let e = a.length; ;e++) {
|
|
325
352
|
const n = p[e];
|
|
326
353
|
if (n === undefined) break;
|
|
327
354
|
laneSet(n, undefined, c);
|
|
328
355
|
}
|
|
329
356
|
const e = p.length;
|
|
330
|
-
if (e !== undefined && (e.l & CONFIG_OVERRIDE || d.length !==
|
|
357
|
+
if (e !== undefined && (e.l & CONFIG_OVERRIDE || d.length !== a.length)) laneSet(e, a.length, c);
|
|
331
358
|
}
|
|
332
359
|
};
|
|
333
360
|
|
|
@@ -342,9 +369,9 @@ function arrangementEqual(e, n, t) {
|
|
|
342
369
|
const i = txOf(e);
|
|
343
370
|
// A guess the screen never showed is void at the correction (D-34); a
|
|
344
371
|
// keyed arrangement guess's view carries its removed-keys set.
|
|
345
|
-
if (!i.
|
|
372
|
+
if (!i.Ue || !(t?.l & CONFIG_OVERRIDE) || !t.T.P?.removed) return false;
|
|
346
373
|
const r = e.T.P;
|
|
347
|
-
if ((!e.
|
|
374
|
+
if ((!e.ye || !e.ye(r, n)) && !GlobalQueue.nn(r, n)) {
|
|
348
375
|
i.folded = foldedRead;
|
|
349
376
|
insertSubs(e);
|
|
350
377
|
} else GlobalQueue.sn?.(i);
|
|
@@ -365,8 +392,8 @@ function arrangementEqual(e, n, t) {
|
|
|
365
392
|
const t = txOf(n);
|
|
366
393
|
joinPassAt(e, resolveTx(t._parent ?? t));
|
|
367
394
|
}
|
|
368
|
-
if (n.
|
|
369
|
-
return n.l & CONFIG_SLOT_NODE ? GlobalQueue.
|
|
395
|
+
if (n.ue !== NOT_PENDING) return n.ue;
|
|
396
|
+
return n.l & CONFIG_SLOT_NODE ? GlobalQueue.an(n) : n.le;
|
|
370
397
|
}
|
|
371
398
|
|
|
372
399
|
function sameRow(e, n, t) {
|
|
@@ -391,7 +418,28 @@ function sameRow(e, n, t) {
|
|
|
391
418
|
}
|
|
392
419
|
}
|
|
393
420
|
|
|
421
|
+
/** D-34 for a per-key guess (#4329): the derive's draft wrote new objects
|
|
422
|
+
* over a target holding guessed rows (`d.length = 0; d.push(...rows)`, or
|
|
423
|
+
* `d.issues = rows`). The container on the way down to each guessed row
|
|
424
|
+
* reconciles the new object at its slot — in a keyed list, the one with
|
|
425
|
+
* the row's key — exactly as a returned landing would: rows match by key,
|
|
426
|
+
* a guessed row keeps its target, and its leaves are judged against their
|
|
427
|
+
* guesses. Rows nothing guessed are left as the draft wrote them. */ function pairRows(e, n) {
|
|
428
|
+
const t = e.fam.key;
|
|
429
|
+
for (let i of e.fam.overlaid ?? []) {
|
|
430
|
+
// The guessed row, or its ancestor directly under `t` (none: skip).
|
|
431
|
+
while (i.u !== e) if ((i = i.u) === null) break;
|
|
432
|
+
if (i === null) continue;
|
|
433
|
+
const r = t?.(i.v);
|
|
434
|
+
const o = Array.isArray(n) ? r !== undefined && n.find(e => isWrappable(e) && sameKey(t(e), r)) : n[i.pk];
|
|
435
|
+
// A new object only: not `c`'s own, nor one another row serves
|
|
436
|
+
// (pairing it would alias the two).
|
|
437
|
+
if (isWrappable(o) && !lookupTarget(o, e.fam)) reconcileState(o, i.px, t, true);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
394
441
|
installOptHooks({
|
|
442
|
+
pair: pairRows,
|
|
395
443
|
draft: optimisticDraft,
|
|
396
444
|
writes: notifyOptimisticWrites,
|
|
397
445
|
arrangement: arrangement,
|
|
@@ -399,9 +447,53 @@ installOptHooks({
|
|
|
399
447
|
view: (e, n, t = false) => t ? optimisticView(e, n, laneValueOf, true) : optimisticView(e, n),
|
|
400
448
|
has: optimisticHas,
|
|
401
449
|
descriptor: optimisticOwnDescriptor,
|
|
402
|
-
sweep: sweepOverlaid
|
|
450
|
+
sweep: sweepOverlaid,
|
|
451
|
+
// A new question (not a `refresh()`) asked over guesses an earlier frame
|
|
452
|
+
// opened, which answer the old one (D-34, #4336). Stamped on `fam.asked`
|
|
453
|
+
// with this flush's `clock`, so it lapses when the flush ends: `clock + 1`
|
|
454
|
+
// from mainline over a live guess — a frame still reading a guess at the
|
|
455
|
+
// seam shows it beside the new input, so the flush holds with the guess's
|
|
456
|
+
// action (`park`); `~clock` from a lane with no guess of its own, or with
|
|
457
|
+
// no live guess left — the lane waits for its answer (F-6), as for a
|
|
458
|
+
// guessed `createOptimistic` (lanes `laneStage`). The guess's own lane
|
|
459
|
+
// asks nothing new and stamps nothing.
|
|
460
|
+
ask: e => {
|
|
461
|
+
if (e.node.R & REACTIVE_REASK || !e.overlaid?.size) return;
|
|
462
|
+
// Stamped with the flush (`clock`): it lapses when the flush ends.
|
|
463
|
+
let n = ~clock;
|
|
464
|
+
for (const t of e.overlaid) {
|
|
465
|
+
const e = laneNodeOf(t);
|
|
466
|
+
if (e) {
|
|
467
|
+
if (passLane === null) n = clock + 1; else if (sameAction(txOf(e), passLane)) return;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
if ((e.asked = n) > 0) joinFuture(null);
|
|
471
|
+
},
|
|
472
|
+
// Over a new question the guesses do not answer (`asked`): from mainline
|
|
473
|
+
// only a target carrying a guess stands in — a read of one with none is an
|
|
474
|
+
// ordinary pending read (F-2), so a keyed store's other keys wait for their
|
|
475
|
+
// answer, not for the guess's action; in a lane with no guess of its own,
|
|
476
|
+
// or with no live guess left, none does (F-6).
|
|
477
|
+
stands: e => {
|
|
478
|
+
const n = e.fam.overlaid;
|
|
479
|
+
const t = e.fam.asked;
|
|
480
|
+
return !!n?.size && (t !== clock + 1 || passLane !== null || n.has(e)) && t !== ~clock;
|
|
481
|
+
},
|
|
482
|
+
// Mainline hold (`clock + 1`): the flush joins the action of each guess a
|
|
483
|
+
// reader still reads at the seam; a reader that moved off it (a keyed
|
|
484
|
+
// store's other key) holds nothing.
|
|
485
|
+
park: e => {
|
|
486
|
+
for (const n of overlaidFamilies) if (n.asked === clock + 1) for (const t of n.overlaid) {
|
|
487
|
+
const n = laneNodeOf(t, true);
|
|
488
|
+
if (n) merge(txOf(n)._parent, e);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
403
491
|
});
|
|
404
492
|
|
|
493
|
+
/** Two lanes of one action (their parents resolved through merges). */ function sameAction(e, n) {
|
|
494
|
+
return resolveTx(e._parent) === resolveTx(n._parent);
|
|
495
|
+
}
|
|
496
|
+
|
|
405
497
|
function shallowKeys(e) {
|
|
406
498
|
const n = {};
|
|
407
499
|
for (const t of Reflect.ownKeys(e)) if (t !== $OWNER) n[t] = unwrapValue(e[t]);
|
|
@@ -424,7 +516,7 @@ function sweepOverlaid() {
|
|
|
424
516
|
if (overlaidFamilies.size === 0) return;
|
|
425
517
|
for (const e of overlaidFamilies) {
|
|
426
518
|
const n = e.overlaid;
|
|
427
|
-
for (const e of n) if (!
|
|
519
|
+
for (const e of n) if (!laneNodeOf(e)) {
|
|
428
520
|
n.delete(e);
|
|
429
521
|
if (e.ch) rebaseChained(e);
|
|
430
522
|
// The container shows its backing again (a shown arrangement guess
|
|
@@ -447,7 +539,7 @@ function sweepOverlaid() {
|
|
|
447
539
|
if (i !== null) for (const e of Reflect.ownKeys(i)) {
|
|
448
540
|
const r = i[e];
|
|
449
541
|
const o = untrack(() => unwrapValue(n[e]));
|
|
450
|
-
if (r.
|
|
542
|
+
if (r.ye && r.ye(r.le, o)) continue;
|
|
451
543
|
r.le = o;
|
|
452
544
|
// (The lane's end notified it this epoch when the shown value and the
|
|
453
545
|
// covered one differed — its readers re-derive already.)
|
|
@@ -472,7 +564,7 @@ function sweepOverlaid() {
|
|
|
472
564
|
const o = e.k;
|
|
473
565
|
if (o !== null && o.o !== null && o.le instanceof LaneView && o.Me !== notifyEpoch) {
|
|
474
566
|
const i = Array.isArray(n) ? untrack(() => n.map(unwrapValue)) : n;
|
|
475
|
-
if (!arrangementEqual(o.le.rows, i, e.fam
|
|
567
|
+
if (!arrangementEqual(o.le.rows, i, e.fam)) {
|
|
476
568
|
insertSubs(o);
|
|
477
569
|
t = true;
|
|
478
570
|
}
|
|
@@ -480,14 +572,18 @@ function sweepOverlaid() {
|
|
|
480
572
|
if (t) schedule();
|
|
481
573
|
}
|
|
482
574
|
|
|
483
|
-
function
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
575
|
+
/** `t`'s nodes (a missing container or deep node: null). */ function nodesOf(e) {
|
|
576
|
+
const n = [ e.k, e.dk ];
|
|
577
|
+
for (const t of [ e.n, e.h ]) if (t !== null) for (const e of Reflect.ownKeys(t)) n.push(t[e]);
|
|
578
|
+
return n;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/** A node of `t` carrying a lane value, if any (`read`: one a reader's
|
|
582
|
+
* last pass read). */ function laneNodeOf(e, n) {
|
|
583
|
+
for (const t of nodesOf(e)) if (t?.l & CONFIG_OVERRIDE) {
|
|
584
|
+
if (!n) return t;
|
|
585
|
+
for (let e = t.o; e !== null; e = e.t) if (e.Ne === e.u.de) return t;
|
|
586
|
+
}
|
|
491
587
|
}
|
|
492
588
|
|
|
493
589
|
function overlaid(e) {
|
|
@@ -562,11 +658,11 @@ i = false) {
|
|
|
562
658
|
if (s !== null) {
|
|
563
659
|
for (const e of Reflect.ownKeys(s)) {
|
|
564
660
|
const o = s[e];
|
|
565
|
-
let
|
|
566
|
-
if (o.l & CONFIG_OVERRIDE)
|
|
567
|
-
const
|
|
568
|
-
const
|
|
569
|
-
if (!
|
|
661
|
+
let f;
|
|
662
|
+
if (o.l & CONFIG_OVERRIDE) f = t(o); else if (!i || (f = pendingGuessOf(o)) === NOT_PENDING) continue;
|
|
663
|
+
const a = !!f;
|
|
664
|
+
const l = r ?? n;
|
|
665
|
+
if (!a && e in l) delete ensure()[e];
|
|
570
666
|
}
|
|
571
667
|
}
|
|
572
668
|
return r ?? n;
|
|
@@ -579,7 +675,7 @@ function createOptimisticStore(e, n, t) {
|
|
|
579
675
|
// createProjectionInternal).
|
|
580
676
|
const o = i ? n || {} : e;
|
|
581
677
|
const s = r?.key === undefined ? "id" : r.key;
|
|
582
|
-
const
|
|
678
|
+
const f = {
|
|
583
679
|
map: new WeakMap,
|
|
584
680
|
node: null,
|
|
585
681
|
live: new Set,
|
|
@@ -587,9 +683,9 @@ function createOptimisticStore(e, n, t) {
|
|
|
587
683
|
opt: true,
|
|
588
684
|
key: typeof s === "function" ? s : s === null ? null : e => isWrappable(e) ? e[s] : undefined
|
|
589
685
|
};
|
|
590
|
-
const
|
|
591
|
-
if (
|
|
592
|
-
|
|
686
|
+
const a = wrap(o, null, null, f);
|
|
687
|
+
if (f.shallow) {
|
|
688
|
+
a[$TARGET].s = true;
|
|
593
689
|
markRawIngest(o);
|
|
594
690
|
}
|
|
595
691
|
if (i) {
|
|
@@ -599,13 +695,13 @@ function createOptimisticStore(e, n, t) {
|
|
|
599
695
|
loadingValue: undefined
|
|
600
696
|
};
|
|
601
697
|
const i = computed(() => {
|
|
602
|
-
if (!
|
|
603
|
-
runProjectionComputed(
|
|
698
|
+
if (!f.node) f.node = getOwner();
|
|
699
|
+
runProjectionComputed(a, n, s);
|
|
604
700
|
}, t);
|
|
605
701
|
i.l &= ~CONFIG_AUTO_DISPOSE;
|
|
606
|
-
|
|
702
|
+
f.node = i;
|
|
607
703
|
}
|
|
608
|
-
return [
|
|
704
|
+
return [ a, e => storeSetter(a, e) ];
|
|
609
705
|
}
|
|
610
706
|
|
|
611
707
|
export { createOptimisticStore, notifyOptimisticWrites, optimisticHas, optimisticOwnDescriptor, optimisticView, sweepOverlaid };
|