@bradensbay/globals-core 0.2.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/README.md +69 -0
- package/dist/src/allocator.d.ts +78 -0
- package/dist/src/allocator.d.ts.map +1 -0
- package/dist/src/allocator.js +211 -0
- package/dist/src/allocator.js.map +1 -0
- package/dist/src/arena.d.ts +81 -0
- package/dist/src/arena.d.ts.map +1 -0
- package/dist/src/arena.js +224 -0
- package/dist/src/arena.js.map +1 -0
- package/dist/src/checksum.d.ts +5 -0
- package/dist/src/checksum.d.ts.map +1 -0
- package/dist/src/checksum.js +35 -0
- package/dist/src/checksum.js.map +1 -0
- package/dist/src/draft.d.ts +48 -0
- package/dist/src/draft.d.ts.map +1 -0
- package/dist/src/draft.js +427 -0
- package/dist/src/draft.js.map +1 -0
- package/dist/src/errors.d.ts +56 -0
- package/dist/src/errors.d.ts.map +1 -0
- package/dist/src/errors.js +69 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/external.d.ts +52 -0
- package/dist/src/external.d.ts.map +1 -0
- package/dist/src/external.js +68 -0
- package/dist/src/external.js.map +1 -0
- package/dist/src/hamt.d.ts +87 -0
- package/dist/src/hamt.d.ts.map +1 -0
- package/dist/src/hamt.js +643 -0
- package/dist/src/hamt.js.map +1 -0
- package/dist/src/history.d.ts +45 -0
- package/dist/src/history.d.ts.map +1 -0
- package/dist/src/history.js +49 -0
- package/dist/src/history.js.map +1 -0
- package/dist/src/index.d.ts +55 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +38 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/inspect.d.ts +74 -0
- package/dist/src/inspect.d.ts.map +1 -0
- package/dist/src/inspect.js +127 -0
- package/dist/src/inspect.js.map +1 -0
- package/dist/src/layout.d.ts +130 -0
- package/dist/src/layout.d.ts.map +1 -0
- package/dist/src/layout.js +149 -0
- package/dist/src/layout.js.map +1 -0
- package/dist/src/liveness.d.ts +48 -0
- package/dist/src/liveness.d.ts.map +1 -0
- package/dist/src/liveness.js +92 -0
- package/dist/src/liveness.js.map +1 -0
- package/dist/src/owner.d.ts +130 -0
- package/dist/src/owner.d.ts.map +1 -0
- package/dist/src/owner.js +368 -0
- package/dist/src/owner.js.map +1 -0
- package/dist/src/reader.d.ts +122 -0
- package/dist/src/reader.d.ts.map +1 -0
- package/dist/src/reader.js +325 -0
- package/dist/src/reader.js.map +1 -0
- package/dist/src/readers.d.ts +60 -0
- package/dist/src/readers.d.ts.map +1 -0
- package/dist/src/readers.js +122 -0
- package/dist/src/readers.js.map +1 -0
- package/dist/src/retained.d.ts +39 -0
- package/dist/src/retained.d.ts.map +1 -0
- package/dist/src/retained.js +99 -0
- package/dist/src/retained.js.map +1 -0
- package/dist/src/schema.d.ts +82 -0
- package/dist/src/schema.d.ts.map +1 -0
- package/dist/src/schema.js +18 -0
- package/dist/src/schema.js.map +1 -0
- package/dist/src/store.d.ts +83 -0
- package/dist/src/store.d.ts.map +1 -0
- package/dist/src/store.js +127 -0
- package/dist/src/store.js.map +1 -0
- package/dist/src/strings.d.ts +37 -0
- package/dist/src/strings.d.ts.map +1 -0
- package/dist/src/strings.js +144 -0
- package/dist/src/strings.js.map +1 -0
- package/dist/src/tags.d.ts +47 -0
- package/dist/src/tags.d.ts.map +1 -0
- package/dist/src/tags.js +53 -0
- package/dist/src/tags.js.map +1 -0
- package/dist/src/values.d.ts +90 -0
- package/dist/src/values.d.ts.map +1 -0
- package/dist/src/values.js +458 -0
- package/dist/src/values.js.map +1 -0
- package/dist/src/vector.d.ts +64 -0
- package/dist/src/vector.d.ts.map +1 -0
- package/dist/src/vector.js +387 -0
- package/dist/src/vector.js.map +1 -0
- package/dist/src/verify.d.ts +38 -0
- package/dist/src/verify.d.ts.map +1 -0
- package/dist/src/verify.js +179 -0
- package/dist/src/verify.js.map +1 -0
- package/dist/src/view.d.ts +66 -0
- package/dist/src/view.d.ts.map +1 -0
- package/dist/src/view.js +278 -0
- package/dist/src/view.js.map +1 -0
- package/package.json +28 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { Header, VerifyMode } from "./layout.js";
|
|
2
|
+
import { HASH_SEED, mixWord } from "./checksum.js";
|
|
3
|
+
import { Tag } from "./tags.js";
|
|
4
|
+
import { WORD } from "./layout.js";
|
|
5
|
+
import { hamtEntries } from "./hamt.js";
|
|
6
|
+
import { vectorSlots } from "./vector.js";
|
|
7
|
+
import { ArenaCorruptError } from "./errors.js";
|
|
8
|
+
/**
|
|
9
|
+
* Verified reads.
|
|
10
|
+
*
|
|
11
|
+
* The trust model says a shared buffer is writable by everything that maps it, and that no
|
|
12
|
+
* amount of engineering removes that. What a checksum does buy is detection: a window that
|
|
13
|
+
* corrupts the arena through a bug, or a hostile window that does not also forge the
|
|
14
|
+
* checksum, is caught before a reader decodes what it wrote.
|
|
15
|
+
*
|
|
16
|
+
* What it does not buy, stated here as plainly as in the documentation, is protection from a
|
|
17
|
+
* window that computes a valid checksum for corrupt data. That window has exactly the
|
|
18
|
+
* information the owner has. This is a corruption detector, not a message authentication
|
|
19
|
+
* code, and calling it one would be a lie a security reviewer would catch.
|
|
20
|
+
*
|
|
21
|
+
* Cost is per version, not per read. The owner computes it once on commit and a reader
|
|
22
|
+
* verifies once when it acquires a new version, so a render loop that reads the same version
|
|
23
|
+
* a hundred times pays once.
|
|
24
|
+
*/
|
|
25
|
+
/** Words covered by the header checksum. The root, the version, and the geometry. */
|
|
26
|
+
const COVERED = [
|
|
27
|
+
Header.Magic,
|
|
28
|
+
Header.LayoutVersion,
|
|
29
|
+
Header.RootTag,
|
|
30
|
+
Header.RootPayload,
|
|
31
|
+
Header.VersionId,
|
|
32
|
+
Header.MaxReaders,
|
|
33
|
+
Header.ReaderTableOffset,
|
|
34
|
+
Header.RetainedRingOffset,
|
|
35
|
+
Header.RetainedCapacity,
|
|
36
|
+
Header.ArenaOffset,
|
|
37
|
+
Header.OwnerGeneration,
|
|
38
|
+
];
|
|
39
|
+
// Deliberately not covered: the reclaim floor, the bump pointer, and the statistics. All
|
|
40
|
+
// three move independently of the root, the floor within the very commit that publishes the
|
|
41
|
+
// checksum, so covering them would make every version fail verification.
|
|
42
|
+
export function verifyMode(arena) {
|
|
43
|
+
const flags = arena.loadHeader(Header.Flags) & 0b11;
|
|
44
|
+
return flags;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The header checksum, over the root and the geometry.
|
|
48
|
+
*
|
|
49
|
+
* Deliberately not over the bump pointer or the statistics, which move independently of the
|
|
50
|
+
* root and would make every reader recompute for no reason.
|
|
51
|
+
*/
|
|
52
|
+
export function headerChecksum(arena, root, versionId) {
|
|
53
|
+
const words = arena.words;
|
|
54
|
+
let hash = HASH_SEED;
|
|
55
|
+
for (const field of COVERED) {
|
|
56
|
+
if (field === Header.RootTag) {
|
|
57
|
+
hash = mixWord(hash, root.tag);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (field === Header.RootPayload) {
|
|
61
|
+
hash = mixWord(hash, root.payload);
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (field === Header.VersionId) {
|
|
65
|
+
hash = mixWord(hash, versionId);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
hash = mixWord(hash, words[field]);
|
|
69
|
+
}
|
|
70
|
+
return hash === 0 ? 1 : hash;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* A checksum over everything reachable from a root.
|
|
74
|
+
*
|
|
75
|
+
* Linear in the size of the structure, so it is a diagnostic mode rather than a production
|
|
76
|
+
* one. It catches corruption of a leaf value deep in the tree, which the header checksum
|
|
77
|
+
* cannot see at all.
|
|
78
|
+
*
|
|
79
|
+
* The walk is bounded by the same block header validation every decode uses, so a corrupted
|
|
80
|
+
* arena makes this throw rather than loop.
|
|
81
|
+
*/
|
|
82
|
+
export function deepChecksum(arena, root, budget = 2_000_000) {
|
|
83
|
+
let hash = HASH_SEED;
|
|
84
|
+
let visited = 0;
|
|
85
|
+
const walk = (slot) => {
|
|
86
|
+
visited += 1;
|
|
87
|
+
if (visited > budget) {
|
|
88
|
+
throw new ArenaCorruptError(`the reachable set exceeded ${budget} nodes, which means a cycle or a corrupt offset`);
|
|
89
|
+
}
|
|
90
|
+
hash = mixWord(hash, slot.tag);
|
|
91
|
+
switch (slot.tag) {
|
|
92
|
+
case Tag.Undefined:
|
|
93
|
+
case Tag.Null:
|
|
94
|
+
case Tag.False:
|
|
95
|
+
case Tag.True:
|
|
96
|
+
return;
|
|
97
|
+
case Tag.Int32:
|
|
98
|
+
hash = mixWord(hash, slot.payload);
|
|
99
|
+
return;
|
|
100
|
+
case Tag.Double:
|
|
101
|
+
case Tag.Date: {
|
|
102
|
+
arena.checkBlock(slot.payload, "verify double");
|
|
103
|
+
const base = slot.payload / WORD;
|
|
104
|
+
hash = mixWord(hash, arena.words[base]);
|
|
105
|
+
hash = mixWord(hash, arena.words[base + 1]);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
case Tag.String:
|
|
109
|
+
case Tag.RegExp:
|
|
110
|
+
case Tag.BigInt:
|
|
111
|
+
case Tag.TypedArray: {
|
|
112
|
+
const size = arena.checkBlock(slot.payload, "verify record");
|
|
113
|
+
const base = slot.payload / WORD;
|
|
114
|
+
for (let i = 0; i < size / WORD; i += 1) {
|
|
115
|
+
hash = mixWord(hash, arena.words[base + i]);
|
|
116
|
+
}
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
case Tag.Object:
|
|
120
|
+
case Tag.Map:
|
|
121
|
+
case Tag.Set: {
|
|
122
|
+
for (const entry of hamtEntries(arena, slot.payload)) {
|
|
123
|
+
walk(entry.key);
|
|
124
|
+
walk(entry.value);
|
|
125
|
+
}
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
case Tag.Array: {
|
|
129
|
+
for (const element of vectorSlots(arena, slot.payload))
|
|
130
|
+
walk(element);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
case Tag.External:
|
|
134
|
+
hash = mixWord(hash, slot.payload);
|
|
135
|
+
return;
|
|
136
|
+
default:
|
|
137
|
+
throw new ArenaCorruptError(`verify found an unknown tag ${slot.tag}`, {
|
|
138
|
+
actual: slot.tag,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
walk(root);
|
|
143
|
+
return hash === 0 ? 1 : hash;
|
|
144
|
+
}
|
|
145
|
+
/** Owner side. Compute and publish the checksum for a version. */
|
|
146
|
+
export function publishChecksum(arena, root, versionId, mode) {
|
|
147
|
+
if (mode === VerifyMode.Off) {
|
|
148
|
+
arena.storeHeader(Header.RootChecksum, 0);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const header = headerChecksum(arena, root, versionId);
|
|
152
|
+
const value = mode === VerifyMode.Full ? mixWord(header, deepChecksum(arena, root)) : header;
|
|
153
|
+
arena.storeHeader(Header.RootChecksum, value === 0 ? 1 : value);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Reader side. Throw when the published checksum does not match the root it belongs to.
|
|
157
|
+
*
|
|
158
|
+
* The published checksum is a parameter rather than something this function loads, and that
|
|
159
|
+
* is not tidiness. It has to be read inside the seqlock window alongside the root and the
|
|
160
|
+
* version, or the writer can commit between the seqlock check and the checksum load, and the
|
|
161
|
+
* reader compares a checksum from one version against a root from another. That produced a
|
|
162
|
+
* steady trickle of false corruption reports under load, roughly fifty in eight hundred
|
|
163
|
+
* thousand reads, which is exactly the shape of bug that looks like flakiness.
|
|
164
|
+
*
|
|
165
|
+
* Called once per version rather than once per read.
|
|
166
|
+
*/
|
|
167
|
+
export function verifyRoot(arena, root, versionId, published) {
|
|
168
|
+
const mode = verifyMode(arena);
|
|
169
|
+
if (mode === VerifyMode.Off)
|
|
170
|
+
return;
|
|
171
|
+
const header = headerChecksum(arena, root, versionId);
|
|
172
|
+
const expected = mode === VerifyMode.Full ? mixWord(header, deepChecksum(arena, root)) : header;
|
|
173
|
+
const normalised = expected === 0 ? 1 : expected;
|
|
174
|
+
if (published !== normalised) {
|
|
175
|
+
throw new ArenaCorruptError(`version ${versionId} does not match its published checksum. Something wrote to the ` +
|
|
176
|
+
"arena that is not the owner. Treat this as a security event as well as a bug.", { expected: normalised, actual: published });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=verify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/verify.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { SharedArena } from "./arena.js";
|
|
2
|
+
import { type Slot } from "./values.js";
|
|
3
|
+
/**
|
|
4
|
+
* Lazy views over arena data.
|
|
5
|
+
*
|
|
6
|
+
* `getSnapshot()` hands back one of these rather than a materialised object. Reading one
|
|
7
|
+
* property decodes one property. A table that renders twenty visible rows out of five
|
|
8
|
+
* thousand pays for twenty.
|
|
9
|
+
*
|
|
10
|
+
* Two things make the laziness safe rather than a trap:
|
|
11
|
+
*
|
|
12
|
+
* Every property access revalidates the version. A view whose version was reclaimed raises
|
|
13
|
+
* StaleSnapshotError on the next access rather than returning stale bytes.
|
|
14
|
+
*
|
|
15
|
+
* Decoded nodes are memoised per version. The cache is owned by the view context and is
|
|
16
|
+
* discarded wholesale when the root moves, so a stale entry is not reachable.
|
|
17
|
+
*/
|
|
18
|
+
export interface ViewContext {
|
|
19
|
+
readonly arena: SharedArena;
|
|
20
|
+
/** Throws when the version this view belongs to is no longer retained. */
|
|
21
|
+
readonly validate: () => void;
|
|
22
|
+
/** Decoded containers, keyed by arena offset, valid for one version only. */
|
|
23
|
+
readonly cache: Map<number, unknown>;
|
|
24
|
+
}
|
|
25
|
+
declare const VIEW_SLOT: unique symbol;
|
|
26
|
+
/** True when the value is a lazy view rather than a plain decoded value. */
|
|
27
|
+
export declare function isView(value: unknown): boolean;
|
|
28
|
+
/** The slot a view is bound to, for callers that need the underlying reference. */
|
|
29
|
+
export declare function viewSlot(value: unknown): Slot | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Decode a slot into a value, lazily for containers and eagerly for everything else.
|
|
32
|
+
*
|
|
33
|
+
* Scalars are cheaper to decode than to wrap, and a `Date` or a typed array has no useful
|
|
34
|
+
* lazy form, so only objects, arrays, maps, and sets become views.
|
|
35
|
+
*/
|
|
36
|
+
export declare function viewValue(context: ViewContext, slot: Slot): unknown;
|
|
37
|
+
/**
|
|
38
|
+
* Read one path without building views for the nodes along it.
|
|
39
|
+
*
|
|
40
|
+
* The fastest way to answer a question like "what is the count", and the shape the framework
|
|
41
|
+
* bindings use for a selector.
|
|
42
|
+
*/
|
|
43
|
+
export declare function readPath(arena: SharedArena, root: Slot, path: readonly (string | number)[]): unknown;
|
|
44
|
+
export { VIEW_SLOT };
|
|
45
|
+
/**
|
|
46
|
+
* Compare two values by the arena node behind them.
|
|
47
|
+
*
|
|
48
|
+
* The default equality for a selector is `Object.is`, and for a selector that returns a
|
|
49
|
+
* container that means a notification on every commit: each commit produces a new snapshot
|
|
50
|
+
* with a fresh decode cache, so the view object is a new proxy even when the underlying
|
|
51
|
+
* subtree did not move. Comparing the slots instead answers the question the selector
|
|
52
|
+
* actually cares about, which is whether the subtree changed.
|
|
53
|
+
*
|
|
54
|
+
* Why comparing offsets is sound here, since it looks like it should not be. A commit
|
|
55
|
+
* encodes the new value before it frees anything the old version held, so a newly written
|
|
56
|
+
* node can never land on the block the current version is using. The value a selector last
|
|
57
|
+
* saw is the current version's node, so a later node reusing that block always compares
|
|
58
|
+
* unequal to it. The comparison dereferences nothing, so a wild offset cannot make it
|
|
59
|
+
* misbehave either.
|
|
60
|
+
*
|
|
61
|
+
* It is still a comparison of representation rather than of value. Two structurally equal
|
|
62
|
+
* subtrees written separately are different nodes and compare unequal, which is the
|
|
63
|
+
* conservative direction: an extra render, never a missed one.
|
|
64
|
+
*/
|
|
65
|
+
export declare function sameNode(a: unknown, b: unknown): boolean;
|
|
66
|
+
//# sourceMappingURL=view.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/view.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAI9C,OAAO,EAAe,KAAK,IAAI,EAAE,MAAM,aAAa,CAAC;AAKrD;;;;;;;;;;;;;;GAcG;AAEH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC;IAC9B,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,QAAA,MAAM,SAAS,eAA6B,CAAC;AAE7C,4EAA4E;AAC5E,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAI9C;AAED,mFAAmF;AACnF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,CAGzD;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAanE;AA8LD;;;;;GAKG;AACH,wBAAgB,QAAQ,CACtB,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GACjC,OAAO,CAeT;AAUD,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAMxD"}
|
package/dist/src/view.js
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { Tag } from "./tags.js";
|
|
2
|
+
import { ArenaCorruptError } from "./errors.js";
|
|
3
|
+
import { decodeString } from "./strings.js";
|
|
4
|
+
import { decodeValue } from "./values.js";
|
|
5
|
+
import { hamtEntries, hamtGet, hamtGetString, keyHash } from "./hamt.js";
|
|
6
|
+
import { vectorGet, vectorLength, vectorSlots } from "./vector.js";
|
|
7
|
+
import { hashString } from "./checksum.js";
|
|
8
|
+
const VIEW_SLOT = Symbol("globals.viewSlot");
|
|
9
|
+
/** True when the value is a lazy view rather than a plain decoded value. */
|
|
10
|
+
export function isView(value) {
|
|
11
|
+
return (value !== null && typeof value === "object" && value[VIEW_SLOT] !== undefined);
|
|
12
|
+
}
|
|
13
|
+
/** The slot a view is bound to, for callers that need the underlying reference. */
|
|
14
|
+
export function viewSlot(value) {
|
|
15
|
+
if (value === null || typeof value !== "object")
|
|
16
|
+
return undefined;
|
|
17
|
+
return value[VIEW_SLOT];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Decode a slot into a value, lazily for containers and eagerly for everything else.
|
|
21
|
+
*
|
|
22
|
+
* Scalars are cheaper to decode than to wrap, and a `Date` or a typed array has no useful
|
|
23
|
+
* lazy form, so only objects, arrays, maps, and sets become views.
|
|
24
|
+
*/
|
|
25
|
+
export function viewValue(context, slot) {
|
|
26
|
+
switch (slot.tag) {
|
|
27
|
+
case Tag.Object:
|
|
28
|
+
return objectView(context, slot);
|
|
29
|
+
case Tag.Array:
|
|
30
|
+
return arrayView(context, slot);
|
|
31
|
+
case Tag.Map:
|
|
32
|
+
return mapView(context, slot);
|
|
33
|
+
case Tag.Set:
|
|
34
|
+
return setView(context, slot);
|
|
35
|
+
default:
|
|
36
|
+
return decodeValue(context.arena, slot);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function cached(context, offset, build) {
|
|
40
|
+
const existing = context.cache.get(offset);
|
|
41
|
+
if (existing !== undefined)
|
|
42
|
+
return existing;
|
|
43
|
+
const created = build();
|
|
44
|
+
context.cache.set(offset, created);
|
|
45
|
+
return created;
|
|
46
|
+
}
|
|
47
|
+
function objectView(context, slot) {
|
|
48
|
+
return cached(context, slot.payload, () => {
|
|
49
|
+
const node = slot.payload;
|
|
50
|
+
let keys;
|
|
51
|
+
const listKeys = () => {
|
|
52
|
+
if (keys === undefined) {
|
|
53
|
+
keys = hamtEntries(context.arena, node).map((entry) => {
|
|
54
|
+
if (entry.key.tag !== Tag.String) {
|
|
55
|
+
throw new ArenaCorruptError("object key is not a string", { actual: entry.key.tag });
|
|
56
|
+
}
|
|
57
|
+
return decodeString(context.arena, entry.key.payload);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return keys;
|
|
61
|
+
};
|
|
62
|
+
// Interning is a write, so a reader cannot compare keys by offset the way the writer
|
|
63
|
+
// does. It walks the trie by hash instead and compares characters only against the one
|
|
64
|
+
// record it lands on, which keeps the lookup logarithmic.
|
|
65
|
+
const lookup = (property) => hamtGetString(context.arena, node, property, hashString(property));
|
|
66
|
+
return new Proxy({}, {
|
|
67
|
+
get(_target, property) {
|
|
68
|
+
if (property === VIEW_SLOT)
|
|
69
|
+
return slot;
|
|
70
|
+
if (property === "toJSON") {
|
|
71
|
+
return () => decodeValue(context.arena, slot);
|
|
72
|
+
}
|
|
73
|
+
if (typeof property === "symbol")
|
|
74
|
+
return undefined;
|
|
75
|
+
context.validate();
|
|
76
|
+
const found = lookup(property);
|
|
77
|
+
return found === undefined ? undefined : viewValue(context, found);
|
|
78
|
+
},
|
|
79
|
+
has(_target, property) {
|
|
80
|
+
if (typeof property === "symbol")
|
|
81
|
+
return false;
|
|
82
|
+
context.validate();
|
|
83
|
+
return lookup(property) !== undefined;
|
|
84
|
+
},
|
|
85
|
+
ownKeys() {
|
|
86
|
+
context.validate();
|
|
87
|
+
return listKeys();
|
|
88
|
+
},
|
|
89
|
+
getOwnPropertyDescriptor(_target, property) {
|
|
90
|
+
if (typeof property === "symbol")
|
|
91
|
+
return undefined;
|
|
92
|
+
context.validate();
|
|
93
|
+
const found = lookup(property);
|
|
94
|
+
if (found === undefined)
|
|
95
|
+
return undefined;
|
|
96
|
+
return {
|
|
97
|
+
configurable: true,
|
|
98
|
+
enumerable: true,
|
|
99
|
+
writable: false,
|
|
100
|
+
value: viewValue(context, found),
|
|
101
|
+
};
|
|
102
|
+
},
|
|
103
|
+
set() {
|
|
104
|
+
throw new TypeError("a snapshot is read only. Send a write through the owner instead, and remember it " +
|
|
105
|
+
"is asynchronous.");
|
|
106
|
+
},
|
|
107
|
+
deleteProperty() {
|
|
108
|
+
throw new TypeError("a snapshot is read only");
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function arrayView(context, slot) {
|
|
114
|
+
return cached(context, slot.payload, () => {
|
|
115
|
+
const vector = slot.payload;
|
|
116
|
+
return new Proxy([], {
|
|
117
|
+
get(_target, property) {
|
|
118
|
+
if (property === VIEW_SLOT)
|
|
119
|
+
return slot;
|
|
120
|
+
if (property === "length") {
|
|
121
|
+
context.validate();
|
|
122
|
+
return vectorLength(context.arena, vector);
|
|
123
|
+
}
|
|
124
|
+
if (property === "toJSON") {
|
|
125
|
+
return () => decodeValue(context.arena, slot);
|
|
126
|
+
}
|
|
127
|
+
if (typeof property === "symbol") {
|
|
128
|
+
if (property !== Symbol.iterator)
|
|
129
|
+
return undefined;
|
|
130
|
+
return function* iterate() {
|
|
131
|
+
context.validate();
|
|
132
|
+
const length = vectorLength(context.arena, vector);
|
|
133
|
+
for (let i = 0; i < length; i += 1) {
|
|
134
|
+
const element = vectorGet(context.arena, vector, i);
|
|
135
|
+
yield element === undefined ? undefined : viewValue(context, element);
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
if (/^\d+$/.test(property)) {
|
|
140
|
+
context.validate();
|
|
141
|
+
const element = vectorGet(context.arena, vector, Number(property));
|
|
142
|
+
return element === undefined ? undefined : viewValue(context, element);
|
|
143
|
+
}
|
|
144
|
+
// Array.prototype methods operate on the materialised array. Reimplementing them
|
|
145
|
+
// lazily would mean reimplementing the array protocol, and the differences would be
|
|
146
|
+
// found by users rather than by tests.
|
|
147
|
+
context.validate();
|
|
148
|
+
const materialised = vectorSlots(context.arena, vector).map((element) => viewValue(context, element));
|
|
149
|
+
const value = materialised[property];
|
|
150
|
+
return typeof value === "function" ? value.bind(materialised) : value;
|
|
151
|
+
},
|
|
152
|
+
has(_target, property) {
|
|
153
|
+
if (property === "length")
|
|
154
|
+
return true;
|
|
155
|
+
if (typeof property === "symbol")
|
|
156
|
+
return false;
|
|
157
|
+
if (!/^\d+$/.test(property))
|
|
158
|
+
return false;
|
|
159
|
+
context.validate();
|
|
160
|
+
return Number(property) < vectorLength(context.arena, vector);
|
|
161
|
+
},
|
|
162
|
+
ownKeys() {
|
|
163
|
+
context.validate();
|
|
164
|
+
const length = vectorLength(context.arena, vector);
|
|
165
|
+
return [...Array.from({ length }, (_unused, index) => String(index)), "length"];
|
|
166
|
+
},
|
|
167
|
+
getOwnPropertyDescriptor(_target, property) {
|
|
168
|
+
context.validate();
|
|
169
|
+
if (property === "length") {
|
|
170
|
+
return {
|
|
171
|
+
configurable: false,
|
|
172
|
+
enumerable: false,
|
|
173
|
+
writable: false,
|
|
174
|
+
value: vectorLength(context.arena, vector),
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
if (typeof property === "symbol" || !/^\d+$/.test(property))
|
|
178
|
+
return undefined;
|
|
179
|
+
const element = vectorGet(context.arena, vector, Number(property));
|
|
180
|
+
if (element === undefined)
|
|
181
|
+
return undefined;
|
|
182
|
+
return {
|
|
183
|
+
configurable: true,
|
|
184
|
+
enumerable: true,
|
|
185
|
+
writable: false,
|
|
186
|
+
value: viewValue(context, element),
|
|
187
|
+
};
|
|
188
|
+
},
|
|
189
|
+
set() {
|
|
190
|
+
throw new TypeError("a snapshot is read only");
|
|
191
|
+
},
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Maps and sets are materialised rather than proxied.
|
|
197
|
+
*
|
|
198
|
+
* A lazy Map would have to be a real Map to satisfy `instanceof` and the iteration protocol,
|
|
199
|
+
* and a subclass that decodes on `get` cannot intercept `size` or the iterators without
|
|
200
|
+
* surprising anyone who passes it to a library. Materialising is the honest option, and it
|
|
201
|
+
* is memoised per version so it happens once.
|
|
202
|
+
*/
|
|
203
|
+
function mapView(context, slot) {
|
|
204
|
+
return cached(context, slot.payload, () => {
|
|
205
|
+
context.validate();
|
|
206
|
+
return new Map(hamtEntries(context.arena, slot.payload).map((entry) => [
|
|
207
|
+
decodeValue(context.arena, entry.key),
|
|
208
|
+
viewValue(context, entry.value),
|
|
209
|
+
]));
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
function setView(context, slot) {
|
|
213
|
+
return cached(context, slot.payload, () => {
|
|
214
|
+
context.validate();
|
|
215
|
+
return new Set(hamtEntries(context.arena, slot.payload).map((entry) => decodeValue(context.arena, entry.key)));
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Read one path without building views for the nodes along it.
|
|
220
|
+
*
|
|
221
|
+
* The fastest way to answer a question like "what is the count", and the shape the framework
|
|
222
|
+
* bindings use for a selector.
|
|
223
|
+
*/
|
|
224
|
+
export function readPath(arena, root, path) {
|
|
225
|
+
let slot = root;
|
|
226
|
+
for (const step of path) {
|
|
227
|
+
if (slot === undefined)
|
|
228
|
+
return undefined;
|
|
229
|
+
if (slot.tag === Tag.Array) {
|
|
230
|
+
slot = vectorGet(arena, slot.payload, Number(step));
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
if (slot.tag === Tag.Object || slot.tag === Tag.Map) {
|
|
234
|
+
slot = lookupSlot(arena, slot.payload, step);
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
return undefined;
|
|
238
|
+
}
|
|
239
|
+
return slot === undefined ? undefined : decodeValue(arena, slot);
|
|
240
|
+
}
|
|
241
|
+
function lookupSlot(arena, node, key) {
|
|
242
|
+
if (typeof key === "number") {
|
|
243
|
+
const slot = { tag: Tag.Int32, payload: key };
|
|
244
|
+
return hamtGet(arena, node, slot, keyHash(arena, slot));
|
|
245
|
+
}
|
|
246
|
+
return hamtGetString(arena, node, key, hashString(key));
|
|
247
|
+
}
|
|
248
|
+
export { VIEW_SLOT };
|
|
249
|
+
/**
|
|
250
|
+
* Compare two values by the arena node behind them.
|
|
251
|
+
*
|
|
252
|
+
* The default equality for a selector is `Object.is`, and for a selector that returns a
|
|
253
|
+
* container that means a notification on every commit: each commit produces a new snapshot
|
|
254
|
+
* with a fresh decode cache, so the view object is a new proxy even when the underlying
|
|
255
|
+
* subtree did not move. Comparing the slots instead answers the question the selector
|
|
256
|
+
* actually cares about, which is whether the subtree changed.
|
|
257
|
+
*
|
|
258
|
+
* Why comparing offsets is sound here, since it looks like it should not be. A commit
|
|
259
|
+
* encodes the new value before it frees anything the old version held, so a newly written
|
|
260
|
+
* node can never land on the block the current version is using. The value a selector last
|
|
261
|
+
* saw is the current version's node, so a later node reusing that block always compares
|
|
262
|
+
* unequal to it. The comparison dereferences nothing, so a wild offset cannot make it
|
|
263
|
+
* misbehave either.
|
|
264
|
+
*
|
|
265
|
+
* It is still a comparison of representation rather than of value. Two structurally equal
|
|
266
|
+
* subtrees written separately are different nodes and compare unequal, which is the
|
|
267
|
+
* conservative direction: an extra render, never a missed one.
|
|
268
|
+
*/
|
|
269
|
+
export function sameNode(a, b) {
|
|
270
|
+
if (Object.is(a, b))
|
|
271
|
+
return true;
|
|
272
|
+
const left = viewSlot(a);
|
|
273
|
+
const right = viewSlot(b);
|
|
274
|
+
if (left === undefined || right === undefined)
|
|
275
|
+
return false;
|
|
276
|
+
return left.tag === right.tag && left.payload === right.payload;
|
|
277
|
+
}
|
|
278
|
+
//# sourceMappingURL=view.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view.js","sourceRoot":"","sources":["../../src/view.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bradensbay/globals-core",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Runtime agnostic shared memory arena: tagged value encoding, persistent data structures, epoch based reclamation.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/src/index.js",
|
|
7
|
+
"types": "./dist/src/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/src/index.d.ts",
|
|
11
|
+
"import": "./dist/src/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist/src",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=20.11.0"
|
|
20
|
+
},
|
|
21
|
+
"sideEffects": false,
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/christianGRogers/globals.git",
|
|
26
|
+
"directory": "packages/core"
|
|
27
|
+
}
|
|
28
|
+
}
|