uneventful 0.0.7 → 0.0.8

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/signals.mjs CHANGED
@@ -1,6 +1,28 @@
1
- import { N as swapCtx, O as nullCtx, P as ruleQueue, c as backpressure, Q as defaultQ, I as IsStream, q as current, R as currentRule, S as makeCtx, T as ruleStops, d as defer, D as makeJob, j as isError, h as markHandled, e as detached, g as getJob, w as reject, b as resolve, U as freeCtx, o as callOrWait } from './call-or-wait-DHkBd_bM.mjs';
2
- import { apply, setMap, CallableObject } from './utils.mjs';
1
+ import { M as swapCtx, N as nullCtx, c as backpressure, I as IsStream, p as current, O as makeCtx, B as makeJob, h as isError, f as markHandled, d as detached, g as getJob, v as reject, b as resolve, P as freeCtx, l as callOrWait } from './call-or-wait-COAmx32w.mjs';
2
+ import { b as batch, a as arrayEq, d as defer, c as apply, s as setMap, C as CallableObject } from './utils-P0JEpWXG.mjs';
3
3
 
4
+ const ruleQueues = /* @__PURE__ */ new WeakMap();
5
+ function ruleQueue(scheduleFn = defer) {
6
+ ruleQueues.has(scheduleFn) || ruleQueues.set(scheduleFn, batch(runRules$1, scheduleFn));
7
+ return ruleQueues.get(scheduleFn);
8
+ }
9
+ var currentRule;
10
+ const ruleStops = /* @__PURE__ */ new WeakMap();
11
+ const defaultQ = /* @__PURE__ */ ruleQueue(defer);
12
+ var currentQueue;
13
+ function runRules$1(q) {
14
+ if (currentQueue)
15
+ return;
16
+ currentQueue = this;
17
+ try {
18
+ for (currentRule of q) {
19
+ currentRule.catchUp();
20
+ q.delete(currentRule);
21
+ }
22
+ } finally {
23
+ currentQueue = currentRule = void 0;
24
+ }
25
+ }
4
26
  class WriteConflict extends Error {
5
27
  }
