@abide/abide 0.103.0 → 0.105.0
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/CHANGELOG.md +29 -0
- package/bin/abide.ts +80 -173
- package/docs/REGISTRY.md +27 -27
- package/docs/RULEBOOK.md +68 -24
- package/docs/abide.md +31 -46
- package/package.json +1 -1
- package/src/compiler/Lowering.ts +15 -5
- package/src/compiler/Refusals.ts +57 -0
- package/src/compiler/TypeSession.ts +46 -89
- package/src/compiler/appLayout.ts +447 -0
- package/src/compiler/appMap.ts +21 -25
- package/src/compiler/checkApp.ts +61 -97
- package/src/compiler/checkedShadow.ts +12 -10
- package/src/compiler/classifyRead.ts +3 -6
- package/src/compiler/compileApp.ts +183 -478
- package/src/compiler/componentGraph.ts +2 -71
- package/src/compiler/declaredExports.ts +79 -60
- package/src/compiler/emitClient.ts +11 -13
- package/src/compiler/emitComponent.ts +21 -6
- package/src/compiler/emitSource.ts +20 -20
- package/src/compiler/handlersUnder.ts +46 -36
- package/src/compiler/hookCalls.ts +152 -0
- package/src/compiler/mountsOf.ts +31 -54
- package/src/compiler/projectShadow.ts +1 -1
- package/src/compiler/readSources.ts +27 -42
- package/src/compiler/readsIn.ts +5 -16
- package/src/compiler/resolverIn.ts +77 -0
- package/src/server/abideModules.ts +152 -146
- package/src/server/answerRequest.ts +18 -4
- package/src/server/answerSocket.ts +136 -76
- package/src/server/answerValue.ts +28 -15
- package/src/server/appTree.ts +59 -73
- package/src/server/claudeApi.ts +2 -5
- package/src/server/clientBundle.ts +198 -0
- package/src/server/coerceArgs.ts +1 -1
- package/src/server/commands.ts +93 -57
- package/src/server/createApp.ts +90 -16
- package/src/server/deferredBuilds.ts +175 -0
- package/src/server/devWorker.ts +107 -319
- package/src/server/faceOf.ts +120 -0
- package/src/server/fenceServer.ts +10 -18
- package/src/server/generatedSurfaces.ts +12 -53
- package/src/server/index.ts +3 -0
- package/src/server/placement.ts +167 -0
- package/src/server/remote.ts +14 -42
- package/src/server/render.ts +25 -17
- package/src/server/renderComponent.ts +9 -5
- package/src/server/requestScope.ts +10 -4
- package/src/server/responseRelay.ts +389 -0
- package/src/server/runCompiled.ts +9 -12
- package/src/server/runDesktop.ts +6 -9
- package/src/server/serveBuild.ts +26 -73
- package/src/server/serveDev.ts +19 -176
- package/src/server/streamEvent.ts +29 -0
- package/src/server/versionOf.ts +1 -2
- package/src/server/withAbideSources.ts +2 -1
- package/src/shared/HandlerRoute.ts +68 -0
- package/src/shared/REFUSAL_KEY.ts +5 -0
- package/src/shared/RESERVED_DIRECTORIES.ts +6 -0
- package/src/shared/answerOf.ts +105 -78
- package/src/shared/filledPath.ts +1 -9
- package/src/shared/framing.ts +127 -128
- package/src/shared/queryText.ts +15 -7
- package/src/shared/reactive/Cursor.ts +69 -124
- package/src/shared/reactive/Reactive.ts +296 -162
- package/src/shared/reactive/callLoad.ts +4 -18
- package/src/shared/reactive/index.ts +11 -8
- package/src/shared/reactive/pairReactive.ts +1 -1
- package/src/shared/reactive/scoped.ts +4 -3
- package/src/shared/reactive/share.ts +11 -1
- package/src/shared/routePattern.ts +0 -110
- package/src/shared/rpc.ts +17 -24
- package/src/shared/rpcRequest.ts +18 -47
- package/src/shared/takeEarlyCall.ts +12 -37
- package/src/shared/url.ts +1 -1
- package/src/ui/Level.ts +276 -0
- package/src/ui/List.ts +17 -17
- package/src/ui/Router.ts +20 -87
- package/src/ui/applyHead.ts +92 -79
- package/src/ui/index.ts +4 -2
- package/src/ui/reconcile.ts +4 -110
- package/src/ui/rows.ts +123 -2
- package/src/ui/wire.ts +12 -27
- package/src/compiler/hooksCalled.ts +0 -35
- package/src/server/clientBuildOptions.ts +0 -54
- package/src/server/refuseAddressCollision.ts +0 -37
- package/src/shared/reactive/chunksOfStream.ts +0 -57
- package/src/ui/MOUNTING_LEVEL.ts +0 -18
|
@@ -19,7 +19,7 @@ import { type Found, runSchema, type Schema } from '../Schema.ts'
|
|
|
19
19
|
import { UNEXPECTED } from '../UNEXPECTED.ts'
|
|
20
20
|
import { WORK } from '../WORK.ts'
|
|
21
21
|
import { CELL } from './CELL.ts'
|
|
22
|
-
import { Cursor, hasCursorBehind, keepPlaces
|
|
22
|
+
import { CAUGHT_UP, Cursor, hasCursorBehind, keepPlaces } from './Cursor.ts'
|
|
23
23
|
import { ENTRY_LIVES } from './ENTRY_LIVES.ts'
|
|
24
24
|
import { armTimer, type Expiry, expiryFor } from './Expiry.ts'
|
|
25
25
|
import { FOLLOWED } from './FOLLOWED.ts'
|
|
@@ -257,7 +257,7 @@ export type Reactive<
|
|
|
257
257
|
invalidate(): void
|
|
258
258
|
// biome-ignore lint/suspicious/noConfusingVoidType: `void` is the RETURN POSITION of an author's effect, and it is load-bearing. `undefined` there refuses `(v) => { read(v) }` — a block body returning nothing infers `void`, which is not assignable to `undefined` — so the rule's fix would reject the ordinary effect.
|
|
259
259
|
watch(effect: (value: Stored) => void | (() => void)): () => void
|
|
260
|
-
/**
|
|
260
|
+
/** What one run produced: the settled value once, or a stream's chunks to its close (2.5, 2.6). */
|
|
261
261
|
[Symbol.asyncIterator](): AsyncIterator<Produced>
|
|
262
262
|
then<Result>(
|
|
263
263
|
onSettled?: (value: Stored) => Result | PromiseLike<Result>,
|
|
@@ -459,7 +459,7 @@ type Stream = {
|
|
|
459
459
|
* Whether what is served is a run that closed.
|
|
460
460
|
*
|
|
461
461
|
* WHETHER WHAT IS SERVED IS A RUN THAT CLOSED, which is the only accumulation a deadline
|
|
462
|
-
* reaches (6.
|
|
462
|
+
* reaches (6.10). A run in flight has minted nothing, so `expiry.at` says nothing about it —
|
|
463
463
|
* without this the standing arm reads `at` as 0 and drops the value on its first read.
|
|
464
464
|
*/
|
|
465
465
|
closed: boolean
|
|
@@ -482,6 +482,17 @@ function newStream(source: Cell | null): Stream {
|
|
|
482
482
|
}
|
|
483
483
|
}
|
|
484
484
|
|
|
485
|
+
/**
|
|
486
|
+
* The stream `cell` produces itself, or `null`: it has none, or the one it has is forwarded (11.15).
|
|
487
|
+
*
|
|
488
|
+
* THE ONE DISCRIMINATOR between following and forwarding. An own stream's `adoption` is a write it
|
|
489
|
+
* follows (9.11), and a forwarding value's is the stream it forwards.
|
|
490
|
+
*/
|
|
491
|
+
function ownStream(cell: Cell): Stream | null {
|
|
492
|
+
const stream = cell.stream
|
|
493
|
+
return stream !== null && stream.source === null ? stream : null
|
|
494
|
+
}
|
|
495
|
+
|
|
485
496
|
/** Turns `cell` into a streaming producer, forwarding `source`'s stream when it has one. */
|
|
486
497
|
function becomeStream(cell: Cell, source: Cell | null): Stream {
|
|
487
498
|
const stream = newStream(source)
|
|
@@ -489,12 +500,13 @@ function becomeStream(cell: Cell, source: Cell | null): Stream {
|
|
|
489
500
|
cell.plain = false
|
|
490
501
|
cell.bareWrite = false
|
|
491
502
|
simpleShape(cell)
|
|
503
|
+
seat(cell)
|
|
492
504
|
cell.direct = false
|
|
493
505
|
return stream
|
|
494
506
|
}
|
|
495
507
|
|
|
496
508
|
/**
|
|
497
|
-
* Starts a closed run's clock: the close is a streaming producer's mint (6.
|
|
509
|
+
* Starts a closed run's clock: the close is a streaming producer's mint (6.10), as `produce` is
|
|
498
510
|
* every other producer's. A failed or superseded run never reaches here, so it starts no clock.
|
|
499
511
|
*/
|
|
500
512
|
function closeRun(cell: Cell, stream: Stream): void {
|
|
@@ -651,8 +663,8 @@ class Cell {
|
|
|
651
663
|
*/
|
|
652
664
|
declare schema: Schema<unknown> | null
|
|
653
665
|
/**
|
|
654
|
-
* A streaming producer's chunk buffer, for a cursor to walk (2.
|
|
655
|
-
* other value
|
|
666
|
+
* A streaming producer's chunk buffer, for a cursor to walk (2.6); `EMPTY_RING` on every
|
|
667
|
+
* other value.
|
|
656
668
|
*/
|
|
657
669
|
declare ring: unknown[]
|
|
658
670
|
/**
|
|
@@ -989,14 +1001,10 @@ function comparatorFor(
|
|
|
989
1001
|
/**
|
|
990
1002
|
* Recomputes `simple` and re-seats the callable on the matching prototype.
|
|
991
1003
|
*
|
|
992
|
-
* `simple` IN ONE PLACE
|
|
993
|
-
*
|
|
994
|
-
*
|
|
995
|
-
*
|
|
996
|
-
*
|
|
997
|
-
* THE CALLABLE IS RE-SEATED ONLY WHERE IT IS ON ONE OF THESE TWO. A value that is adopting or
|
|
998
|
-
* forwarding a stream carries a prototype of its own and keeps it; the field is still
|
|
999
|
-
* maintained, so the seat it lands on when the adoption drops is the right one.
|
|
1004
|
+
* `simple` IN ONE PLACE. A second copy of this conjunction is the drift that would let one of the
|
|
1005
|
+
* sites go on reading `true` after the field under it moved — and what the short write would then
|
|
1006
|
+
* skip is a cap, a ring or a declared `identity`, silently. The prototype that goes with it is
|
|
1007
|
+
* `seat`'s, taken where the transition that moved a field under it ends.
|
|
1000
1008
|
*/
|
|
1001
1009
|
function simpleShape(cell: Cell): void {
|
|
1002
1010
|
cell.simple =
|
|
@@ -1006,14 +1014,38 @@ function simpleShape(cell: Cell): void {
|
|
|
1006
1014
|
cell.cap === null &&
|
|
1007
1015
|
cell.store === null &&
|
|
1008
1016
|
cell.identityFn === null
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
/**
|
|
1020
|
+
* The prototype a value's state calls for: its own stream's writes (9.11), an adoption's (11.59),
|
|
1021
|
+
* the short write of a `simple` value, or the members alone.
|
|
1022
|
+
*/
|
|
1023
|
+
function seatOf(cell: Cell): object {
|
|
1024
|
+
if (ownStream(cell) !== null) return STREAM_PROTOTYPE
|
|
1025
|
+
if (cell.adoption !== null) return ADOPTING_PROTOTYPE
|
|
1026
|
+
return cell.simple ? SIMPLE_PROTOTYPE : MEMBER_PROTOTYPE
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
/**
|
|
1030
|
+
* Re-seats the callable on the prototype its state calls for, where that moved.
|
|
1031
|
+
*
|
|
1032
|
+
* THE ONE WRITER OF A VALUE'S PROTOTYPE after construction, so the seat is derived rather than
|
|
1033
|
+
* remembered by each transition that moves it. A seat this file did not make — `pairReactive`'s —
|
|
1034
|
+
* is its owner's, and left alone.
|
|
1035
|
+
*/
|
|
1036
|
+
function seat(cell: Cell): void {
|
|
1009
1037
|
const callable = cell.callable
|
|
1010
1038
|
if (callable === null) return
|
|
1011
|
-
const
|
|
1012
|
-
if (
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1039
|
+
const now = Object.getPrototypeOf(callable)
|
|
1040
|
+
if (
|
|
1041
|
+
now !== MEMBER_PROTOTYPE &&
|
|
1042
|
+
now !== SIMPLE_PROTOTYPE &&
|
|
1043
|
+
now !== ADOPTING_PROTOTYPE &&
|
|
1044
|
+
now !== STREAM_PROTOTYPE
|
|
1016
1045
|
)
|
|
1046
|
+
return
|
|
1047
|
+
const next = seatOf(cell)
|
|
1048
|
+
if (next !== now) Object.setPrototypeOf(callable as object, next)
|
|
1017
1049
|
}
|
|
1018
1050
|
|
|
1019
1051
|
/**
|
|
@@ -1496,19 +1528,8 @@ function produce(cell: Cell, produced: unknown): number {
|
|
|
1496
1528
|
// collapses was still accepted — it produced nothing because the value was already
|
|
1497
1529
|
// the one being written, not because it failed. Leaving the failure standing left
|
|
1498
1530
|
// `s.error()` reporting a load that a later write superseded.
|
|
1499
|
-
const wasServable = cell.servable
|
|
1500
1531
|
const settling = settleProbes(cell)
|
|
1501
|
-
cell
|
|
1502
|
-
setDirect(cell, cell.state === CLEAN)
|
|
1503
|
-
// THE VALUE EDGE MOVED TOO WHERE THERE WAS NOTHING TO SERVE, whatever the gate
|
|
1504
|
-
// says about the payload — the same split `refused` makes, and for the same
|
|
1505
|
-
// reason. A read taken while this was unservable THREW, so a body that reached
|
|
1506
|
-
// it aborted: it is `CLEAN`, holds nothing, and nothing downstream will ever
|
|
1507
|
-
// pull it. Left silent, an `invalidate` whose reload landed the value it already
|
|
1508
|
-
// held stranded every value built from it at `ready()` false for the life of the
|
|
1509
|
-
// page. Over a value still being served nothing a reader can see moved (5.1) and
|
|
1510
|
-
// this stays quiet, which is the arm 5.2 is about.
|
|
1511
|
-
if (!wasServable) cascade(cell)
|
|
1532
|
+
serveAgain(cell)
|
|
1512
1533
|
if (settling) probesMoved(cell)
|
|
1513
1534
|
return cell.ordinal
|
|
1514
1535
|
}
|
|
@@ -1519,9 +1540,7 @@ function produce(cell: Cell, produced: unknown): number {
|
|
|
1519
1540
|
// `ttl` must not pay.
|
|
1520
1541
|
const expiry = cell.expiry
|
|
1521
1542
|
const mintedAt = expiry === null ? 0 : Date.now()
|
|
1522
|
-
|
|
1523
|
-
// message, and not a JSON value either.
|
|
1524
|
-
if (produced !== undefined) cell.ordinal += 1
|
|
1543
|
+
cell.ordinal += 1
|
|
1525
1544
|
if (expiry !== null) {
|
|
1526
1545
|
expiry.at = mintedAt
|
|
1527
1546
|
// A production is what 6.7 released being replaced, so the value is no longer
|
|
@@ -1535,8 +1554,7 @@ function produce(cell: Cell, produced: unknown): number {
|
|
|
1535
1554
|
if (cap !== null && cell.body === null)
|
|
1536
1555
|
return capped(cell, cap, produced, moved)
|
|
1537
1556
|
serve(cell, produced)
|
|
1538
|
-
|
|
1539
|
-
if (moved) probesMoved(cell)
|
|
1557
|
+
land(cell, moved)
|
|
1540
1558
|
return cell.ordinal
|
|
1541
1559
|
}
|
|
1542
1560
|
|
|
@@ -1555,6 +1573,56 @@ function settleProbes(cell: Cell): boolean {
|
|
|
1555
1573
|
return moved
|
|
1556
1574
|
}
|
|
1557
1575
|
|
|
1576
|
+
// THE LOAD-STATE TRANSITIONS. `loading`, `servable` and `failure` are written by these and by the
|
|
1577
|
+
// value's construction, and nowhere else: `beginLoad`, `settleProbes` with `serve` or `landChunks`
|
|
1578
|
+
// and then `land`, `serveAgain`, `endLoad`, `refused`, `unserve`, `hold`/`release`/`dropHeld`,
|
|
1579
|
+
// `abortRun`, `supersede`, `landOpening` and `dropStanding`.
|
|
1580
|
+
// Each owns the probe move it makes, so a site that changes what a probe answers cannot forget to
|
|
1581
|
+
// say so. `loading` carries five meanings and they are named here rather than told apart: a load in
|
|
1582
|
+
// flight, an open stream run, a window holding a production (5.15), a body aborted on a value that
|
|
1583
|
+
// had not landed (2.13), and a keyed entry a window has not started (5.19).
|
|
1584
|
+
|
|
1585
|
+
/**
|
|
1586
|
+
* Tells both edges a production landed: the readers through `cascade`, the guards where
|
|
1587
|
+
* `settleProbes` said a probe moved.
|
|
1588
|
+
*
|
|
1589
|
+
* THE OTHER HALF OF `settleProbes`, which has to be read before the landing it describes.
|
|
1590
|
+
*/
|
|
1591
|
+
function land(cell: Cell, moved: boolean): void {
|
|
1592
|
+
cascade(cell)
|
|
1593
|
+
if (moved) probesMoved(cell)
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
/**
|
|
1597
|
+
* Serves what is held again, with no production; returns whether there had been nothing to serve.
|
|
1598
|
+
*
|
|
1599
|
+
* THE VALUE EDGE MOVES WHERE THERE WAS NOTHING TO SERVE, whatever the identity gate says about the
|
|
1600
|
+
* payload — the same split `refused` makes, and for the same reason. A read taken while this was
|
|
1601
|
+
* unservable THREW, so a body that reached it aborted: it is `CLEAN`, holds nothing, and nothing
|
|
1602
|
+
* downstream will ever pull it. Left silent, an `invalidate` whose reload landed the value it
|
|
1603
|
+
* already held stranded every value built from it at `ready()` false for the life of the page. Over
|
|
1604
|
+
* a value still being served nothing a reader can see moved (5.1) and this stays quiet, which is the
|
|
1605
|
+
* arm 5.2 is about.
|
|
1606
|
+
*/
|
|
1607
|
+
function serveAgain(cell: Cell): boolean {
|
|
1608
|
+
const was = cell.servable
|
|
1609
|
+
cell.servable = true
|
|
1610
|
+
setDirect(cell, cell.state === CLEAN)
|
|
1611
|
+
if (!was) cascade(cell)
|
|
1612
|
+
return !was
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
/**
|
|
1616
|
+
* Ends a load that landed nothing: a stream's close, a deferred entry a window dropped, a store's
|
|
1617
|
+
* miss with nothing to fall back on. `busy` moves where it was loading, or where `moved` says
|
|
1618
|
+
* another probe did.
|
|
1619
|
+
*/
|
|
1620
|
+
function endLoad(cell: Cell, moved: boolean): void {
|
|
1621
|
+
const was = cell.loading
|
|
1622
|
+
cell.loading = false
|
|
1623
|
+
if (was || moved) probesMoved(cell)
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1558
1626
|
/**
|
|
1559
1627
|
* Makes a production what readers see: stores it, arms its deadline, persists it.
|
|
1560
1628
|
*
|
|
@@ -1649,8 +1717,7 @@ function capped(
|
|
|
1649
1717
|
// collapses a RUN of changes and the first landing has nothing to collapse with.
|
|
1650
1718
|
if (wakes(cell, cap, produced)) {
|
|
1651
1719
|
serve(cell, produced)
|
|
1652
|
-
|
|
1653
|
-
if (moved) probesMoved(cell)
|
|
1720
|
+
land(cell, moved)
|
|
1654
1721
|
}
|
|
1655
1722
|
return cell.ordinal
|
|
1656
1723
|
}
|
|
@@ -1682,9 +1749,27 @@ function release(cell: Cell, cap: Cap): void {
|
|
|
1682
1749
|
cap.held = undefined
|
|
1683
1750
|
cell.loading = false
|
|
1684
1751
|
serve(cell, value)
|
|
1685
|
-
cascade(cell)
|
|
1686
1752
|
// The close is a `busy` edge (5.15) even though the value's readiness never moved.
|
|
1687
|
-
|
|
1753
|
+
land(cell, true)
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
/**
|
|
1757
|
+
* Discards the production a window is holding, where an adoption superseded it; returns whether
|
|
1758
|
+
* `busy` was the hold's.
|
|
1759
|
+
*
|
|
1760
|
+
* An adoption is a later write (11.61), and a later write replaces what a window holds — save that
|
|
1761
|
+
* these two do not reach the window: a stream is forwarded rather than produced (11.15), and a value
|
|
1762
|
+
* with nothing to serve leaves this one nothing (11.16). What the window minted last is then what is
|
|
1763
|
+
* served, which the identity gate compares against (5.9).
|
|
1764
|
+
*/
|
|
1765
|
+
function dropHeld(cell: Cell): boolean {
|
|
1766
|
+
const cap = cell.cap
|
|
1767
|
+
if (cap === null || !cap.holding || cell.stream !== null) return false
|
|
1768
|
+
cap.holding = false
|
|
1769
|
+
cap.held = undefined
|
|
1770
|
+
cap.minted = cell.value
|
|
1771
|
+
cell.loading = false
|
|
1772
|
+
return true
|
|
1688
1773
|
}
|
|
1689
1774
|
|
|
1690
1775
|
function releaseHeld(cell: Cell, cap: Cap): void {
|
|
@@ -1857,10 +1942,10 @@ function standWrite(cell: Cell, stream: Stream, value: unknown): number {
|
|
|
1857
1942
|
cell.value = value
|
|
1858
1943
|
stream.materializedAt = stream.version
|
|
1859
1944
|
stream.written = true
|
|
1945
|
+
// `busy` is the run's, which a write stands beside (3.7), so only `ready` and `error` move.
|
|
1860
1946
|
const moved = !cell.servable || cell.failure !== undefined
|
|
1861
1947
|
landChunks(cell)
|
|
1862
|
-
|
|
1863
|
-
if (moved) probesMoved(cell)
|
|
1948
|
+
land(cell, moved)
|
|
1864
1949
|
return cell.ordinal
|
|
1865
1950
|
}
|
|
1866
1951
|
|
|
@@ -1987,7 +2072,7 @@ function adopt(cell: Cell, inner: Cell): Error | undefined {
|
|
|
1987
2072
|
// 11.59: an adopting value's writes are the adopted value's, reached through a prototype of its
|
|
1988
2073
|
// own rather than a branch on every value's write path — see `acceptIntoStream` for what such a
|
|
1989
2074
|
// branch costs under V8 even where nothing takes it.
|
|
1990
|
-
|
|
2075
|
+
seat(cell)
|
|
1991
2076
|
if (!cell.loading && busyNow(inner) !== wasBusy) probesMoved(cell)
|
|
1992
2077
|
return undefined
|
|
1993
2078
|
}
|
|
@@ -2086,6 +2171,7 @@ function mirror(cell: Cell, inner: Cell): void {
|
|
|
2086
2171
|
if (cell.stream !== null) stopForwarding(cell)
|
|
2087
2172
|
if (!inner.servable) {
|
|
2088
2173
|
// 11.16: the newly adopted has nothing to serve, so neither has this.
|
|
2174
|
+
if (dropHeld(cell)) probesMoved(cell)
|
|
2089
2175
|
unserve(cell)
|
|
2090
2176
|
return
|
|
2091
2177
|
}
|
|
@@ -2116,20 +2202,16 @@ function mirror(cell: Cell, inner: Cell): void {
|
|
|
2116
2202
|
function dropAdoption(cell: Cell): void {
|
|
2117
2203
|
if (cell.adoption === null) return
|
|
2118
2204
|
unfollow(cell)
|
|
2119
|
-
const stream = cell.stream
|
|
2120
2205
|
// 9.11: AN OWN STREAM'S `adoption` IS A WRITE IT FOLLOWS, not a stream it forwards — the
|
|
2121
2206
|
// discriminator `adoptedCellOf` reads. Letting go of the write is all there is: the stream is
|
|
2122
2207
|
// its own, so is its prototype, and `follow` never touched `identityFn`. Stopping it as a
|
|
2123
2208
|
// forward nulled the stream a queued `wakeStreams` was about to read.
|
|
2124
|
-
if (
|
|
2125
|
-
if (stream !== null) stopForwarding(cell)
|
|
2209
|
+
if (ownStream(cell) !== null) return
|
|
2210
|
+
if (cell.stream !== null) stopForwarding(cell)
|
|
2126
2211
|
// 11.17 inherited the identity for the length of the adoption only.
|
|
2127
2212
|
cell.identityFn = cell.declaredIdentityFn
|
|
2128
2213
|
simpleShape(cell)
|
|
2129
|
-
|
|
2130
|
-
cell.callable as object,
|
|
2131
|
-
cell.simple ? SIMPLE_PROTOTYPE : MEMBER_PROTOTYPE,
|
|
2132
|
-
)
|
|
2214
|
+
seat(cell)
|
|
2133
2215
|
}
|
|
2134
2216
|
|
|
2135
2217
|
/**
|
|
@@ -2143,6 +2225,8 @@ function dropAdoption(cell: Cell): void {
|
|
|
2143
2225
|
function forwardStream(cell: Cell, inner: Cell, adopted: Stream): void {
|
|
2144
2226
|
let stream = cell.stream
|
|
2145
2227
|
if (stream === null) {
|
|
2228
|
+
// The `busy` the hold left is settled below, with the adopter's own load.
|
|
2229
|
+
dropHeld(cell)
|
|
2146
2230
|
stream = becomeStream(cell, inner)
|
|
2147
2231
|
stream.ordinalOffset = cell.ordinal - inner.ringBase
|
|
2148
2232
|
}
|
|
@@ -2168,8 +2252,7 @@ function forwardStream(cell: Cell, inner: Cell, adopted: Stream): void {
|
|
|
2168
2252
|
// on answering through the adoption (11.19) for as long as the stream is open.
|
|
2169
2253
|
const moved = settleProbes(cell)
|
|
2170
2254
|
landChunks(cell)
|
|
2171
|
-
|
|
2172
|
-
if (moved) probesMoved(cell)
|
|
2255
|
+
land(cell, moved)
|
|
2173
2256
|
}
|
|
2174
2257
|
|
|
2175
2258
|
function stopForwarding(cell: Cell): void {
|
|
@@ -2230,17 +2313,7 @@ function run(cell: Cell): void {
|
|
|
2230
2313
|
truncateProbes(reader)
|
|
2231
2314
|
cell.running = false
|
|
2232
2315
|
if (thrown instanceof NotLanded) {
|
|
2233
|
-
cell
|
|
2234
|
-
// 2.13: the mark a source's production makes is what finishes this run, and
|
|
2235
|
-
// `markReaders` queues it rather than leaving it for a read that may never come.
|
|
2236
|
-
cell.aborted = true
|
|
2237
|
-
// NOT EVERYTHING IT READS IS READY, so neither is this — 11.58, and the same
|
|
2238
|
-
// sentence 11.16 makes for a re-adoption. It stops serving rather than handing
|
|
2239
|
-
// back a figure it computed from a source that has since gone away, and that
|
|
2240
|
-
// is a move its readers have to hear even though the aborted run minted
|
|
2241
|
-
// nothing for a cascade to carry.
|
|
2242
|
-
if (cell.servable) unserve(cell)
|
|
2243
|
-
else probesMoved(cell)
|
|
2316
|
+
abortRun(cell)
|
|
2244
2317
|
return
|
|
2245
2318
|
}
|
|
2246
2319
|
refused(cell, thrown)
|
|
@@ -2321,6 +2394,23 @@ function run(cell: Cell): void {
|
|
|
2321
2394
|
absorb(cell, produced, true)
|
|
2322
2395
|
}
|
|
2323
2396
|
|
|
2397
|
+
/**
|
|
2398
|
+
* Leaves a run that read a value which had not landed owing the rest of itself (2.13).
|
|
2399
|
+
*
|
|
2400
|
+
* BUSY, because what it waits on is loading. The mark a source's production makes is what finishes
|
|
2401
|
+
* the run, and `markReaders` queues it rather than leaving it for a read that may never come. And
|
|
2402
|
+
* NOT EVERYTHING IT READS IS READY, so neither is this — 11.58, and the same sentence 11.16 makes
|
|
2403
|
+
* for a re-adoption. It stops serving rather than handing back a figure it computed from a source
|
|
2404
|
+
* that has since gone away, and that is a move its readers have to hear even though the aborted run
|
|
2405
|
+
* minted nothing for a cascade to carry.
|
|
2406
|
+
*/
|
|
2407
|
+
function abortRun(cell: Cell): void {
|
|
2408
|
+
cell.loading = true
|
|
2409
|
+
cell.aborted = true
|
|
2410
|
+
if (cell.servable) unserve(cell)
|
|
2411
|
+
else probesMoved(cell)
|
|
2412
|
+
}
|
|
2413
|
+
|
|
2324
2414
|
/**
|
|
2325
2415
|
* Adopts what a body handed back, refusing the body where that would close a cycle.
|
|
2326
2416
|
*
|
|
@@ -2336,7 +2426,7 @@ function adoptAnswer(cell: Cell, produced: unknown): void {
|
|
|
2336
2426
|
*
|
|
2337
2427
|
* 4.16: AN OPENING `undefined` IS LOADED AND IS NOT A PRODUCTION THROUGH THE PIPELINE. No `schema`
|
|
2338
2428
|
* judges it, no `transform` shapes it, no window holds it and no `store` writes it — it is the value
|
|
2339
|
-
* being empty, and the first real production is what those are for. It mints no ordinal
|
|
2429
|
+
* being empty, and the first real production is what those are for. It mints no ordinal.
|
|
2340
2430
|
*/
|
|
2341
2431
|
function landOpening(cell: Cell): void {
|
|
2342
2432
|
const moved = settleProbes(cell)
|
|
@@ -2344,8 +2434,7 @@ function landOpening(cell: Cell): void {
|
|
|
2344
2434
|
cell.landed = true
|
|
2345
2435
|
cell.servable = true
|
|
2346
2436
|
setDirect(cell, cell.state === CLEAN)
|
|
2347
|
-
|
|
2348
|
-
if (moved) probesMoved(cell)
|
|
2437
|
+
land(cell, moved)
|
|
2349
2438
|
}
|
|
2350
2439
|
|
|
2351
2440
|
/**
|
|
@@ -2357,11 +2446,23 @@ function landOpening(cell: Cell): void {
|
|
|
2357
2446
|
* be marked by (14.13).
|
|
2358
2447
|
*/
|
|
2359
2448
|
function startProducer(cell: Cell): void {
|
|
2360
|
-
const stream = cell
|
|
2361
|
-
if (stream === null
|
|
2449
|
+
const stream = ownStream(cell)
|
|
2450
|
+
if (stream === null) run(cell)
|
|
2362
2451
|
else startStream(cell, stream)
|
|
2363
2452
|
}
|
|
2364
2453
|
|
|
2454
|
+
/**
|
|
2455
|
+
* Supersedes the work in flight: a load's answer lands nowhere once `generation` has moved, and a
|
|
2456
|
+
* stream's own run is stopped outright. `busy` moves silently, and telling the guards is the
|
|
2457
|
+
* caller's — 7.3 has an invalidate tell nobody.
|
|
2458
|
+
*/
|
|
2459
|
+
function supersede(cell: Cell): void {
|
|
2460
|
+
cell.generation += 1
|
|
2461
|
+
cell.loading = false
|
|
2462
|
+
const stream = ownStream(cell)
|
|
2463
|
+
if (stream !== null) stopStream(stream)
|
|
2464
|
+
}
|
|
2465
|
+
|
|
2365
2466
|
/**
|
|
2366
2467
|
* Supersedes the run in flight and tells its iterator to return.
|
|
2367
2468
|
*
|
|
@@ -2395,10 +2496,7 @@ function startStream(cell: Cell, stream: Stream): void {
|
|
|
2395
2496
|
*/
|
|
2396
2497
|
function promoteToStream(cell: Cell, generator: AsyncIterable<unknown>): void {
|
|
2397
2498
|
let stream = cell.stream
|
|
2398
|
-
if (stream === null)
|
|
2399
|
-
stream = becomeStream(cell, null)
|
|
2400
|
-
Object.setPrototypeOf(cell.callable as object, STREAM_PROTOTYPE)
|
|
2401
|
-
}
|
|
2499
|
+
if (stream === null) stream = becomeStream(cell, null)
|
|
2402
2500
|
pumpRun(cell, stream, generator[Symbol.asyncIterator]())
|
|
2403
2501
|
}
|
|
2404
2502
|
|
|
@@ -2484,7 +2582,6 @@ async function pump(
|
|
|
2484
2582
|
cap.holding = false
|
|
2485
2583
|
releaseChunks(cell, stream)
|
|
2486
2584
|
}
|
|
2487
|
-
const moved = !begun || cell.loading
|
|
2488
2585
|
if (!begun) {
|
|
2489
2586
|
// A stream that closed with nothing in it has finished, and what it accumulated is
|
|
2490
2587
|
// no chunks — a value, where waiting on would be a load that never ends.
|
|
@@ -2492,10 +2589,9 @@ async function pump(
|
|
|
2492
2589
|
landChunks(cell)
|
|
2493
2590
|
cascade(cell)
|
|
2494
2591
|
}
|
|
2495
|
-
cell.loading = false
|
|
2496
2592
|
// 3.7: `busy` held until the close, and this is the close.
|
|
2497
|
-
|
|
2498
|
-
// 6.
|
|
2593
|
+
endLoad(cell, !begun)
|
|
2594
|
+
// 6.10, AFTER THE CASCADE ABOVE: the entry is what a read would answer with, so it is taken
|
|
2499
2595
|
// once the last chunk has landed and the value is servable.
|
|
2500
2596
|
closeRun(cell, stream)
|
|
2501
2597
|
// 8.9: a stream is written once, at the close, with the accumulation and never a partial.
|
|
@@ -2631,7 +2727,7 @@ function materialize(cell: Cell, stream: Stream): void {
|
|
|
2631
2727
|
// 9.11: the accumulation moved past a write following a `Reactive`, which lets go of it here
|
|
2632
2728
|
// where no chunk's wake did — a patch, or a run that closed empty. Only an own stream follows;
|
|
2633
2729
|
// a forwarding one's `adoption` is what it forwards.
|
|
2634
|
-
if (cell.adoption !== null &&
|
|
2730
|
+
if (cell.adoption !== null && ownStream(cell) !== null) unfollow(cell)
|
|
2635
2731
|
stream.materializedAt = stream.version
|
|
2636
2732
|
stream.written = false
|
|
2637
2733
|
gateInto(cell, stream.chunks.slice(0, stream.visible))
|
|
@@ -2681,6 +2777,97 @@ function heldValue(cell: Cell): unknown {
|
|
|
2681
2777
|
return cell.value
|
|
2682
2778
|
}
|
|
2683
2779
|
|
|
2780
|
+
/**
|
|
2781
|
+
* The chunks of the run `cell` is serving, from its first to its close (2.6).
|
|
2782
|
+
*
|
|
2783
|
+
* ONE RUN, AND THE READER OWNS ITS BOUNDARY. The run is its ring: a new run's first chunk replaces
|
|
2784
|
+
* the array, where a patch mutates it in place (9.13) and only moves the base — so a ring that moved
|
|
2785
|
+
* ends the walk (9.16), save the `EMPTY_RING` a run with no chunk yet holds. And what the run failed
|
|
2786
|
+
* on is thrown after its chunks (9.15), unless it was standing before the walk began — a
|
|
2787
|
+
* revalidation's (2.4), not this run's. The cursor is the wake and the settling is the end
|
|
2788
|
+
* (`Cursor.closeOn`).
|
|
2789
|
+
*
|
|
2790
|
+
* `gated` IS THE WIRE'S, and the two never share a take. Ungated is the ring by ordinal, every chunk
|
|
2791
|
+
* a window collapsed included (5.10) — `for await`. Gated is what a read would serve, chunk by chunk
|
|
2792
|
+
* (16.32): the accumulation to what the window released (5.18), or the gated accumulation (9.8).
|
|
2793
|
+
*/
|
|
2794
|
+
async function* runChunks(cell: Cell, gated: boolean): AsyncGenerator<unknown> {
|
|
2795
|
+
let ring = cell.ring
|
|
2796
|
+
const standing = failureOf(cell)
|
|
2797
|
+
// Gated reads by index and holds no place, so it sits past every chunk where no patch keeps it.
|
|
2798
|
+
const cursor = new Cursor(
|
|
2799
|
+
cell,
|
|
2800
|
+
gated ? Number.POSITIVE_INFINITY : cell.ringBase,
|
|
2801
|
+
)
|
|
2802
|
+
cursor.closeOn(settled(cell))
|
|
2803
|
+
let sent = 0
|
|
2804
|
+
try {
|
|
2805
|
+
for (;;) {
|
|
2806
|
+
if (cell.ring !== ring) {
|
|
2807
|
+
if (ring !== EMPTY_RING) return
|
|
2808
|
+
ring = cell.ring
|
|
2809
|
+
}
|
|
2810
|
+
const chunk = gated ? toldAt(cell, sent) : cursor.take()
|
|
2811
|
+
if (chunk !== CAUGHT_UP) {
|
|
2812
|
+
sent += 1
|
|
2813
|
+
yield chunk
|
|
2814
|
+
continue
|
|
2815
|
+
}
|
|
2816
|
+
if (cursor.closed) break
|
|
2817
|
+
await cursor.turn()
|
|
2818
|
+
}
|
|
2819
|
+
} finally {
|
|
2820
|
+
cursor.stop()
|
|
2821
|
+
}
|
|
2822
|
+
if (cursor.failure !== undefined) throw cursor.failure
|
|
2823
|
+
// 9.15 AND 16.59 — a run that failed after its first chunk, or one its timeout ended, settles
|
|
2824
|
+
// with what it had; the refusal stands beside it.
|
|
2825
|
+
const ended = failureOf(cell)
|
|
2826
|
+
if (ended !== undefined && ended !== standing) throw ended
|
|
2827
|
+
}
|
|
2828
|
+
|
|
2829
|
+
/**
|
|
2830
|
+
* The chunk at `index` of what a read of `cell` would serve, or `CAUGHT_UP`.
|
|
2831
|
+
*
|
|
2832
|
+
* Ungated it is read out of the accumulation in place, to `visible`: a read materializes a copy of
|
|
2833
|
+
* the whole of it (9.1), which for a writer woken per chunk is n²/2 elements copied to send n. A
|
|
2834
|
+
* schema or a transform has to see the whole accumulation (9.8), so a gated value answers from what
|
|
2835
|
+
* a read would.
|
|
2836
|
+
*/
|
|
2837
|
+
function toldAt(cell: Cell, index: number): unknown {
|
|
2838
|
+
const stream = cell.stream
|
|
2839
|
+
// A forward that ended (11.16) is no stream to send any more of.
|
|
2840
|
+
if (stream === null) return CAUGHT_UP
|
|
2841
|
+
if (cell.schema === null && cell.transform === null)
|
|
2842
|
+
return index < stream.visible ? stream.chunks[index] : CAUGHT_UP
|
|
2843
|
+
const held = MEMBERS.peek.call(cell.callable as unknown as Callable)
|
|
2844
|
+
return Array.isArray(held) && index < held.length ? held[index] : CAUGHT_UP
|
|
2845
|
+
}
|
|
2846
|
+
|
|
2847
|
+
/**
|
|
2848
|
+
* What one run of `cell` produced, as `for await` walks it.
|
|
2849
|
+
*
|
|
2850
|
+
* 2.5 AND 2.6 — the settling, yielded once, or a stream's chunks from the first to the close. Which
|
|
2851
|
+
* of the two is asked of the settling, since a value may only turn out to stream once its load
|
|
2852
|
+
* resolves (9.6).
|
|
2853
|
+
*/
|
|
2854
|
+
async function* producedRun(cell: Cell): AsyncGenerator<unknown> {
|
|
2855
|
+
const first = await settled(cell, true)
|
|
2856
|
+
if (first !== STREAMING) {
|
|
2857
|
+
yield first
|
|
2858
|
+
return
|
|
2859
|
+
}
|
|
2860
|
+
yield* runChunks(cell, false)
|
|
2861
|
+
}
|
|
2862
|
+
|
|
2863
|
+
/**
|
|
2864
|
+
* The chunks of the run `value` is serving, as a streamed answer sends them (16.32), ending with
|
|
2865
|
+
* that run (9.16) and throwing what it failed on (9.15).
|
|
2866
|
+
*/
|
|
2867
|
+
export function chunksOfStream(value: unknown): AsyncGenerator<unknown> {
|
|
2868
|
+
return runChunks((value as Callable)[CELL], true)
|
|
2869
|
+
}
|
|
2870
|
+
|
|
2684
2871
|
/**
|
|
2685
2872
|
* Releases the standing production at its deadline, waking nobody.
|
|
2686
2873
|
*
|
|
@@ -2773,7 +2960,7 @@ function beginLoad(cell: Cell): void {
|
|
|
2773
2960
|
*
|
|
2774
2961
|
* AND WHAT IS SERVED WAS MINTED, which every producer but a streaming one answers yes to the moment
|
|
2775
2962
|
* it is servable. A stream serves the run it is building (9.1), and that run has minted nothing
|
|
2776
|
-
* until it closes (6.
|
|
2963
|
+
* until it closes (6.10) — so a deadline has nothing to measure from and must not drop it.
|
|
2777
2964
|
*/
|
|
2778
2965
|
function standingLive(cell: Cell, expiry: Expiry): boolean {
|
|
2779
2966
|
if (!reloads(cell) || expiry.dropped || !cell.servable) return false
|
|
@@ -2835,8 +3022,7 @@ function expire(cell: Cell): void {
|
|
|
2835
3022
|
* which is what lets the flag be conservative.
|
|
2836
3023
|
*/
|
|
2837
3024
|
function readIndirect(cell: Cell): unknown {
|
|
2838
|
-
|
|
2839
|
-
if (cell.state !== CLEAN) resolve(cell)
|
|
3025
|
+
bringCurrent(cell)
|
|
2840
3026
|
// 6.5: THE READ THAT FOLLOWS. Every value carrying an expiry arrives here and no
|
|
2841
3027
|
// other value does, which is the whole of what `setDirect` buys.
|
|
2842
3028
|
if (cell.expiry !== null) expire(cell)
|
|
@@ -2991,12 +3177,14 @@ function isReady(cell: Cell): boolean {
|
|
|
2991
3177
|
}
|
|
2992
3178
|
|
|
2993
3179
|
/**
|
|
2994
|
-
*
|
|
3180
|
+
* Settles what an invalidate left owing and runs the body where it is marked: what a read, a probe,
|
|
3181
|
+
* a `peek` and an await each pull before they answer. Where they part is the deadline — a read and
|
|
3182
|
+
* a `peek` take 6.5's half, an await only a drop the timer made (16.7) — and each says so after.
|
|
2995
3183
|
*
|
|
2996
3184
|
* 3.2 — A PROBE ANSWERS ABOUT THE VALUE A READ WOULD SERVE. Under push-pull a write leaves every
|
|
2997
3185
|
* derived value it reached unrun, so a probe that walked what the last run left answered about a
|
|
2998
3186
|
* value nothing would serve: `x.ready()` true over a body whose inputs had moved to a load, and the
|
|
2999
|
-
* read the guard admitted threw `NotLanded`.
|
|
3187
|
+
* read the guard admitted threw `NotLanded`.
|
|
3000
3188
|
*/
|
|
3001
3189
|
function bringCurrent(cell: Cell): void {
|
|
3002
3190
|
if (cell.owes !== OWES_NOTHING) settleOwed(cell)
|
|
@@ -3036,8 +3224,7 @@ function settled(cell: Cell, untilStreaming = false): Promise<unknown> {
|
|
|
3036
3224
|
// ONLY ONCE THE TIMER HAS DROPPED IT. The read's half of 6.5 — a production still served past
|
|
3037
3225
|
// its deadline — is not taken here, because 16.7's `ttl` of 0 makes every mutation's production
|
|
3038
3226
|
// past its deadline the moment it lands, and the await that answers the call ran it again.
|
|
3039
|
-
|
|
3040
|
-
if (cell.state !== CLEAN) resolve(cell)
|
|
3227
|
+
bringCurrent(cell)
|
|
3041
3228
|
if (cell.expiry?.dropped) expire(cell)
|
|
3042
3229
|
if (untilStreaming && cell.stream !== null)
|
|
3043
3230
|
return Promise.resolve(STREAMING)
|
|
@@ -3288,12 +3475,9 @@ function invalidateOne(cell: Cell): void {
|
|
|
3288
3475
|
if (!reloads(cell)) return
|
|
3289
3476
|
// Not directly servable, so the next read goes a frame in and settles the debt.
|
|
3290
3477
|
cell.direct = false
|
|
3291
|
-
// 7.15: work already in flight was started from what this says is wrong.
|
|
3292
|
-
//
|
|
3293
|
-
cell
|
|
3294
|
-
cell.loading = false
|
|
3295
|
-
const stream = cell.stream
|
|
3296
|
-
if (stream !== null && stream.source === null) stopStream(stream)
|
|
3478
|
+
// 7.15: work already in flight was started from what this says is wrong — and 7.3 moves no
|
|
3479
|
+
// probe for it.
|
|
3480
|
+
supersede(cell)
|
|
3297
3481
|
cell.owes = OWES_RELOAD
|
|
3298
3482
|
owedBelow(cell)
|
|
3299
3483
|
}
|
|
@@ -3409,10 +3593,7 @@ export function startDeferred(value: unknown): void {
|
|
|
3409
3593
|
* and a reader still holding it hears that.
|
|
3410
3594
|
*/
|
|
3411
3595
|
export function abandonDeferred(value: unknown): void {
|
|
3412
|
-
|
|
3413
|
-
if (!cell.loading) return
|
|
3414
|
-
cell.loading = false
|
|
3415
|
-
probesMoved(cell)
|
|
3596
|
+
endLoad((value as Callable)[CELL], false)
|
|
3416
3597
|
}
|
|
3417
3598
|
|
|
3418
3599
|
// ── `store` ──────────────────────────────────────────────────────────────────────────────
|
|
@@ -3465,7 +3646,7 @@ function restoreFirst(
|
|
|
3465
3646
|
settleRestore(cell, persisted, answer, initial)
|
|
3466
3647
|
return
|
|
3467
3648
|
}
|
|
3468
|
-
cell
|
|
3649
|
+
beginLoad(cell)
|
|
3469
3650
|
const generation = cell.generation
|
|
3470
3651
|
answer.then(
|
|
3471
3652
|
(value) => {
|
|
@@ -3498,10 +3679,7 @@ function settleRestore(
|
|
|
3498
3679
|
if (cell.body !== null) startProducer(cell)
|
|
3499
3680
|
else if (initial === undefined) landOpening(cell)
|
|
3500
3681
|
else if (initial !== NO_INITIAL) open(cell, initial)
|
|
3501
|
-
else
|
|
3502
|
-
cell.loading = false
|
|
3503
|
-
probesMoved(cell)
|
|
3504
|
-
}
|
|
3682
|
+
else endLoad(cell, false)
|
|
3505
3683
|
}
|
|
3506
3684
|
|
|
3507
3685
|
/**
|
|
@@ -3538,8 +3716,7 @@ function restoreStream(cell: Cell, stream: Stream, chunks: unknown[]): void {
|
|
|
3538
3716
|
stream.version += 1
|
|
3539
3717
|
const moved = settleProbes(cell)
|
|
3540
3718
|
landChunks(cell)
|
|
3541
|
-
|
|
3542
|
-
if (moved) probesMoved(cell)
|
|
3719
|
+
land(cell, moved)
|
|
3543
3720
|
// 8.7 SAYS THE BODY NEVER STARTS, AND `pump` IS WHAT REACHES `closeRun` — so the
|
|
3544
3721
|
// restored accumulation is entered as a closed run here or nothing ever does it.
|
|
3545
3722
|
// Without this `standingLive` answers false for the life of the value, which takes
|
|
@@ -3618,13 +3795,7 @@ function settleMiss(cell: Cell): void {
|
|
|
3618
3795
|
)
|
|
3619
3796
|
return
|
|
3620
3797
|
}
|
|
3621
|
-
|
|
3622
|
-
const wasLoading = cell.loading
|
|
3623
|
-
cell.servable = true
|
|
3624
|
-
cell.loading = false
|
|
3625
|
-
setDirect(cell, cell.state === CLEAN)
|
|
3626
|
-
if (cell.servable !== wasServable) cascade(cell)
|
|
3627
|
-
if (wasLoading || cell.servable !== wasServable) probesMoved(cell)
|
|
3798
|
+
endLoad(cell, serveAgain(cell))
|
|
3628
3799
|
}
|
|
3629
3800
|
|
|
3630
3801
|
/**
|
|
@@ -4034,20 +4205,7 @@ const MEMBERS = {
|
|
|
4034
4205
|
return watchCell(this[CELL], effect)
|
|
4035
4206
|
},
|
|
4036
4207
|
[Symbol.asyncIterator](this: Callable): AsyncIterator<unknown> {
|
|
4037
|
-
|
|
4038
|
-
// 2.5: "the production in flight, from its start". Starting one ordinal back is
|
|
4039
|
-
// what includes it rather than skipping to whatever comes next — and clamped at
|
|
4040
|
-
// zero, where a value nothing has produced into must WAIT rather than hand over
|
|
4041
|
-
// the `undefined` it is holding.
|
|
4042
|
-
// A STREAM'S PRODUCTION IN FLIGHT IS THE STREAM, so its start is the run's first
|
|
4043
|
-
// chunk rather than the latest one.
|
|
4044
|
-
const from =
|
|
4045
|
-
cell.stream !== null
|
|
4046
|
-
? cell.ringBase
|
|
4047
|
-
: cell.ordinal > 0
|
|
4048
|
-
? cell.ordinal - 1
|
|
4049
|
-
: 0
|
|
4050
|
-
return new Cursor(cell, from)
|
|
4208
|
+
return producedRun(this[CELL])
|
|
4051
4209
|
},
|
|
4052
4210
|
// biome-ignore lint/suspicious/noThenProperty: RULEBOOK 1.4 — a `Reactive` MUST be thenable, which is what this rule warns about. Banning it buys a discrimination rather than a semantics, and 16.4's in-process `Rpc` arm is what that discrimination would have cost. 1.6 is the guard that makes thenability safe — the brand is read before `then`.
|
|
4053
4211
|
then(
|
|
@@ -4069,12 +4227,13 @@ const MEMBERS = {
|
|
|
4069
4227
|
}
|
|
4070
4228
|
|
|
4071
4229
|
/**
|
|
4072
|
-
* The cell `value` serves from, through every adoption
|
|
4230
|
+
* The cell `value` serves from, through every adoption: its identity and its ordinal, and nothing
|
|
4231
|
+
* else of it the server can reach.
|
|
4073
4232
|
*
|
|
4074
4233
|
* 11.12: an adopting value serves the adopted value's production, and an adoption of an adoption
|
|
4075
4234
|
* goes on down — so a follow's version (18.7) and its feed name the cell that actually produced.
|
|
4076
4235
|
*/
|
|
4077
|
-
export function servedCellOf(value: unknown):
|
|
4236
|
+
export function servedCellOf(value: unknown): { readonly ordinal: number } {
|
|
4078
4237
|
return adoptedCellOf(value)
|
|
4079
4238
|
}
|
|
4080
4239
|
|
|
@@ -4098,10 +4257,16 @@ export function deadlineOf(value: unknown): number {
|
|
|
4098
4257
|
* 16.48 — WHICH LOAD A VALUE HAS IN FLIGHT, as the generation that started it, or `undefined` where
|
|
4099
4258
|
* none is. Read off the cell rather than through `busy`, which is a probe and would subscribe the
|
|
4100
4259
|
* caller that asked (3.3).
|
|
4260
|
+
*
|
|
4261
|
+
* A WINDOW HOLDING A PRODUCTION IS BUSY AND IS NO LOAD (5.15): nothing is in flight for a call to end
|
|
4262
|
+
* or time, and the window's close is its own bound. Told apart by the hold, which only a value with
|
|
4263
|
+
* neither body nor stream makes — so a write's load taken in under a hold is not one a call times.
|
|
4101
4264
|
*/
|
|
4102
4265
|
export function loadOf(value: unknown): number | undefined {
|
|
4103
4266
|
const cell = (value as Callable)[CELL]
|
|
4104
|
-
|
|
4267
|
+
if (!cell.loading) return undefined
|
|
4268
|
+
if (cell.cap?.holding && cell.stream === null) return undefined
|
|
4269
|
+
return cell.generation
|
|
4105
4270
|
}
|
|
4106
4271
|
|
|
4107
4272
|
/**
|
|
@@ -4138,8 +4303,7 @@ export function failedTransiently(value: unknown): boolean {
|
|
|
4138
4303
|
export function abandonLoad(value: unknown, failure: unknown): void {
|
|
4139
4304
|
const cell = (value as Callable)[CELL]
|
|
4140
4305
|
if (!cell.loading) return
|
|
4141
|
-
cell
|
|
4142
|
-
if (cell.stream !== null) stopStream(cell.stream)
|
|
4306
|
+
supersede(cell)
|
|
4143
4307
|
refused(cell, failure)
|
|
4144
4308
|
}
|
|
4145
4309
|
|
|
@@ -4166,33 +4330,10 @@ export function isStreaming(value: unknown): boolean {
|
|
|
4166
4330
|
return stream !== null && stream !== undefined
|
|
4167
4331
|
}
|
|
4168
4332
|
|
|
4169
|
-
/**
|
|
4170
|
-
* The chunks a streaming value has told its readers of, from index `from` on.
|
|
4171
|
-
*
|
|
4172
|
-
* 16.32 — THE CHUNKS A STREAMING VALUE HAS TOLD ITS READERS OF PAST `from`, for a writer sending each
|
|
4173
|
-
* once. Ungated they are read out of the accumulation in place, to `visible` rather than its length
|
|
4174
|
-
* (5.18): a read materializes a copy of the whole of it (9.1), which for a writer woken per chunk is
|
|
4175
|
-
* n²/2 elements copied to send n. A schema or a transform has to see the whole accumulation (9.8),
|
|
4176
|
-
* so a gated value answers from what a read would.
|
|
4177
|
-
*/
|
|
4178
|
-
export function* chunksFrom(value: unknown, from: number): Generator<unknown> {
|
|
4179
|
-
const cell = (value as Callable)[CELL]
|
|
4180
|
-
if (cell.schema === null && cell.transform === null) {
|
|
4181
|
-
const stream = cell.stream as Stream
|
|
4182
|
-
for (let index = from; index < stream.visible; index += 1)
|
|
4183
|
-
yield stream.chunks[index]
|
|
4184
|
-
return
|
|
4185
|
-
}
|
|
4186
|
-
const held = MEMBERS.peek.call(value as Callable)
|
|
4187
|
-
if (Array.isArray(held))
|
|
4188
|
-
for (let index = from; index < held.length; index += 1)
|
|
4189
|
-
yield held[index]
|
|
4190
|
-
}
|
|
4191
|
-
|
|
4192
4333
|
function adoptedCellOf(value: unknown): Cell {
|
|
4193
4334
|
let cell = (value as Callable)[CELL]
|
|
4194
4335
|
// A stream's own `adoption` is a write it follows (9.11), and its past is its own.
|
|
4195
|
-
while (cell.adoption !== null && cell
|
|
4336
|
+
while (cell.adoption !== null && ownStream(cell) === null)
|
|
4196
4337
|
cell = cell.adoption.source
|
|
4197
4338
|
return cell
|
|
4198
4339
|
}
|
|
@@ -4347,8 +4488,7 @@ const SIMPLE_PROTOTYPE = brandedPrototype({
|
|
|
4347
4488
|
return undefined
|
|
4348
4489
|
}
|
|
4349
4490
|
cell.value = value
|
|
4350
|
-
|
|
4351
|
-
if (value !== undefined) cell.ordinal += 1
|
|
4491
|
+
cell.ordinal += 1
|
|
4352
4492
|
// `setDirect`, with `plain` known true by `simple`.
|
|
4353
4493
|
cell.direct = cell.state === CLEAN
|
|
4354
4494
|
if (cell.readers.length !== 0) markReaders(cell, DIRTY)
|
|
@@ -4386,7 +4526,8 @@ function orphan(cell: Cell): void {
|
|
|
4386
4526
|
function releaseOrphan(cell: Cell): void {
|
|
4387
4527
|
cell.orphaned = false
|
|
4388
4528
|
const stream = cell.stream
|
|
4389
|
-
|
|
4529
|
+
const own = ownStream(cell)
|
|
4530
|
+
if (own !== null) stopStream(own)
|
|
4390
4531
|
dropAdoption(cell)
|
|
4391
4532
|
cell.aborted = false
|
|
4392
4533
|
if (cell.body !== null && stream === null) {
|
|
@@ -4466,14 +4607,7 @@ export function createReactive<
|
|
|
4466
4607
|
// BEFORE THE FIELD, not after: an engine keys its inline caches on the shape a
|
|
4467
4608
|
// property was added to, and re-pointing the prototype afterwards invalidates the
|
|
4468
4609
|
// transition the store just built.
|
|
4469
|
-
Object.setPrototypeOf(
|
|
4470
|
-
self,
|
|
4471
|
-
streaming
|
|
4472
|
-
? STREAM_PROTOTYPE
|
|
4473
|
-
: cell.simple
|
|
4474
|
-
? SIMPLE_PROTOTYPE
|
|
4475
|
-
: MEMBER_PROTOTYPE,
|
|
4476
|
-
)
|
|
4610
|
+
Object.setPrototypeOf(self, seatOf(cell))
|
|
4477
4611
|
self[CELL] = cell
|
|
4478
4612
|
cell.callable = self as unknown as Reactive<unknown>
|
|
4479
4613
|
if (cell.tags !== null) tagCell(cell)
|