@abide/abide 0.104.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 +16 -0
- package/bin/abide.ts +80 -173
- package/docs/REGISTRY.md +17 -17
- package/docs/RULEBOOK.md +50 -12
- package/docs/abide.md +9 -9
- package/package.json +1 -1
- package/src/compiler/Lowering.ts +15 -5
- package/src/compiler/Refusals.ts +57 -0
- package/src/compiler/TypeSession.ts +45 -86
- package/src/compiler/appLayout.ts +447 -0
- package/src/compiler/appMap.ts +21 -20
- package/src/compiler/checkApp.ts +61 -97
- package/src/compiler/checkedShadow.ts +11 -9
- package/src/compiler/classifyRead.ts +3 -6
- package/src/compiler/compileApp.ts +180 -512
- 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/readSources.ts +27 -42
- package/src/compiler/readsIn.ts +5 -16
- package/src/compiler/resolverIn.ts +77 -0
- package/src/server/abideModules.ts +92 -123
- 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 +49 -71
- 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/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/withAbideSources.ts +2 -1
- package/src/shared/HandlerRoute.ts +68 -0
- package/src/shared/REFUSAL_KEY.ts +5 -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 +4 -2
- package/src/shared/reactive/Reactive.ts +285 -197
- 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 -123
- 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 -33
- package/src/ui/MOUNTING_LEVEL.ts +0 -18
|
@@ -19,13 +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 {
|
|
23
|
-
CAUGHT_UP,
|
|
24
|
-
Cursor,
|
|
25
|
-
hasCursorBehind,
|
|
26
|
-
keepPlaces,
|
|
27
|
-
type Retained,
|
|
28
|
-
} from './Cursor.ts'
|
|
22
|
+
import { CAUGHT_UP, Cursor, hasCursorBehind, keepPlaces } from './Cursor.ts'
|
|
29
23
|
import { ENTRY_LIVES } from './ENTRY_LIVES.ts'
|
|
30
24
|
import { armTimer, type Expiry, expiryFor } from './Expiry.ts'
|
|
31
25
|
import { FOLLOWED } from './FOLLOWED.ts'
|
|
@@ -488,6 +482,17 @@ function newStream(source: Cell | null): Stream {
|
|
|
488
482
|
}
|
|
489
483
|
}
|
|
490
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
|
+
|
|
491
496
|
/** Turns `cell` into a streaming producer, forwarding `source`'s stream when it has one. */
|
|
492
497
|
function becomeStream(cell: Cell, source: Cell | null): Stream {
|
|
493
498
|
const stream = newStream(source)
|
|
@@ -495,6 +500,7 @@ function becomeStream(cell: Cell, source: Cell | null): Stream {
|
|
|
495
500
|
cell.plain = false
|
|
496
501
|
cell.bareWrite = false
|
|
497
502
|
simpleShape(cell)
|
|
503
|
+
seat(cell)
|
|
498
504
|
cell.direct = false
|
|
499
505
|
return stream
|
|
500
506
|
}
|
|
@@ -995,14 +1001,10 @@ function comparatorFor(
|
|
|
995
1001
|
/**
|
|
996
1002
|
* Recomputes `simple` and re-seats the callable on the matching prototype.
|
|
997
1003
|
*
|
|
998
|
-
* `simple` IN ONE PLACE
|
|
999
|
-
*
|
|
1000
|
-
*
|
|
1001
|
-
*
|
|
1002
|
-
*
|
|
1003
|
-
* THE CALLABLE IS RE-SEATED ONLY WHERE IT IS ON ONE OF THESE TWO. A value that is adopting or
|
|
1004
|
-
* forwarding a stream carries a prototype of its own and keeps it; the field is still
|
|
1005
|
-
* 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.
|
|
1006
1008
|
*/
|
|
1007
1009
|
function simpleShape(cell: Cell): void {
|
|
1008
1010
|
cell.simple =
|
|
@@ -1012,14 +1014,38 @@ function simpleShape(cell: Cell): void {
|
|
|
1012
1014
|
cell.cap === null &&
|
|
1013
1015
|
cell.store === null &&
|
|
1014
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 {
|
|
1015
1037
|
const callable = cell.callable
|
|
1016
1038
|
if (callable === null) return
|
|
1017
|
-
const
|
|
1018
|
-
if (
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1039
|
+
const now = Object.getPrototypeOf(callable)
|
|
1040
|
+
if (
|
|
1041
|
+
now !== MEMBER_PROTOTYPE &&
|
|
1042
|
+
now !== SIMPLE_PROTOTYPE &&
|
|
1043
|
+
now !== ADOPTING_PROTOTYPE &&
|
|
1044
|
+
now !== STREAM_PROTOTYPE
|
|
1022
1045
|
)
|
|
1046
|
+
return
|
|
1047
|
+
const next = seatOf(cell)
|
|
1048
|
+
if (next !== now) Object.setPrototypeOf(callable as object, next)
|
|
1023
1049
|
}
|
|
1024
1050
|
|
|
1025
1051
|
/**
|
|
@@ -1502,19 +1528,8 @@ function produce(cell: Cell, produced: unknown): number {
|
|
|
1502
1528
|
// collapses was still accepted — it produced nothing because the value was already
|
|
1503
1529
|
// the one being written, not because it failed. Leaving the failure standing left
|
|
1504
1530
|
// `s.error()` reporting a load that a later write superseded.
|
|
1505
|
-
const wasServable = cell.servable
|
|
1506
1531
|
const settling = settleProbes(cell)
|
|
1507
|
-
cell
|
|
1508
|
-
setDirect(cell, cell.state === CLEAN)
|
|
1509
|
-
// THE VALUE EDGE MOVED TOO WHERE THERE WAS NOTHING TO SERVE, whatever the gate
|
|
1510
|
-
// says about the payload — the same split `refused` makes, and for the same
|
|
1511
|
-
// reason. A read taken while this was unservable THREW, so a body that reached
|
|
1512
|
-
// it aborted: it is `CLEAN`, holds nothing, and nothing downstream will ever
|
|
1513
|
-
// pull it. Left silent, an `invalidate` whose reload landed the value it already
|
|
1514
|
-
// held stranded every value built from it at `ready()` false for the life of the
|
|
1515
|
-
// page. Over a value still being served nothing a reader can see moved (5.1) and
|
|
1516
|
-
// this stays quiet, which is the arm 5.2 is about.
|
|
1517
|
-
if (!wasServable) cascade(cell)
|
|
1532
|
+
serveAgain(cell)
|
|
1518
1533
|
if (settling) probesMoved(cell)
|
|
1519
1534
|
return cell.ordinal
|
|
1520
1535
|
}
|
|
@@ -1539,8 +1554,7 @@ function produce(cell: Cell, produced: unknown): number {
|
|
|
1539
1554
|
if (cap !== null && cell.body === null)
|
|
1540
1555
|
return capped(cell, cap, produced, moved)
|
|
1541
1556
|
serve(cell, produced)
|
|
1542
|
-
|
|
1543
|
-
if (moved) probesMoved(cell)
|
|
1557
|
+
land(cell, moved)
|
|
1544
1558
|
return cell.ordinal
|
|
1545
1559
|
}
|
|
1546
1560
|
|
|
@@ -1559,6 +1573,56 @@ function settleProbes(cell: Cell): boolean {
|
|
|
1559
1573
|
return moved
|
|
1560
1574
|
}
|
|
1561
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
|
+
|
|
1562
1626
|
/**
|
|
1563
1627
|
* Makes a production what readers see: stores it, arms its deadline, persists it.
|
|
1564
1628
|
*
|
|
@@ -1653,8 +1717,7 @@ function capped(
|
|
|
1653
1717
|
// collapses a RUN of changes and the first landing has nothing to collapse with.
|
|
1654
1718
|
if (wakes(cell, cap, produced)) {
|
|
1655
1719
|
serve(cell, produced)
|
|
1656
|
-
|
|
1657
|
-
if (moved) probesMoved(cell)
|
|
1720
|
+
land(cell, moved)
|
|
1658
1721
|
}
|
|
1659
1722
|
return cell.ordinal
|
|
1660
1723
|
}
|
|
@@ -1686,9 +1749,27 @@ function release(cell: Cell, cap: Cap): void {
|
|
|
1686
1749
|
cap.held = undefined
|
|
1687
1750
|
cell.loading = false
|
|
1688
1751
|
serve(cell, value)
|
|
1689
|
-
cascade(cell)
|
|
1690
1752
|
// The close is a `busy` edge (5.15) even though the value's readiness never moved.
|
|
1691
|
-
|
|
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
|
|
1692
1773
|
}
|
|
1693
1774
|
|
|
1694
1775
|
function releaseHeld(cell: Cell, cap: Cap): void {
|
|
@@ -1861,10 +1942,10 @@ function standWrite(cell: Cell, stream: Stream, value: unknown): number {
|
|
|
1861
1942
|
cell.value = value
|
|
1862
1943
|
stream.materializedAt = stream.version
|
|
1863
1944
|
stream.written = true
|
|
1945
|
+
// `busy` is the run's, which a write stands beside (3.7), so only `ready` and `error` move.
|
|
1864
1946
|
const moved = !cell.servable || cell.failure !== undefined
|
|
1865
1947
|
landChunks(cell)
|
|
1866
|
-
|
|
1867
|
-
if (moved) probesMoved(cell)
|
|
1948
|
+
land(cell, moved)
|
|
1868
1949
|
return cell.ordinal
|
|
1869
1950
|
}
|
|
1870
1951
|
|
|
@@ -1991,7 +2072,7 @@ function adopt(cell: Cell, inner: Cell): Error | undefined {
|
|
|
1991
2072
|
// 11.59: an adopting value's writes are the adopted value's, reached through a prototype of its
|
|
1992
2073
|
// own rather than a branch on every value's write path — see `acceptIntoStream` for what such a
|
|
1993
2074
|
// branch costs under V8 even where nothing takes it.
|
|
1994
|
-
|
|
2075
|
+
seat(cell)
|
|
1995
2076
|
if (!cell.loading && busyNow(inner) !== wasBusy) probesMoved(cell)
|
|
1996
2077
|
return undefined
|
|
1997
2078
|
}
|
|
@@ -2090,6 +2171,7 @@ function mirror(cell: Cell, inner: Cell): void {
|
|
|
2090
2171
|
if (cell.stream !== null) stopForwarding(cell)
|
|
2091
2172
|
if (!inner.servable) {
|
|
2092
2173
|
// 11.16: the newly adopted has nothing to serve, so neither has this.
|
|
2174
|
+
if (dropHeld(cell)) probesMoved(cell)
|
|
2093
2175
|
unserve(cell)
|
|
2094
2176
|
return
|
|
2095
2177
|
}
|
|
@@ -2120,20 +2202,16 @@ function mirror(cell: Cell, inner: Cell): void {
|
|
|
2120
2202
|
function dropAdoption(cell: Cell): void {
|
|
2121
2203
|
if (cell.adoption === null) return
|
|
2122
2204
|
unfollow(cell)
|
|
2123
|
-
const stream = cell.stream
|
|
2124
2205
|
// 9.11: AN OWN STREAM'S `adoption` IS A WRITE IT FOLLOWS, not a stream it forwards — the
|
|
2125
2206
|
// discriminator `adoptedCellOf` reads. Letting go of the write is all there is: the stream is
|
|
2126
2207
|
// its own, so is its prototype, and `follow` never touched `identityFn`. Stopping it as a
|
|
2127
2208
|
// forward nulled the stream a queued `wakeStreams` was about to read.
|
|
2128
|
-
if (
|
|
2129
|
-
if (stream !== null) stopForwarding(cell)
|
|
2209
|
+
if (ownStream(cell) !== null) return
|
|
2210
|
+
if (cell.stream !== null) stopForwarding(cell)
|
|
2130
2211
|
// 11.17 inherited the identity for the length of the adoption only.
|
|
2131
2212
|
cell.identityFn = cell.declaredIdentityFn
|
|
2132
2213
|
simpleShape(cell)
|
|
2133
|
-
|
|
2134
|
-
cell.callable as object,
|
|
2135
|
-
cell.simple ? SIMPLE_PROTOTYPE : MEMBER_PROTOTYPE,
|
|
2136
|
-
)
|
|
2214
|
+
seat(cell)
|
|
2137
2215
|
}
|
|
2138
2216
|
|
|
2139
2217
|
/**
|
|
@@ -2147,6 +2225,8 @@ function dropAdoption(cell: Cell): void {
|
|
|
2147
2225
|
function forwardStream(cell: Cell, inner: Cell, adopted: Stream): void {
|
|
2148
2226
|
let stream = cell.stream
|
|
2149
2227
|
if (stream === null) {
|
|
2228
|
+
// The `busy` the hold left is settled below, with the adopter's own load.
|
|
2229
|
+
dropHeld(cell)
|
|
2150
2230
|
stream = becomeStream(cell, inner)
|
|
2151
2231
|
stream.ordinalOffset = cell.ordinal - inner.ringBase
|
|
2152
2232
|
}
|
|
@@ -2172,8 +2252,7 @@ function forwardStream(cell: Cell, inner: Cell, adopted: Stream): void {
|
|
|
2172
2252
|
// on answering through the adoption (11.19) for as long as the stream is open.
|
|
2173
2253
|
const moved = settleProbes(cell)
|
|
2174
2254
|
landChunks(cell)
|
|
2175
|
-
|
|
2176
|
-
if (moved) probesMoved(cell)
|
|
2255
|
+
land(cell, moved)
|
|
2177
2256
|
}
|
|
2178
2257
|
|
|
2179
2258
|
function stopForwarding(cell: Cell): void {
|
|
@@ -2234,17 +2313,7 @@ function run(cell: Cell): void {
|
|
|
2234
2313
|
truncateProbes(reader)
|
|
2235
2314
|
cell.running = false
|
|
2236
2315
|
if (thrown instanceof NotLanded) {
|
|
2237
|
-
cell
|
|
2238
|
-
// 2.13: the mark a source's production makes is what finishes this run, and
|
|
2239
|
-
// `markReaders` queues it rather than leaving it for a read that may never come.
|
|
2240
|
-
cell.aborted = true
|
|
2241
|
-
// NOT EVERYTHING IT READS IS READY, so neither is this — 11.58, and the same
|
|
2242
|
-
// sentence 11.16 makes for a re-adoption. It stops serving rather than handing
|
|
2243
|
-
// back a figure it computed from a source that has since gone away, and that
|
|
2244
|
-
// is a move its readers have to hear even though the aborted run minted
|
|
2245
|
-
// nothing for a cascade to carry.
|
|
2246
|
-
if (cell.servable) unserve(cell)
|
|
2247
|
-
else probesMoved(cell)
|
|
2316
|
+
abortRun(cell)
|
|
2248
2317
|
return
|
|
2249
2318
|
}
|
|
2250
2319
|
refused(cell, thrown)
|
|
@@ -2325,6 +2394,23 @@ function run(cell: Cell): void {
|
|
|
2325
2394
|
absorb(cell, produced, true)
|
|
2326
2395
|
}
|
|
2327
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
|
+
|
|
2328
2414
|
/**
|
|
2329
2415
|
* Adopts what a body handed back, refusing the body where that would close a cycle.
|
|
2330
2416
|
*
|
|
@@ -2348,8 +2434,7 @@ function landOpening(cell: Cell): void {
|
|
|
2348
2434
|
cell.landed = true
|
|
2349
2435
|
cell.servable = true
|
|
2350
2436
|
setDirect(cell, cell.state === CLEAN)
|
|
2351
|
-
|
|
2352
|
-
if (moved) probesMoved(cell)
|
|
2437
|
+
land(cell, moved)
|
|
2353
2438
|
}
|
|
2354
2439
|
|
|
2355
2440
|
/**
|
|
@@ -2361,11 +2446,23 @@ function landOpening(cell: Cell): void {
|
|
|
2361
2446
|
* be marked by (14.13).
|
|
2362
2447
|
*/
|
|
2363
2448
|
function startProducer(cell: Cell): void {
|
|
2364
|
-
const stream = cell
|
|
2365
|
-
if (stream === null
|
|
2449
|
+
const stream = ownStream(cell)
|
|
2450
|
+
if (stream === null) run(cell)
|
|
2366
2451
|
else startStream(cell, stream)
|
|
2367
2452
|
}
|
|
2368
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
|
+
|
|
2369
2466
|
/**
|
|
2370
2467
|
* Supersedes the run in flight and tells its iterator to return.
|
|
2371
2468
|
*
|
|
@@ -2399,10 +2496,7 @@ function startStream(cell: Cell, stream: Stream): void {
|
|
|
2399
2496
|
*/
|
|
2400
2497
|
function promoteToStream(cell: Cell, generator: AsyncIterable<unknown>): void {
|
|
2401
2498
|
let stream = cell.stream
|
|
2402
|
-
if (stream === null)
|
|
2403
|
-
stream = becomeStream(cell, null)
|
|
2404
|
-
Object.setPrototypeOf(cell.callable as object, STREAM_PROTOTYPE)
|
|
2405
|
-
}
|
|
2499
|
+
if (stream === null) stream = becomeStream(cell, null)
|
|
2406
2500
|
pumpRun(cell, stream, generator[Symbol.asyncIterator]())
|
|
2407
2501
|
}
|
|
2408
2502
|
|
|
@@ -2488,7 +2582,6 @@ async function pump(
|
|
|
2488
2582
|
cap.holding = false
|
|
2489
2583
|
releaseChunks(cell, stream)
|
|
2490
2584
|
}
|
|
2491
|
-
const moved = !begun || cell.loading
|
|
2492
2585
|
if (!begun) {
|
|
2493
2586
|
// A stream that closed with nothing in it has finished, and what it accumulated is
|
|
2494
2587
|
// no chunks — a value, where waiting on would be a load that never ends.
|
|
@@ -2496,9 +2589,8 @@ async function pump(
|
|
|
2496
2589
|
landChunks(cell)
|
|
2497
2590
|
cascade(cell)
|
|
2498
2591
|
}
|
|
2499
|
-
cell.loading = false
|
|
2500
2592
|
// 3.7: `busy` held until the close, and this is the close.
|
|
2501
|
-
|
|
2593
|
+
endLoad(cell, !begun)
|
|
2502
2594
|
// 6.10, AFTER THE CASCADE ABOVE: the entry is what a read would answer with, so it is taken
|
|
2503
2595
|
// once the last chunk has landed and the value is servable.
|
|
2504
2596
|
closeRun(cell, stream)
|
|
@@ -2635,7 +2727,7 @@ function materialize(cell: Cell, stream: Stream): void {
|
|
|
2635
2727
|
// 9.11: the accumulation moved past a write following a `Reactive`, which lets go of it here
|
|
2636
2728
|
// where no chunk's wake did — a patch, or a run that closed empty. Only an own stream follows;
|
|
2637
2729
|
// a forwarding one's `adoption` is what it forwards.
|
|
2638
|
-
if (cell.adoption !== null &&
|
|
2730
|
+
if (cell.adoption !== null && ownStream(cell) !== null) unfollow(cell)
|
|
2639
2731
|
stream.materializedAt = stream.version
|
|
2640
2732
|
stream.written = false
|
|
2641
2733
|
gateInto(cell, stream.chunks.slice(0, stream.visible))
|
|
@@ -2685,6 +2777,97 @@ function heldValue(cell: Cell): unknown {
|
|
|
2685
2777
|
return cell.value
|
|
2686
2778
|
}
|
|
2687
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
|
+
|
|
2688
2871
|
/**
|
|
2689
2872
|
* Releases the standing production at its deadline, waking nobody.
|
|
2690
2873
|
*
|
|
@@ -2839,8 +3022,7 @@ function expire(cell: Cell): void {
|
|
|
2839
3022
|
* which is what lets the flag be conservative.
|
|
2840
3023
|
*/
|
|
2841
3024
|
function readIndirect(cell: Cell): unknown {
|
|
2842
|
-
|
|
2843
|
-
if (cell.state !== CLEAN) resolve(cell)
|
|
3025
|
+
bringCurrent(cell)
|
|
2844
3026
|
// 6.5: THE READ THAT FOLLOWS. Every value carrying an expiry arrives here and no
|
|
2845
3027
|
// other value does, which is the whole of what `setDirect` buys.
|
|
2846
3028
|
if (cell.expiry !== null) expire(cell)
|
|
@@ -2940,53 +3122,6 @@ function failureOf(cell: Cell): unknown {
|
|
|
2940
3122
|
return at.failure
|
|
2941
3123
|
}
|
|
2942
3124
|
|
|
2943
|
-
/**
|
|
2944
|
-
* What one run of `cell` produced, as `for await` walks it.
|
|
2945
|
-
*
|
|
2946
|
-
* 2.5 AND 2.6 — the settling, yielded once, or a stream's chunks from the first to the close. Which
|
|
2947
|
-
* of the two is asked of the settling, since a value may only turn out to stream once its load
|
|
2948
|
-
* resolves (9.6).
|
|
2949
|
-
*
|
|
2950
|
-
* THE CURSOR IS THE WAKE AND THE SETTLING IS THE END (`Cursor.closeOn`).
|
|
2951
|
-
*/
|
|
2952
|
-
async function* producedRun(cell: Cell): AsyncGenerator<unknown> {
|
|
2953
|
-
const first = await settled(cell, true)
|
|
2954
|
-
if (first !== STREAMING) {
|
|
2955
|
-
yield first
|
|
2956
|
-
return
|
|
2957
|
-
}
|
|
2958
|
-
// THE RUN IS ITS RING: a new run's first chunk replaces the array, where a patch mutates it in
|
|
2959
|
-
// place (9.13) and only moves the base. A run with no chunk yet holds `EMPTY_RING`.
|
|
2960
|
-
let ring = cell.ring
|
|
2961
|
-
// 9.15 — a failure already standing is a revalidation's (2.4), and not this run's.
|
|
2962
|
-
const standing = failureOf(cell)
|
|
2963
|
-
const cursor = new Cursor(cell, cell.ringBase)
|
|
2964
|
-
cursor.closeOn(settled(cell))
|
|
2965
|
-
try {
|
|
2966
|
-
for (;;) {
|
|
2967
|
-
if (cell.ring !== ring) {
|
|
2968
|
-
// 9.16.
|
|
2969
|
-
if (ring !== EMPTY_RING) return
|
|
2970
|
-
ring = cell.ring
|
|
2971
|
-
}
|
|
2972
|
-
const chunk = cursor.take()
|
|
2973
|
-
if (chunk !== CAUGHT_UP) {
|
|
2974
|
-
yield chunk
|
|
2975
|
-
continue
|
|
2976
|
-
}
|
|
2977
|
-
if (cursor.closed) break
|
|
2978
|
-
await cursor.turn()
|
|
2979
|
-
}
|
|
2980
|
-
} finally {
|
|
2981
|
-
cursor.stop()
|
|
2982
|
-
}
|
|
2983
|
-
if (cursor.failure !== undefined) throw cursor.failure
|
|
2984
|
-
// 9.15 AND 16.59 — a run that failed after its first chunk, or one its timeout ended, settles
|
|
2985
|
-
// with what it had; the refusal stands beside it.
|
|
2986
|
-
const ended = failureOf(cell)
|
|
2987
|
-
if (ended !== undefined && ended !== standing) throw ended
|
|
2988
|
-
}
|
|
2989
|
-
|
|
2990
3125
|
/**
|
|
2991
3126
|
* `busy` without subscribing.
|
|
2992
3127
|
*
|
|
@@ -3042,12 +3177,14 @@ function isReady(cell: Cell): boolean {
|
|
|
3042
3177
|
}
|
|
3043
3178
|
|
|
3044
3179
|
/**
|
|
3045
|
-
*
|
|
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.
|
|
3046
3183
|
*
|
|
3047
3184
|
* 3.2 — A PROBE ANSWERS ABOUT THE VALUE A READ WOULD SERVE. Under push-pull a write leaves every
|
|
3048
3185
|
* derived value it reached unrun, so a probe that walked what the last run left answered about a
|
|
3049
3186
|
* value nothing would serve: `x.ready()` true over a body whose inputs had moved to a load, and the
|
|
3050
|
-
* read the guard admitted threw `NotLanded`.
|
|
3187
|
+
* read the guard admitted threw `NotLanded`.
|
|
3051
3188
|
*/
|
|
3052
3189
|
function bringCurrent(cell: Cell): void {
|
|
3053
3190
|
if (cell.owes !== OWES_NOTHING) settleOwed(cell)
|
|
@@ -3087,8 +3224,7 @@ function settled(cell: Cell, untilStreaming = false): Promise<unknown> {
|
|
|
3087
3224
|
// ONLY ONCE THE TIMER HAS DROPPED IT. The read's half of 6.5 — a production still served past
|
|
3088
3225
|
// its deadline — is not taken here, because 16.7's `ttl` of 0 makes every mutation's production
|
|
3089
3226
|
// past its deadline the moment it lands, and the await that answers the call ran it again.
|
|
3090
|
-
|
|
3091
|
-
if (cell.state !== CLEAN) resolve(cell)
|
|
3227
|
+
bringCurrent(cell)
|
|
3092
3228
|
if (cell.expiry?.dropped) expire(cell)
|
|
3093
3229
|
if (untilStreaming && cell.stream !== null)
|
|
3094
3230
|
return Promise.resolve(STREAMING)
|
|
@@ -3339,12 +3475,9 @@ function invalidateOne(cell: Cell): void {
|
|
|
3339
3475
|
if (!reloads(cell)) return
|
|
3340
3476
|
// Not directly servable, so the next read goes a frame in and settles the debt.
|
|
3341
3477
|
cell.direct = false
|
|
3342
|
-
// 7.15: work already in flight was started from what this says is wrong.
|
|
3343
|
-
//
|
|
3344
|
-
cell
|
|
3345
|
-
cell.loading = false
|
|
3346
|
-
const stream = cell.stream
|
|
3347
|
-
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)
|
|
3348
3481
|
cell.owes = OWES_RELOAD
|
|
3349
3482
|
owedBelow(cell)
|
|
3350
3483
|
}
|
|
@@ -3460,10 +3593,7 @@ export function startDeferred(value: unknown): void {
|
|
|
3460
3593
|
* and a reader still holding it hears that.
|
|
3461
3594
|
*/
|
|
3462
3595
|
export function abandonDeferred(value: unknown): void {
|
|
3463
|
-
|
|
3464
|
-
if (!cell.loading) return
|
|
3465
|
-
cell.loading = false
|
|
3466
|
-
probesMoved(cell)
|
|
3596
|
+
endLoad((value as Callable)[CELL], false)
|
|
3467
3597
|
}
|
|
3468
3598
|
|
|
3469
3599
|
// ── `store` ──────────────────────────────────────────────────────────────────────────────
|
|
@@ -3516,7 +3646,7 @@ function restoreFirst(
|
|
|
3516
3646
|
settleRestore(cell, persisted, answer, initial)
|
|
3517
3647
|
return
|
|
3518
3648
|
}
|
|
3519
|
-
cell
|
|
3649
|
+
beginLoad(cell)
|
|
3520
3650
|
const generation = cell.generation
|
|
3521
3651
|
answer.then(
|
|
3522
3652
|
(value) => {
|
|
@@ -3549,10 +3679,7 @@ function settleRestore(
|
|
|
3549
3679
|
if (cell.body !== null) startProducer(cell)
|
|
3550
3680
|
else if (initial === undefined) landOpening(cell)
|
|
3551
3681
|
else if (initial !== NO_INITIAL) open(cell, initial)
|
|
3552
|
-
else
|
|
3553
|
-
cell.loading = false
|
|
3554
|
-
probesMoved(cell)
|
|
3555
|
-
}
|
|
3682
|
+
else endLoad(cell, false)
|
|
3556
3683
|
}
|
|
3557
3684
|
|
|
3558
3685
|
/**
|
|
@@ -3589,8 +3716,7 @@ function restoreStream(cell: Cell, stream: Stream, chunks: unknown[]): void {
|
|
|
3589
3716
|
stream.version += 1
|
|
3590
3717
|
const moved = settleProbes(cell)
|
|
3591
3718
|
landChunks(cell)
|
|
3592
|
-
|
|
3593
|
-
if (moved) probesMoved(cell)
|
|
3719
|
+
land(cell, moved)
|
|
3594
3720
|
// 8.7 SAYS THE BODY NEVER STARTS, AND `pump` IS WHAT REACHES `closeRun` — so the
|
|
3595
3721
|
// restored accumulation is entered as a closed run here or nothing ever does it.
|
|
3596
3722
|
// Without this `standingLive` answers false for the life of the value, which takes
|
|
@@ -3669,13 +3795,7 @@ function settleMiss(cell: Cell): void {
|
|
|
3669
3795
|
)
|
|
3670
3796
|
return
|
|
3671
3797
|
}
|
|
3672
|
-
|
|
3673
|
-
const wasLoading = cell.loading
|
|
3674
|
-
cell.servable = true
|
|
3675
|
-
cell.loading = false
|
|
3676
|
-
setDirect(cell, cell.state === CLEAN)
|
|
3677
|
-
if (cell.servable !== wasServable) cascade(cell)
|
|
3678
|
-
if (wasLoading || cell.servable !== wasServable) probesMoved(cell)
|
|
3798
|
+
endLoad(cell, serveAgain(cell))
|
|
3679
3799
|
}
|
|
3680
3800
|
|
|
3681
3801
|
/**
|
|
@@ -4107,12 +4227,13 @@ const MEMBERS = {
|
|
|
4107
4227
|
}
|
|
4108
4228
|
|
|
4109
4229
|
/**
|
|
4110
|
-
* 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.
|
|
4111
4232
|
*
|
|
4112
4233
|
* 11.12: an adopting value serves the adopted value's production, and an adoption of an adoption
|
|
4113
4234
|
* goes on down — so a follow's version (18.7) and its feed name the cell that actually produced.
|
|
4114
4235
|
*/
|
|
4115
|
-
export function servedCellOf(value: unknown):
|
|
4236
|
+
export function servedCellOf(value: unknown): { readonly ordinal: number } {
|
|
4116
4237
|
return adoptedCellOf(value)
|
|
4117
4238
|
}
|
|
4118
4239
|
|
|
@@ -4136,10 +4257,16 @@ export function deadlineOf(value: unknown): number {
|
|
|
4136
4257
|
* 16.48 — WHICH LOAD A VALUE HAS IN FLIGHT, as the generation that started it, or `undefined` where
|
|
4137
4258
|
* none is. Read off the cell rather than through `busy`, which is a probe and would subscribe the
|
|
4138
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.
|
|
4139
4264
|
*/
|
|
4140
4265
|
export function loadOf(value: unknown): number | undefined {
|
|
4141
4266
|
const cell = (value as Callable)[CELL]
|
|
4142
|
-
|
|
4267
|
+
if (!cell.loading) return undefined
|
|
4268
|
+
if (cell.cap?.holding && cell.stream === null) return undefined
|
|
4269
|
+
return cell.generation
|
|
4143
4270
|
}
|
|
4144
4271
|
|
|
4145
4272
|
/**
|
|
@@ -4176,8 +4303,7 @@ export function failedTransiently(value: unknown): boolean {
|
|
|
4176
4303
|
export function abandonLoad(value: unknown, failure: unknown): void {
|
|
4177
4304
|
const cell = (value as Callable)[CELL]
|
|
4178
4305
|
if (!cell.loading) return
|
|
4179
|
-
cell
|
|
4180
|
-
if (cell.stream !== null) stopStream(cell.stream)
|
|
4306
|
+
supersede(cell)
|
|
4181
4307
|
refused(cell, failure)
|
|
4182
4308
|
}
|
|
4183
4309
|
|
|
@@ -4204,42 +4330,10 @@ export function isStreaming(value: unknown): boolean {
|
|
|
4204
4330
|
return stream !== null && stream !== undefined
|
|
4205
4331
|
}
|
|
4206
4332
|
|
|
4207
|
-
/**
|
|
4208
|
-
* A cursor over `value` that reads nothing and only wakes when it changes.
|
|
4209
|
-
*
|
|
4210
|
-
* PLACED PAST EVERY CHUNK, so it holds no place a patch has to keep (5.7) and is never behind.
|
|
4211
|
-
*/
|
|
4212
|
-
export function wakeOf(value: unknown): Cursor {
|
|
4213
|
-
return new Cursor((value as Callable)[CELL], Number.POSITIVE_INFINITY)
|
|
4214
|
-
}
|
|
4215
|
-
|
|
4216
|
-
/**
|
|
4217
|
-
* The chunks a streaming value has told its readers of, from index `from` on.
|
|
4218
|
-
*
|
|
4219
|
-
* 16.32 — THE CHUNKS A STREAMING VALUE HAS TOLD ITS READERS OF PAST `from`, for a writer sending each
|
|
4220
|
-
* once. Ungated they are read out of the accumulation in place, to `visible` rather than its length
|
|
4221
|
-
* (5.18): a read materializes a copy of the whole of it (9.1), which for a writer woken per chunk is
|
|
4222
|
-
* n²/2 elements copied to send n. A schema or a transform has to see the whole accumulation (9.8),
|
|
4223
|
-
* so a gated value answers from what a read would.
|
|
4224
|
-
*/
|
|
4225
|
-
export function* chunksFrom(value: unknown, from: number): Generator<unknown> {
|
|
4226
|
-
const cell = (value as Callable)[CELL]
|
|
4227
|
-
if (cell.schema === null && cell.transform === null) {
|
|
4228
|
-
const stream = cell.stream as Stream
|
|
4229
|
-
for (let index = from; index < stream.visible; index += 1)
|
|
4230
|
-
yield stream.chunks[index]
|
|
4231
|
-
return
|
|
4232
|
-
}
|
|
4233
|
-
const held = MEMBERS.peek.call(value as Callable)
|
|
4234
|
-
if (Array.isArray(held))
|
|
4235
|
-
for (let index = from; index < held.length; index += 1)
|
|
4236
|
-
yield held[index]
|
|
4237
|
-
}
|
|
4238
|
-
|
|
4239
4333
|
function adoptedCellOf(value: unknown): Cell {
|
|
4240
4334
|
let cell = (value as Callable)[CELL]
|
|
4241
4335
|
// A stream's own `adoption` is a write it follows (9.11), and its past is its own.
|
|
4242
|
-
while (cell.adoption !== null && cell
|
|
4336
|
+
while (cell.adoption !== null && ownStream(cell) === null)
|
|
4243
4337
|
cell = cell.adoption.source
|
|
4244
4338
|
return cell
|
|
4245
4339
|
}
|
|
@@ -4432,7 +4526,8 @@ function orphan(cell: Cell): void {
|
|
|
4432
4526
|
function releaseOrphan(cell: Cell): void {
|
|
4433
4527
|
cell.orphaned = false
|
|
4434
4528
|
const stream = cell.stream
|
|
4435
|
-
|
|
4529
|
+
const own = ownStream(cell)
|
|
4530
|
+
if (own !== null) stopStream(own)
|
|
4436
4531
|
dropAdoption(cell)
|
|
4437
4532
|
cell.aborted = false
|
|
4438
4533
|
if (cell.body !== null && stream === null) {
|
|
@@ -4512,14 +4607,7 @@ export function createReactive<
|
|
|
4512
4607
|
// BEFORE THE FIELD, not after: an engine keys its inline caches on the shape a
|
|
4513
4608
|
// property was added to, and re-pointing the prototype afterwards invalidates the
|
|
4514
4609
|
// transition the store just built.
|
|
4515
|
-
Object.setPrototypeOf(
|
|
4516
|
-
self,
|
|
4517
|
-
streaming
|
|
4518
|
-
? STREAM_PROTOTYPE
|
|
4519
|
-
: cell.simple
|
|
4520
|
-
? SIMPLE_PROTOTYPE
|
|
4521
|
-
: MEMBER_PROTOTYPE,
|
|
4522
|
-
)
|
|
4610
|
+
Object.setPrototypeOf(self, seatOf(cell))
|
|
4523
4611
|
self[CELL] = cell
|
|
4524
4612
|
cell.callable = self as unknown as Reactive<unknown>
|
|
4525
4613
|
if (cell.tags !== null) tagCell(cell)
|