6
28
  class CircularDependency extends Error {
@@ -8,7 +30,11 @@ class CircularDependency extends Error {
8
30
  var timestamp = 1;
9
31
  const fntrackers = /* @__PURE__ */ new WeakMap();
10
32
  const obtrackers = /* @__PURE__ */ new WeakMap();
11
- const streamtrackers = /* @__PURE__ */ new WeakMap();
33
+ const monitors = /* @__PURE__ */ new WeakMap();
34
+ const demandChanges = batch((q) => {
35
+ for (const cell of q)
36
+ cell.updateDemand();
37
+ });
12
38
  const dirtyStack = [];
13
39
  function markDependentsDirty(cell) {
14
40
  const latestSource = cell.latestSource = timestamp;
@@ -58,9 +84,17 @@ function mksub(source, target) {
58
84
  target.sources.nS = sub;
59
85
  target.sources = sub;
60
86
  source.adding = sub;
61
- if (target.subscribers || target.queue)
87
+ if (target.flags & 1 /* Observed */)
62
88
  source.subscribe(sub);
63
89
  }
90
+ function removeConstListener(sub) {
91
+ const { tgt, nS, pS } = sub;
92
+ if (sub.src.adding === sub)
93
+ sub.src.adding = sub.old;
94
+ delsub(sub);
95
+ if (tgt.sources === sub)
96
+ (tgt.sources = nS || pS) || tgt.becomeConstant();
97
+ }
64
98
  function delsub(sub) {
65
99
  sub.src.unsubscribe(sub);
66
100
  if (sub.nS)
@@ -71,25 +105,29 @@ function delsub(sub) {
71
105
  sub.old = freesubs;
72
106
  freesubs = sub;
73
107
  }
74
- function subscribeAll(s) {
75
- if (s)
76
- while (s.pS)
77
- s = s.pS;
78
- else
79
- return;
80
- for (; s; s = s.nS)
108
+ function subscribeAll(c) {
109
+ for (let s = firstSource(c); s; s = s.nS)
81
110
  s.src.subscribe(s);
111
+ toggleDemand(c);
82
112
  }
83
- function unsubscribeAll(s) {
113
+ function unsubscribeAll(c) {
114
+ for (let s = firstSource(c); s; s = s.nS)
115
+ s.src.unsubscribe(s);
116
+ toggleDemand(c);
117
+ }
118
+ const sentinel = {};
119
+ function firstSource(c) {
120
+ let s = c.sources;
84
121
  if (s)
85
122
  while (s.pS)
86
123
  s = s.pS;
87
- else
88
- return;
89
- for (; s; s = s.nS)
90
- s.src.unsubscribe(s);
124
+ return s;
125
+ }
126
+ function toggleDemand(c) {
127
+ if (((c.flags ^= 1 /* Observed */) & 64 /* Stateful */) === 64 /* Stateful */) {
128
+ demandChanges.has(c) ? demandChanges.delete(c) : demandChanges.add(c);
129
+ }
91
130
  }
92
- const sentinel = {};
93
131
  class Cell {
94
132
  constructor() {
95
133
  this.value = void 0;
@@ -111,7 +149,7 @@ class Cell {
111
149
  this.queue = void 0;
112
150
  /**
113
151
  * The computation to be performed (if {@link Is.Compute}) or the
114
- * setup/teardown for {@link Is.Stream}.
152
+ * setup/teardown for {@link Is.Stateful}.
115
153
  */
116
154
  this.compute = returnValue;
117
155
  }
@@ -133,7 +171,6 @@ class Cell {
133
171
  getValue() {
134
172
  if (arguments.length)
135
173
  return apply(this.stream, this, arguments);
136
- this.catchUp();
137
174
  const dep = current.cell;
138
175
  if (dep && this.flags & 132 /* Variable */) {
139
176
  if (this.flags & 32 /* Running */)
@@ -141,6 +178,7 @@ class Cell {
141
178
  let s = this.adding;
142
179
  if (!s || s.tgt !== dep) {
143
180
  mksub(this, dep);
181
+ s = this.adding;
144
182
  } else {
145
183
  if (s.ts === -1) {
146
184
  s.ts = this.lastChanged;
@@ -155,7 +193,11 @@ class Cell {
155
193
  }
156
194
  }
157
195
  }
158
- }
196
+ this.catchUp();
197
+ if (this.adding === s)
198
+ s.ts = this.lastChanged;
199
+ } else
200
+ this.catchUp();
159
201
  if (this.flags & 16 /* Error */)
160
202
  throw this.value;
161
203
  return this.value;
@@ -232,7 +274,10 @@ class Cell {
232
274
  return this.doRecalc();
233
275
  }
234
276
  doRecalc() {
235
- const oldCtx = swapCtx(this.ctx);
277
+ const { ctx } = this, oldCtx = swapCtx(ctx);
278
+ if (this.flags & 64 /* Stateful */) {
279
+ ctx.job?.restart();
280
+ }
236
281
  for (let sub = this.sources; sub; sub = sub.nS) {
237
282
  sub.ts = -1;
238
283
  sub.old = sub.src.adding;
@@ -257,6 +302,15 @@ class Cell {
257
302
  }
258
303
  } finally {
259
304
  this.flags &= ~32 /* Running */;
305
+ if (this.flags & 64 /* Stateful */) {
306
+ demandChanges.delete(this);
307
+ if (this.flags & (16 /* Error */ | 2 /* Stopped */)) {
308
+ this.flags &= ~2 /* Stopped */;
309
+ ctx.job?.restart();
310
+ } else if (this.flags & 1 /* Observed */) ; else {
311
+ ctx.job?.restart();
312
+ }
313
+ }
260
314
  swapCtx(oldCtx);
261
315
  let head;
262
316
  for (let sub = this.sources; sub; ) {
@@ -269,34 +323,50 @@ class Cell {
269
323
  head = sub;
270
324
  sub = pS;
271
325
  }
272
- this.sources = head;
273
- if (!head) {
274
- this.flags &= ~4 /* Compute */;
275
- }
326
+ (this.sources = head) || this.becomeConstant();
327
+ }
328
+ }
329
+ becomeConstant() {
330
+ if (this.flags & (32 /* Running */ | 64 /* Stateful */))
331
+ return;
332
+ this.flags &= ~4 /* Compute */;
333
+ if (this.flags & 132 /* Variable */)
334
+ return;
335
+ while (this.adding)
336
+ removeConstListener(this.adding);
337
+ for (let sub = this.subscribers; sub; ) {
338
+ const { nT } = sub;
339
+ sub.ts !== this.lastChanged || removeConstListener(sub);
340
+ sub = nT;
276
341
  }
277
342
  }
278
343
  stop() {
279
344
  this.setQ(null);
345
+ if (this.flags & 32 /* Running */) {
346
+ this.flags |= 2 /* Stopped */;
347
+ } else
348
+ this.updateDemand();
280
349
  ruleStops.get(this)?.();
281
350
  }
282
351
  setQ(queue = defaultQ) {
283
- queue || this.subscribers || unsubscribeAll(this.sources);
352
+ if (queue == this.queue)
353
+ return;
354
+ if (!this.subscribers) {
355
+ queue || !this.queue || unsubscribeAll(this);
356
+ }
284
357
  if (this.queue) {
285
358
  if (this.queue.has(this))
286
359
  queue?.add(this);
287
360
  this.queue.delete(this);
288
- queue || this.ctx.job?.restart();
289
361
  } else if (queue) {
290
362
  queue.add(this);
291
- this.subscribers || subscribeAll(this.sources);
363
+ this.subscribers || subscribeAll(this);
292
364
  }
293
365
  this.queue = queue;
294
366
  }
295
367
  subscribe(sub) {
296
- if (!this.subscribers) {
297
- this.queue || subscribeAll(this.sources);
298
- if ((this.flags & 320 /* Demand */) === 64 /* Stream */)
299
- this.updateDemand();
368
+ if (!this.subscribers && !this.queue) {
369
+ subscribeAll(this);
300
370
  }
301
371
  if (this.subscribers !== sub && !sub.pT) {
302
372
  sub.nT = this.subscribers;
@@ -313,10 +383,8 @@ class Cell {
313
383
  if (this.subscribers === sub)
314
384
  this.subscribers = sub.nT;
315
385
  sub.nT = sub.pT = void 0;
316
- if (!this.subscribers) {
317
- this.queue || unsubscribeAll(this.sources);
318
- if ((this.flags & 320 /* Demand */) === 64 /* Stream */)
319
- this.updateDemand();
386
+ if (!this.subscribers && !this.queue) {
387
+ unsubscribeAll(this);
320
388
  }
321
389
  }
322
390
  static mkValue(val) {
@@ -326,22 +394,32 @@ class Cell {
326
394
  cell.lastChanged = timestamp;
327
395
  return cell;
328
396
  }
397
+ isObserved() {
398
+ return !!((this.flags |= 64 /* Stateful */) & 1 /* Observed */);
399
+ }
400
+ getJob() {
401
+ this.flags |= 64 /* Stateful */;
402
+ return this.ctx.job ||= makeJob();
403
+ }
329
404
  updateDemand() {
330
- this.flags |= 256 /* Demanded */;
331
- defer(streamtrackers.get(this));
405
+ demandChanges.delete(this);
406
+ if (monitors.has(this)) {
407
+ monitors.get(this)();
408
+ } else if (this.flags & 1 /* Observed */) {
409
+ this.shouldWrite(true);
410
+ } else {
411
+ this.ctx.job?.restart();
412
+ }
332
413
  }
333
414
  static mkStream(src, val) {
334
415
  const cell = this.mkValue(val);
335
- cell.flags |= 64 /* Stream */;
416
+ cell.flags |= 64 /* Stateful */;
336
417
  const ctx = makeCtx();
337
418
  const write = (v) => {
338
419
  cell.setValue(v, false);
339
420
  };
340
421
  let job;
341
- streamtrackers.set(cell, () => {
342
- if (!(cell.flags & 256 /* Demanded */))
343
- return;
344
- cell.flags &= ~256 /* Demanded */;
422
+ monitors.set(cell, () => {
345
423
  if (!cell.subscribers) {
346
424
  write(val);
347
425
  job?.end();
@@ -388,23 +466,30 @@ class Cell {
388
466
  return cell;
389
467
  }
390
468
  static mkRule(fn, q) {
391
- const cell = new Cell(), outer = getJob(), job = makeJob(), stop = cell.stop.bind(cell);
392
- outer === detached || ruleStops.set(cell, outer.release(stop));
393
- cell.compute = () => {
469
+ const outer = getJob(), cell = Cell.mkCached(() => {
394
470
  try {
395
- job.restart().must(fn(stop));
471
+ const cleanup = fn();
472
+ if (cleanup)
473
+ (cell.ctx.job || cell.getJob()).must(cleanup);
396
474
  cell.lastChanged = timestamp;
397
475
  } catch (e) {
398
- stop();
476
+ cell.stop();
399
477
  throw e;
400
478
  }
401
- };
402
- cell.ctx = makeCtx(job, cell);
403
- cell.flags = 4 /* Compute */;
479
+ }), stop = cell.stop.bind(cell);
480
+ outer === detached || ruleStops.set(cell, outer.release(stop));
404
481
  cell.setQ(q);
405
482
  return stop;
406
483
  }
407
484
  }
485
+ function unchangedIf(newVal, equals = arrayEq) {
486
+ const { cell } = current;
487
+ if (cell) {
488
+ return cell.flags & 16 /* Error */ || !equals(cell.value, newVal) ? newVal : cell.value;
489
+ } else {
490
+ throw new Error("unchangedIf() must be called from a reactive expression");
491
+ }
492
+ }
408
493
 
409
494
  class RF extends CallableObject {
410
495
  constructor(q) {
@@ -477,15 +562,15 @@ class SignalImpl extends CallableObject {
477
562
  *"uneventful.next"() {
478
563
  return yield (r) => {
479
564
  let seen = false, res;
480
- rule((stop) => {
565
+ rule(() => {
481
566
  try {
482
567
  res = this();
483
568
  } catch (e) {
484
- stop();
569
+ rule.stop();
485
570
  defer(reject.bind(null, r, e));
486
571
  }
487
572
  if (seen) {
488
- stop();
573
+ rule.stop();
489
574
  defer(resolve.bind(null, r, res));
490
575
  }
491
576
  seen = true;
@@ -503,15 +588,15 @@ class SignalImpl extends CallableObject {
503
588
  }
504
589
  if (res)
505
590
  return resolve(r, res);
506
- rule((stop) => {
591
+ rule(() => {
507
592
  try {
508
593
  res = this();
509
594
  } catch (e) {
510
- stop();
595
+ rule.stop();
511
596
  defer(reject.bind(null, r, e));
512
597
  }
513
598
  if (res) {
514
- stop();
599
+ rule.stop();
515
600
  defer(resolve.bind(null, r, res));
516
601
  }
517
602
  });
@@ -586,5 +671,5 @@ function waitTruthy(job, v) {
586
671
  v && job.return(v);
587
672
  }
588
673
 
589
- export { CircularDependency, ConfigurableImpl, SignalImpl, WritableImpl, WriteConflict, action, cached, peek, rule, runRules, until, value };
674
+ export { CircularDependency, ConfigurableImpl, SignalImpl, WritableImpl, WriteConflict, action, cached, peek, rule, runRules, unchangedIf, until, value };
590
675
  //# sourceMappingURL=signals.mjs.map