tuple->object

async-another-try
Simon Holthausen 4 days ago
parent bd0faecdaa
commit 408d51b362
No known key found for this signature in database

@ -155,17 +155,16 @@ export class Batch {
/**
* The current values of any signals that are updated in this batch.
* Tuple format: [value, is_derived, write_version] (note: is_derived is false for deriveds, too, if they were overridden via assignment)
* `is_derived` is false for deriveds, too, if they were overridden via assignment.
* They keys of this map are identical to `this.previous`
* @type {Map<Value, [any, boolean, number]>}
* @type {Map<Value, { v: any, wv: number, is_derived: boolean }>}
*/
current = new Map();
/**
* The values and write versions of any signals (sources and deriveds) that are updated in this batch _before_ those updates took place.
* Tuple format: [value, write_version]
* They keys of this map are identical to `this.current`
* @type {Map<Value, [any, number]>}
* @type {Map<Value, { v: any, wv: number }>}
*/
previous = new Map();
@ -679,7 +678,10 @@ export class Batch {
#merge(batch) {
for (const [source, value] of batch.current) {
if (!this.previous.has(source) && batch.previous.has(source)) {
this.previous.set(source, /** @type {[any, number]} */ (batch.previous.get(source)));
this.previous.set(
source,
/** @type {{ v: any, wv: number }} */ (batch.previous.get(source))
);
}
this.current.set(source, value);
@ -759,14 +761,14 @@ export class Batch {
*/
capture(source, value, is_derived = false) {
if (source.v !== UNINITIALIZED && !this.previous.has(source)) {
this.previous.set(source, [source.v, source.wv]);
this.previous.set(source, { v: source.v, wv: source.wv });
}
const wv = increment_write_version();
// Don't save errors in `batch_values`, or they won't be thrown in `runtime.js#get`
if ((source.f & ERROR_VALUE) === 0) {
this.current.set(source, [value, is_derived, wv]);
this.current.set(source, { v: value, wv, is_derived });
batch_values?.set(source, value);
wv_values?.set(source, wv);
}
@ -798,8 +800,7 @@ export class Batch {
/** @type {Derived} */ (source).deps?.some(
(d) =>
/** @type {Batch} */ (batch).current.has(d) ||
(this.current.has(d) &&
/** @type {[any, boolean, number]} */ (this.current.get(d))[0] !== d.v)
(this.current.has(d) && /** @type {{ v: any }} */ (this.current.get(d)).v !== d.v)
))
) {
is_latest_value = false;
@ -834,17 +835,17 @@ export class Batch {
const current = batch.current.get(source);
batch.current.delete(source);
if (![...batch.current.values()].some((v) => !v[1])) {
if (![...batch.current.values()].some((value) => !value.is_derived)) {
// The real world has overtaken every write of this fork, so it is obsolete. Discard it
// right away (its speculative branches must not be adopted by anyone), and empty
// `current` so that `commit()` can tell this apart from a user-initiated discard
batch.current.clear();
batch.discard();
} else {
if (current && current[0] !== value) batch.current.set(source, current);
if (current && current.v !== value) batch.current.set(source, current);
if (
!is_derived &&
(!current || current[0] !== value) &&
(!current || current.v !== value) &&
((source.f & ASYNC) === 0 ||
!depends_on(
/** @type {Effect} */ (/** @type {Source} */ (source).e),
@ -1044,9 +1045,9 @@ export class Batch {
held_sources = new Map();
stale_sources = new Map();
for (const [source, [value, _, wv]] of this.current) {
batch_values.set(source, value);
wv_values.set(source, wv);
for (const [source, current] of this.current) {
batch_values.set(source, current.v);
wv_values.set(source, current.wv);
}
for (let batch = first_batch; batch !== null; batch = batch.next) {
@ -1067,10 +1068,10 @@ export class Batch {
}
if (batch.id > this.id || include_earlier || this.is_eager) {
for (const [source, [value, wv]] of batch.previous) {
for (const [source, previous] of batch.previous) {
if (!batch_values.has(source)) {
batch_values.set(source, value);
wv_values.set(source, wv);
batch_values.set(source, previous.v);
wv_values.set(source, previous.wv);
}
}
}
@ -1548,21 +1549,21 @@ export function fork(fn) {
// in `batch.current` at this point is the latest value: sources that the real world has
// written to in the meantime were removed from the fork via `notify_fork` (an async
// source only survives if its effect depends on inputs that only the fork changed).
// We use fresh versions rather than the fork-time `content[2]`, because the real world
// We use fresh versions rather than the fork-time `content.wv`, because the real world
// may have run reactions since then whose versions would otherwise outrank them.
for (var [source, content] of batch.current) {
var changed = source.v !== content[0];
source.v = content[0];
var changed = source.v !== content.v;
source.v = content.v;
if (!content[1]) {
content[2] = source.wv = increment_write_version();
if (!content.is_derived) {
content.wv = source.wv = increment_write_version();
// dirty those effects the fork did not see yet, e.g. because a later batch created new branches
batch.mark(source, MAYBE_DIRTY, true);
} else if (changed) {
// A derived that was evaluated inside the fork: bump its version too, so that reactions
// which read the (then still old) real value _after_ the fork evaluated it — and which are
// therefore not in `stale_effects` — see a newer dependency version and re-run.
content[2] = source.wv = increment_write_version();
content.wv = source.wv = increment_write_version();
}
}
@ -1600,10 +1601,10 @@ export function fork(fn) {
// Other forks might need to rerun now with the updated state.
let next_batch = batch.next;
while (next_batch) {
for (const [source, [value, is_derived]] of batch.current) {
for (const [source, current] of batch.current) {
if (next_batch.current.has(source)) {
batch.notify_fork(next_batch, source, is_derived, value);
} else if (!is_derived) {
batch.notify_fork(next_batch, source, current.is_derived, current.v);
} else if (!current.is_derived) {
next_batch.queue_revalidation(source);
}
}

Loading…
Cancel
Save