@amritk/nish-x86_64-linux 0.17.0 → 0.20.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.
Files changed (61) hide show
  1. package/INSTALL.md +43 -25
  2. package/bin/nish +0 -0
  3. package/package.json +2 -2
  4. package/runtime/nish.d.ts +55 -5
  5. package/runtime/nish.h +231 -20
  6. package/runtime/nish.mjs +16 -0
  7. package/runtime/runtime-aes.c +490 -0
  8. package/runtime/runtime-cross.c +366 -0
  9. package/runtime/runtime-host.c +7 -6
  10. package/runtime/runtime-net.c +93 -34
  11. package/runtime/runtime-os.c +213 -15
  12. package/runtime/runtime-parallel.c +590 -107
  13. package/runtime/runtime-simd.c +203 -0
  14. package/runtime/runtime-wasm.c +16 -3
  15. package/runtime/runtime.c +89 -23
  16. package/runtime/shim.mjs +71 -1
  17. package/scripts/build.sh +225 -20
  18. package/std/README.md +86 -55
  19. package/std/bytes.ts +163 -0
  20. package/std/crypto/LICENSE-libsecp256k1 +19 -0
  21. package/std/crypto/aes.ts +238 -76
  22. package/std/crypto/chacha20poly1305.ts +43 -9
  23. package/std/crypto/ed25519.ts +840 -0
  24. package/std/crypto/hkdf.ts +304 -12
  25. package/std/crypto/hmac.ts +245 -53
  26. package/std/crypto/p256.ts +1376 -42
  27. package/std/crypto/x25519.ts +55 -37
  28. package/std/crypto/x509-random.ts +71 -0
  29. package/std/crypto/x509.ts +9 -9
  30. package/std/json-tokenizer.ts +1296 -0
  31. package/std/json-typed.ts +1014 -0
  32. package/std/json-value.ts +1163 -0
  33. package/std/json.ts +1412 -70
  34. package/std/net/buffer-pool.ts +151 -0
  35. package/std/net/hpack.ts +416 -112
  36. package/std/net/http-fields.ts +93 -0
  37. package/std/net/http1-server.ts +417 -55
  38. package/std/net/http1.ts +31 -6
  39. package/std/net/http2-tls.ts +112 -24
  40. package/std/net/http2.ts +333 -75
  41. package/std/net/http3-server.ts +231 -45
  42. package/std/net/http3.ts +187 -28
  43. package/std/net/prefork.ts +412 -0
  44. package/std/net/quic-conn-params.ts +86 -16
  45. package/std/net/quic-listener.ts +576 -219
  46. package/std/net/quic-packet.ts +443 -58
  47. package/std/net/quic-recovery.ts +361 -30
  48. package/std/net/quic-stream.ts +434 -28
  49. package/std/net/quic.ts +922 -206
  50. package/std/net/router.ts +676 -0
  51. package/std/net/tls/codec.ts +426 -27
  52. package/std/net/tls/record-server.ts +478 -132
  53. package/std/net/tls/record.ts +133 -42
  54. package/std/net/tls/schedule.ts +464 -55
  55. package/std/net/tls/ticket.ts +610 -0
  56. package/std/net/tls-tcp.ts +204 -57
  57. package/std/net/tls.ts +1132 -305
  58. package/std/net/url.ts +571 -0
  59. package/std/random.ts +94 -0
  60. package/std/text.ts +77 -0
  61. package/std/threads.ts +438 -14
@@ -0,0 +1,1163 @@
1
+ /**
2
+ * `nish/json-value` — any JSON document as a tree a program can read, build
3
+ * and write back, with every number kept as the text it was written in.
4
+ *
5
+ * `nish/json-typed` reads JSON into a class the program declares, which is the
6
+ * fast and safe way when the shape is known. This module is for when it is
7
+ * not: a configuration file, a proxy that rewrites one field and passes the
8
+ * rest through, a tool that prints whatever it was given.
9
+ *
10
+ * import { JsonDocument, JSON_VALUE_NUMBER } from "nish/json-value"
11
+ * import { JsonLimits } from "nish/json-tokenizer"
12
+ *
13
+ * const doc = new JsonDocument(new JsonLimits())
14
+ * const root = doc.parseText('{"id":18446744073709551615,"tags":["a","b"]}')
15
+ * if (root < 0) {
16
+ * // a JSON_TOK_ERR_* code, or JSON_VALUE_ERR_DUPLICATE; the byte is doc.errorAt
17
+ * }
18
+ * const id = doc.get(root, "id")
19
+ * doc.kind(id) === JSON_VALUE_NUMBER // true
20
+ * doc.isU64(id) // true; doc.isI64(id) is false
21
+ * doc.numberText(id) // "18446744073709551615", as written
22
+ * doc.stringify(root) // the same text back, byte for byte
23
+ *
24
+ * **A value is a handle.** `JsonValue` is an `i32` naming one value of the
25
+ * document that made it, and every reader and builder is a method of that
26
+ * document. A handle stays valid until the document parses again or is
27
+ * `clear`ed, which forgets every value at once and keeps the memory: the
28
+ * nodes, the member slots and the bytes of every string and number live in a
29
+ * handful of arrays the document owns and reuses. A server keeps one document
30
+ * and parses each request into it, and once the arrays have grown to the
31
+ * largest request seen, parsing allocates nothing.
32
+ *
33
+ * A handle carries the generation of the document's contents it was made in,
34
+ * which moves on at every `parse` and `clear`, so a handle kept from an
35
+ * earlier request names nothing in the next one, even when the next one has
36
+ * the same shape: it is `JSON_VALUE_NONE` to `kind`, and every reader answers
37
+ * its empty value for it rather than another document's. The generation has
38
+ * 511 values and moves by one at a `clear`, one at a parse and two at a parse
39
+ * that fails, so the check misses only a handle kept across exactly a
40
+ * multiple of 511 of those steps; a program must not keep handles across
41
+ * documents, and this catches the mistake rather than licensing it. A
42
+ * negative handle, or one past the last value, is `JSON_VALUE_NONE` too.
43
+ *
44
+ * **The document's size is bounded.** Each value costs about 46 bytes of the
45
+ * arrays the document keeps for its life, on top of the decoded text of its
46
+ * strings, keys and numbers, which `JsonLimits.maxTotalBytes` bounds through
47
+ * the input (`docs/security/json.md`, JSON-10). `maxValues` caps the first
48
+ * part by capping how many values one document holds:
49
+ * `JSON_VALUE_DEFAULT_MAX_VALUES` unless the program sets it, at most
50
+ * `JSON_VALUE_MAX_VALUES`. A parse that would make one more is
51
+ * `JSON_VALUE_ERR_VALUES` at the byte of the value that does not fit, and a
52
+ * builder answers the same code.
53
+ *
54
+ * **Numbers are lossless.** A number keeps its source text, and is read as
55
+ * whatever the caller asks for when it asks: `i64` and `u64` when the text is
56
+ * an integer that fits (`isI64`, `isU64`), the nearest `f64` (`f64`, correctly
57
+ * rounded, the tokenizer's `numberF64`), or the text itself (`numberText`).
58
+ * Writing it back copies the text. So `18446744073709551616`, wider than any
59
+ * integer type, and `0.1000000000000000055511151231257827`, more digits than an
60
+ * `f64` holds, come back out exactly as they went in, where JavaScript's
61
+ * `JSON.parse` turns both into the nearest double.
62
+ *
63
+ * **Objects keep insertion order**, the order the members were written in or
64
+ * added. `get` finds a member by its key with a scan, so it is for a handful of
65
+ * lookups per object; a program that looks up many keys of a large object
66
+ * walks it once with `keyAt` and `at`.
67
+ *
68
+ * **Duplicate keys are refused by default.** `{"a":1,"a":2}` is
69
+ * `JSON_VALUE_ERR_DUPLICATE`, with `errorAt` at the first key that repeats an
70
+ * earlier one, because two readers that pick different members of the same
71
+ * text are a check bypassed (`docs/security/json.md`, JSON-3), and refusing
72
+ * is what `nish/json-typed` does too. A program that has to accept what
73
+ * `JSON.parse` accepts sets `duplicates` to `JSON_VALUE_DUPLICATE_LAST`, and
74
+ * gets `JSON.parse`'s answer: one member, at the place of the first, holding
75
+ * the value of the last. The check sorts each object's keys, so an object of
76
+ * n members costs n log n comparisons whatever the keys are.
77
+ *
78
+ * **Every limit and every parse error is the tokenizer's.** `parse` runs a
79
+ * `JsonTokenizer` with the `JsonLimits` the document was made with, and
80
+ * answers its `JSON_TOK_ERR_*` code and offset unchanged. The depth limit is
81
+ * capped at `JSON_WRITER_MAX_DEPTH`, 64, so that every document a parse
82
+ * accepts can be written back; a deeper one is the tokenizer's
83
+ * `JSON_TOK_ERR_DEPTH`. Nothing an input holds panics, and the parse keeps its
84
+ * own stack of open containers rather than recursing.
85
+ *
86
+ * **Writing goes through `JsonWriter`.** `write(v, w)` writes a value into a
87
+ * writer the caller set up, so its buffer, its reuse and its sticky
88
+ * `JSON_WRITE_*` codes are the writer's own, and `stringify` is a convenience
89
+ * that sizes a buffer and answers a string. Strings come out as `JsonWriter`
90
+ * escapes them, which is `JSON.stringify`'s rule, numbers as their text, and
91
+ * members in order. Only a built tree can be deeper than
92
+ * `JSON_WRITER_MAX_DEPTH`, and writing one is the writer's
93
+ * `JSON_WRITE_TOO_DEEP`.
94
+ *
95
+ * **Building a tree** is a `new*` call per value, then `push` onto an array or
96
+ * `set` on an object, each answering `JSON_VALUE_OK` or a negative code. A
97
+ * value lives in at most one container, so a tree built through `push` and
98
+ * `set` can never contain itself: adding a value that is already in a
99
+ * container, or a container to itself or to anything inside it, is
100
+ * `JSON_VALUE_ERR_ATTACHED`, and writing always ends.
101
+ * Strings handed to a builder are taken as their bytes, as `JsonWriter` takes
102
+ * them, and a string read back is made from the stored bytes in one
103
+ * allocation (`String.fromBytes`). Under Node a string is UTF-16, and
104
+ * `parseText` and the builders take one byte per code unit, so non-ASCII text
105
+ * is stored differently there than natively, where a string is its UTF-8
106
+ * bytes; `parse` over a `u8[]` reads the same bytes both ways.
107
+ *
108
+ * **Public is not the whole API.** Nish has no private members, so the
109
+ * methods marked "Internal" in their comments, and the fields, are reachable
110
+ * by a program; the guarantees above hold only through the methods that are
111
+ * not marked so. `append` with indices of the program's choosing, for
112
+ * example, skips the check that keeps a tree finite.
113
+ *
114
+ * Every name here is `json`-prefixed, because a `std/` module is compiled into
115
+ * the program that imports it and the symbol namespace is flat
116
+ * (`std/README.md`). Every offset, count and code is an `i32`, so the module is
117
+ * the same under `--number-mode f64`, and it runs under the Node prelude, where
118
+ * `tests/run.js` holds every method to the native answers.
119
+ */
120
+ import { JSON_WRITE_FULL, JSON_WRITE_OK, JSON_WRITER_MAX_DEPTH, JsonWriter } from "nish/json"
121
+ import {
122
+ JSON_TOK_ARRAY_BEGIN,
123
+ JSON_TOK_ARRAY_END,
124
+ JSON_TOK_END,
125
+ JSON_TOK_KEY,
126
+ JSON_TOK_NULL,
127
+ JSON_TOK_NUMBER,
128
+ JSON_TOK_OBJECT_BEGIN,
129
+ JSON_TOK_OBJECT_END,
130
+ JSON_TOK_STRING,
131
+ JSON_TOK_TRUE,
132
+ JsonLimits,
133
+ JsonTokenizer,
134
+ } from "nish/json-tokenizer"
135
+
136
+ /** A value in a `JsonDocument`: an index into it, valid until the document parses again or is cleared. */
137
+ export type JsonValue = i32
138
+
139
+ /** What `kind` answers for a handle that names no value. */
140
+ export const JSON_VALUE_NONE: i32 = 0
141
+ export const JSON_VALUE_NULL: i32 = 1
142
+ export const JSON_VALUE_BOOLEAN: i32 = 2
143
+ /** A number, kept as its text: `numberText`, `isI64`, `i64`, `isU64`, `u64` and `f64` read it. */
144
+ export const JSON_VALUE_NUMBER: i32 = 3
145
+ export const JSON_VALUE_STRING: i32 = 4
146
+ export const JSON_VALUE_ARRAY: i32 = 5
147
+ export const JSON_VALUE_OBJECT: i32 = 6
148
+
149
+ /** What a builder answers when it did what it was asked. */
150
+ export const JSON_VALUE_OK: i32 = 0
151
+ /** A key an object already has, refused while `duplicates` is `JSON_VALUE_DUPLICATE_REFUSE`. */
152
+ export const JSON_VALUE_ERR_DUPLICATE: i32 = -30
153
+ /** A handle that names no value, or a value of the wrong kind: `push` onto an object, `set` on an array. */
154
+ export const JSON_VALUE_ERR_HANDLE: i32 = -31
155
+ /** A value already in a container, or a container added to itself or to a value inside it. */
156
+ export const JSON_VALUE_ERR_ATTACHED: i32 = -32
157
+ /** Text that is not one JSON number, for `newNumber`, or an `f64` that is NaN or an infinity, for `newF64`. */
158
+ export const JSON_VALUE_ERR_NUMBER: i32 = -33
159
+ /** One value more than `JsonDocument.maxValues`, by a parse (with `errorAt` at its first byte) or a builder. */
160
+ export const JSON_VALUE_ERR_VALUES: i32 = -34
161
+
162
+ /**
163
+ * The most values one document holds by default: a parse that would make
164
+ * more is `JSON_VALUE_ERR_VALUES`. Each value costs the document about 46
165
+ * bytes of arrays it keeps (`docs/security/json.md`, JSON-10), so this caps
166
+ * them near 12 MB; a program raises `maxValues` up to
167
+ * `JSON_VALUE_MAX_VALUES` for larger documents.
168
+ */
169
+ export const JSON_VALUE_DEFAULT_MAX_VALUES: i32 = 262144
170
+ /** The most `maxValues` can be: a handle keeps a value's index in its low 22 bits. */
171
+ export const JSON_VALUE_MAX_VALUES: i32 = 4194304
172
+
173
+ /** The default: a repeated key is `JSON_VALUE_ERR_DUPLICATE`. */
174
+ export const JSON_VALUE_DUPLICATE_REFUSE: i32 = 0
175
+ /** `JSON.parse`'s rule: one member, at the first key's place, with the last key's value. */
176
+ export const JSON_VALUE_DUPLICATE_LAST: i32 = 1
177
+
178
+ /**
179
+ * A handle is `generation << JSON_VALUE_INDEX_BITS | index`. The generation
180
+ * runs from 1 to `JSON_VALUE_LAST_GENERATION` and moves on by one at every
181
+ * `clear` and every parse, two at a parse that fails, so a handle kept from an
182
+ * earlier document names nothing in this one, unless exactly a multiple of
183
+ * 511 of those steps have passed.
184
+ */
185
+ const JSON_VALUE_INDEX_BITS: i32 = 22
186
+ const JSON_VALUE_INDEX_MASK: i32 = 4194303
187
+ const JSON_VALUE_LAST_GENERATION: i32 = 511
188
+ /** At most this many members are checked for duplicates pair by pair; a larger object is sorted. */
189
+ const JSON_VALUE_PAIRWISE: i32 = 8
190
+ /** How many member slots a built container gets when it first grows. */
191
+ const JSON_VALUE_FIRST_SLOTS: i32 = 4
192
+ /** The largest an `i32` count may be, which every limit of the number reader is set to. */
193
+ const JSON_VALUE_I32_MAX: i32 = 2147483647
194
+ const JSON_VALUE_DIGIT_0: i32 = 48
195
+ /** The words of a value with nothing to point at, and a `true` boolean's first word; spelled `i32` for `--number-mode f64`. */
196
+ const JSON_VALUE_NO_WORD: i32 = 0
197
+ const JSON_VALUE_TRUE_WORD: i32 = 1
198
+ const JSON_VALUE_MINUS: i32 = 45
199
+
200
+ /**
201
+ * A JSON tree, and the memory every value of it lives in. Make one, then
202
+ * `parse` into it or build with the `new*` methods; the module header has the
203
+ * rules. Its fields and its "Internal" methods are reachable, as every
204
+ * member in Nish is; use the others.
205
+ */
206
+ export class JsonDocument {
207
+ /** Per value: its `JSON_VALUE_*` kind. */
208
+ kinds: u8[]
209
+ /** Per value: a string's or a number's first byte in `bytes`, a container's first slot, a boolean's `0` or `1`. */
210
+ first: i32[]
211
+ /** Per value: a string's or a number's byte count, or a container's member count. */
212
+ count: i32[]
213
+ /** Per value: how many slots a container has from `first`, its members and room to grow. */
214
+ room: i32[]
215
+ /** Per value: the container it is in, or `-1`. */
216
+ parent: i32[]
217
+ /** Per member slot: the member's value, and an object member's key as a window of `bytes`. */
218
+ slotValue: i32[]
219
+ slotKeyAt: i32[]
220
+ slotKeyLength: i32[]
221
+ /** The bytes of every string, key and number, decoded, one after the other. */
222
+ bytes: u8[]
223
+ /**
224
+ * The parse's own stacks: the open containers, where each one's members
225
+ * start in the pending arrays and the key it is the value of, if any; and
226
+ * the pending arrays, which hold every member read and not yet
227
+ * placed, with its key and the key's source offset. The sort arrays are the
228
+ * duplicate check's. All of them keep their length from one parse to the
229
+ * next, which is what lets a parse allocate nothing.
230
+ */
231
+ openValue: i32[]
232
+ openBase: i32[]
233
+ openKeyAt: i32[]
234
+ openKeyLength: i32[]
235
+ openKeySource: i32[]
236
+ pendingValue: i32[]
237
+ pendingKeyAt: i32[]
238
+ pendingKeyLength: i32[]
239
+ pendingSource: i32[]
240
+ sortA: i32[]
241
+ sortB: i32[]
242
+ /** `parseText`'s copy of its string. */
243
+ textBytes: u8[]
244
+ tok: JsonTokenizer
245
+ /** A tokenizer over one stored number at a time, for `isI64`, `i64` and `f64`, limited only by `i32`. */
246
+ numbers: JsonTokenizer
247
+
248
+ /** `JSON_VALUE_DUPLICATE_REFUSE` or `JSON_VALUE_DUPLICATE_LAST`; read by `parse`. */
249
+ duplicates: i32 = 0
250
+ /** The last `parse`'s code: `0`, a `JSON_TOK_ERR_*` code or `JSON_VALUE_ERR_DUPLICATE`. */
251
+ failed: i32 = 0
252
+ /** The byte offset in the parsed array the error was found at, and `-1` until one. */
253
+ errorAt: i32 = -1
254
+ /** How many values are in use: the handles are `0 .. top - 1`. */
255
+ top: i32 = 0
256
+ /** How many member slots are in use, and how many bytes. */
257
+ slotTop: i32 = 0
258
+ byteTop: i32 = 0
259
+ /** How many members are pending. */
260
+ pendingTop: i32 = 0
261
+ /** The most values the document holds; more is `JSON_VALUE_ERR_VALUES`. At most `JSON_VALUE_MAX_VALUES`. */
262
+ maxValues: i32 = 0
263
+ /** The generation every handle of the current document carries; see `JSON_VALUE_INDEX_BITS`. */
264
+ generation: i32 = 1
265
+ /** Whether the last `unsigned` read a number that fits a `u64`. */
266
+ unsignedFits: boolean = false
267
+
268
+ constructor(limits: JsonLimits) {
269
+ this.maxValues = JSON_VALUE_DEFAULT_MAX_VALUES
270
+ this.kinds = []
271
+ this.first = []
272
+ this.count = []
273
+ this.room = []
274
+ this.parent = []
275
+ this.slotValue = []
276
+ this.slotKeyAt = []
277
+ this.slotKeyLength = []
278
+ this.bytes = []
279
+ this.openValue = []
280
+ this.openBase = []
281
+ this.openKeyAt = []
282
+ this.openKeyLength = []
283
+ this.openKeySource = []
284
+ this.pendingValue = []
285
+ this.pendingKeyAt = []
286
+ this.pendingKeyLength = []
287
+ this.pendingSource = []
288
+ this.sortA = []
289
+ this.sortB = []
290
+ this.textBytes = []
291
+ // The writer nests 64 deep, so a parsed document is held to that too:
292
+ // every document a parse accepts can be written back.
293
+ const capped = new JsonLimits()
294
+ capped.maxDepth = limits.maxDepth < JSON_WRITER_MAX_DEPTH ? limits.maxDepth : JSON_WRITER_MAX_DEPTH
295
+ capped.maxStringBytes = limits.maxStringBytes
296
+ capped.maxNumberBytes = limits.maxNumberBytes
297
+ capped.maxTotalBytes = limits.maxTotalBytes
298
+ this.tok = new JsonTokenizer(this.bytes, 0, 0, capped)
299
+ const wide = new JsonLimits()
300
+ wide.maxDepth = 0
301
+ wide.maxNumberBytes = JSON_VALUE_I32_MAX
302
+ wide.maxTotalBytes = JSON_VALUE_I32_MAX
303
+ this.numbers = new JsonTokenizer(this.bytes, 0, 0, wide)
304
+ }
305
+
306
+ /** Forgets every value, keeping the memory for the next parse or build. Every handle is invalid afterwards. */
307
+ clear(): void {
308
+ this.generation = this.generation >= JSON_VALUE_LAST_GENERATION ? 1 : this.generation + 1
309
+ this.top = 0
310
+ this.slotTop = 0
311
+ this.byteTop = 0
312
+ this.pendingTop = 0
313
+ this.failed = 0
314
+ this.errorAt = -1
315
+ }
316
+
317
+ // ---- Parsing ----------------------------------------------------------------
318
+
319
+ /**
320
+ * Clears the document and parses `src[off, off + len)` into it. Answers the
321
+ * root value, or a negative code — the tokenizer's `JSON_TOK_ERR_*` or
322
+ * `JSON_VALUE_ERR_DUPLICATE` — which is also in `failed`, with the byte
323
+ * offset in `errorAt`. Nothing is kept from a parse that fails.
324
+ */
325
+ parse(src: u8[], off: i32, len: i32): JsonValue {
326
+ this.clear()
327
+ const tok: JsonTokenizer = this.tok
328
+ tok.reset(src, off, len)
329
+ let depth: i32 = 0
330
+ let root: i32 = -1
331
+ let keyAt: i32 = 0
332
+ let keyLength: i32 = 0
333
+ let keySource: i32 = 0
334
+ let k: i32 = tok.next()
335
+ while (k > 0) {
336
+ let v: i32 = -1
337
+ if (k === JSON_TOK_KEY) {
338
+ keySource = tok.tokStart
339
+ keyAt = this.byteTop
340
+ keyLength = this.storeString(tok)
341
+ } else if (k === JSON_TOK_OBJECT_BEGIN || k === JSON_TOK_ARRAY_BEGIN) {
342
+ const c: i32 = this.newNode(
343
+ k === JSON_TOK_OBJECT_BEGIN ? JSON_VALUE_OBJECT : JSON_VALUE_ARRAY,
344
+ JSON_VALUE_NO_WORD,
345
+ JSON_VALUE_NO_WORD
346
+ )
347
+ if (c < 0) {
348
+ return this.parseFailed(c, tok.tokStart)
349
+ }
350
+ jsonValuePut(this.openValue, depth, c)
351
+ jsonValuePut(this.openBase, depth, this.pendingTop)
352
+ jsonValuePut(this.openKeyAt, depth, keyAt)
353
+ jsonValuePut(this.openKeyLength, depth, keyLength)
354
+ jsonValuePut(this.openKeySource, depth, keySource)
355
+ depth += 1
356
+ } else if (k === JSON_TOK_OBJECT_END || k === JSON_TOK_ARRAY_END) {
357
+ depth -= 1
358
+ const c: i32 = jsonValueGet(this.openValue, depth)
359
+ const code: i32 = this.close(c, jsonValueGet(this.openBase, depth))
360
+ if (code < 0) {
361
+ return this.parseFailed(code, this.errorAt)
362
+ }
363
+ // The container's own key, read before its members' keys overwrote the three locals.
364
+ keyAt = jsonValueGet(this.openKeyAt, depth)
365
+ keyLength = jsonValueGet(this.openKeyLength, depth)
366
+ keySource = jsonValueGet(this.openKeySource, depth)
367
+ v = c
368
+ } else if (k === JSON_TOK_STRING) {
369
+ v = this.newNode(JSON_VALUE_STRING, this.byteTop, this.storeString(tok))
370
+ } else if (k === JSON_TOK_NUMBER) {
371
+ v = this.newNode(JSON_VALUE_NUMBER, this.byteTop, this.storeSource(tok))
372
+ } else if (k === JSON_TOK_NULL) {
373
+ v = this.newNode(JSON_VALUE_NULL, JSON_VALUE_NO_WORD, JSON_VALUE_NO_WORD)
374
+ } else {
375
+ v = this.newNode(
376
+ JSON_VALUE_BOOLEAN,
377
+ k === JSON_TOK_TRUE ? JSON_VALUE_TRUE_WORD : JSON_VALUE_NO_WORD,
378
+ JSON_VALUE_NO_WORD
379
+ )
380
+ }
381
+ // `-1` is a key or an opener, which place no value yet; below it, the value was refused.
382
+ if (v < -1) {
383
+ return this.parseFailed(v, tok.tokStart)
384
+ }
385
+ if (v >= 0) {
386
+ if (depth === 0) {
387
+ root = v
388
+ } else {
389
+ const p: i32 = this.pendingTop
390
+ jsonValuePut(this.pendingValue, p, v)
391
+ jsonValuePut(this.pendingKeyAt, p, keyAt)
392
+ jsonValuePut(this.pendingKeyLength, p, keyLength)
393
+ jsonValuePut(this.pendingSource, p, keySource)
394
+ this.pendingTop = p + 1
395
+ }
396
+ }
397
+ k = tok.next()
398
+ }
399
+ if (k < 0 || root < 0) {
400
+ return this.parseFailed(k < 0 ? k : JSON_VALUE_ERR_HANDLE, tok.errorAt)
401
+ }
402
+ return this.handle(root)
403
+ }
404
+
405
+ /** `parse` over the bytes of `s`, copied into an array the document reuses; `errorAt` is a byte offset in `s`. */
406
+ parseText(s: string): JsonValue {
407
+ const n: i32 = toI32(s.length)
408
+ const buf: u8[] = jsonValueRoom(this.textBytes, n)
409
+ this.textBytes = buf
410
+ for (let i: i32 = 0; i < n && i < toI32(buf.length); i += 1) {
411
+ buf[i] = toU8(s.charCodeAt(i))
412
+ }
413
+ return this.parse(buf, JSON_VALUE_NO_WORD, n)
414
+ }
415
+
416
+ /** Internal: Records a failed parse and forgets what it built. */
417
+ parseFailed(code: i32, at: i32): i32 {
418
+ this.clear()
419
+ this.failed = code
420
+ this.errorAt = at
421
+ return code
422
+ }
423
+
424
+ /**
425
+ * Internal: Places the members pending from `base` into container `c` as one run of
426
+ * slots, checking an object's keys for duplicates first. Answers `0`, or
427
+ * `JSON_VALUE_ERR_DUPLICATE` with `errorAt` set.
428
+ */
429
+ close(c: i32, base: i32): i32 {
430
+ let n: i32 = this.pendingTop - base
431
+ const object: boolean = this.kindAt(c) === JSON_VALUE_OBJECT
432
+ if (object && n > 1) {
433
+ const code: i32 = this.duplicateKeys(base, n)
434
+ if (code < 0) {
435
+ return code
436
+ }
437
+ }
438
+ const start: i32 = this.slotTop
439
+ let kept: i32 = 0
440
+ for (let p: i32 = base; p < base + n; p += 1) {
441
+ const v: i32 = jsonValueGet(this.pendingValue, p)
442
+ if (v < 0) {
443
+ continue
444
+ }
445
+ const s: i32 = start + kept
446
+ jsonValuePut(this.slotValue, s, v)
447
+ jsonValuePut(this.slotKeyAt, s, jsonValueGet(this.pendingKeyAt, p))
448
+ jsonValuePut(this.slotKeyLength, s, jsonValueGet(this.pendingKeyLength, p))
449
+ jsonValuePut(this.parent, v, c)
450
+ kept += 1
451
+ }
452
+ n = kept
453
+ this.slotTop = start + n
454
+ jsonValuePut(this.first, c, start)
455
+ jsonValuePut(this.count, c, n)
456
+ jsonValuePut(this.room, c, n)
457
+ this.pendingTop = base
458
+ return 0
459
+ }
460
+
461
+ /**
462
+ * Internal: The duplicate check over the `n` members pending from `base`. Under
463
+ * `JSON_VALUE_DUPLICATE_LAST`, a repeated key's later members are marked
464
+ * gone (their pending value set to `-1`) and the first one takes the last
465
+ * one's value. Small objects compare every pair; larger ones are sorted by
466
+ * key with ties in member order, so a key's repeats are next to each other
467
+ * and the first of them is its first member.
468
+ */
469
+ duplicateKeys(base: i32, n: i32): i32 {
470
+ let firstRepeat: i32 = -1
471
+ if (n <= JSON_VALUE_PAIRWISE) {
472
+ for (let i: i32 = base + 1; i < base + n; i += 1) {
473
+ for (let j: i32 = base; j < i; j += 1) {
474
+ if (jsonValueGet(this.pendingValue, j) >= 0 && this.samePendingKey(i, j)) {
475
+ firstRepeat = this.repeat(j, i, firstRepeat)
476
+ break
477
+ }
478
+ }
479
+ }
480
+ } else {
481
+ const order: i32[] = this.sortPending(base, n)
482
+ let i: i32 = 0
483
+ while (i < n) {
484
+ const head: i32 = jsonValueGet(order, i)
485
+ let j: i32 = i + 1
486
+ while (j < n && this.samePendingKey(head, jsonValueGet(order, j))) {
487
+ firstRepeat = this.repeat(head, jsonValueGet(order, j), firstRepeat)
488
+ j += 1
489
+ }
490
+ i = j
491
+ }
492
+ }
493
+ if (firstRepeat >= 0 && this.duplicates !== JSON_VALUE_DUPLICATE_LAST) {
494
+ this.errorAt = firstRepeat
495
+ return JSON_VALUE_ERR_DUPLICATE
496
+ }
497
+ return 0
498
+ }
499
+
500
+ /**
501
+ * Internal: Pending member `later` repeats the key of the earlier `head`: under
502
+ * `JSON_VALUE_DUPLICATE_LAST` `head` takes its value and it is marked gone.
503
+ * Answers the smallest source offset of a repeating key seen so far.
504
+ */
505
+ repeat(head: i32, later: i32, firstRepeat: i32): i32 {
506
+ const source: i32 = jsonValueGet(this.pendingSource, later)
507
+ if (this.duplicates === JSON_VALUE_DUPLICATE_LAST) {
508
+ jsonValuePut(this.pendingValue, head, jsonValueGet(this.pendingValue, later))
509
+ jsonValuePut(this.pendingValue, later, -1)
510
+ }
511
+ return firstRepeat < 0 || source < firstRepeat ? source : firstRepeat
512
+ }
513
+
514
+ /** Internal: Whether pending members `a` and `b` have the same key bytes. */
515
+ samePendingKey(a: i32, b: i32): boolean {
516
+ return this.comparePending(a, b) === 0
517
+ }
518
+
519
+ /**
520
+ * Internal: The pending indices `base .. base + n - 1` sorted by key, ties in index
521
+ * order: a bottom-up merge sort between the two sort arrays, which answers
522
+ * whichever of them holds the result.
523
+ */
524
+ sortPending(base: i32, n: i32): i32[] {
525
+ let from: i32[] = jsonValueRoomI32(this.sortA, n)
526
+ let to: i32[] = jsonValueRoomI32(this.sortB, n)
527
+ this.sortA = from
528
+ this.sortB = to
529
+ for (let i: i32 = 0; i < n && i < toI32(from.length); i += 1) {
530
+ from[i] = base + i
531
+ }
532
+ let width: i32 = 1
533
+ while (width < n) {
534
+ let lo: i32 = 0
535
+ while (lo < n) {
536
+ const mid: i32 = lo + width < n ? lo + width : n
537
+ const hi: i32 = mid + width < n ? mid + width : n
538
+ let a: i32 = lo
539
+ let b: i32 = mid
540
+ let out: i32 = lo
541
+ while (out < hi) {
542
+ const takeA: boolean =
543
+ b >= hi || (a < mid && this.comparePending(jsonValueGet(from, a), jsonValueGet(from, b)) <= 0)
544
+ if (takeA) {
545
+ jsonValuePut(to, out, jsonValueGet(from, a))
546
+ a += 1
547
+ } else {
548
+ jsonValuePut(to, out, jsonValueGet(from, b))
549
+ b += 1
550
+ }
551
+ out += 1
552
+ }
553
+ lo = hi
554
+ }
555
+ const swap: i32[] = from
556
+ from = to
557
+ to = swap
558
+ width = width * 2
559
+ }
560
+ return from
561
+ }
562
+
563
+ /** Internal: Pending members `a` and `b` ordered by key bytes. */
564
+ comparePending(a: i32, b: i32): i32 {
565
+ return jsonValueCompareBytes(
566
+ this.bytes,
567
+ jsonValueGet(this.pendingKeyAt, a),
568
+ jsonValueGet(this.pendingKeyLength, a),
569
+ jsonValueGet(this.pendingKeyAt, b),
570
+ jsonValueGet(this.pendingKeyLength, b)
571
+ )
572
+ }
573
+
574
+ /** Internal: The tokenizer's current string or key, decoded onto the end of `bytes`; answers its length. */
575
+ storeString(tok: JsonTokenizer): i32 {
576
+ const n: i32 = tok.stringLength()
577
+ const at: i32 = this.byteTop
578
+ const buf: u8[] = jsonValueRoom(this.bytes, at + n)
579
+ this.bytes = buf
580
+ tok.stringInto(buf, at)
581
+ this.byteTop = at + n
582
+ return n
583
+ }
584
+
585
+ /** Internal: The tokenizer's current token as written, a number's text, onto the end of `bytes`; answers its length. */
586
+ storeSource(tok: JsonTokenizer): i32 {
587
+ const src: u8[] = tok.src
588
+ const start: i32 = tok.tokStart
589
+ const n: i32 = tok.tokEnd - start
590
+ const at: i32 = this.byteTop
591
+ const buf: u8[] = jsonValueRoom(this.bytes, at + n)
592
+ this.bytes = buf
593
+ for (let i: i32 = 0; i < n && start + i < toI32(src.length) && at + i < toI32(buf.length); i += 1) {
594
+ if (start + i >= 0 && at + i >= 0) {
595
+ buf[at + i] = src[start + i]
596
+ }
597
+ }
598
+ this.byteTop = at + n
599
+ return n
600
+ }
601
+
602
+ /**
603
+ * Internal: a new value of `kind` with its two words, in no container, and
604
+ * its index; `JSON_VALUE_ERR_VALUES` when the document already holds
605
+ * `maxValues`.
606
+ */
607
+ newNode(kind: i32, first: i32, count: i32): i32 {
608
+ const v: i32 = this.top
609
+ const cap: i32 = this.maxValues < JSON_VALUE_MAX_VALUES ? this.maxValues : JSON_VALUE_MAX_VALUES
610
+ if (v >= cap) {
611
+ return JSON_VALUE_ERR_VALUES
612
+ }
613
+ if (v < toI32(this.kinds.length)) {
614
+ this.kinds[v] = toU8(kind)
615
+ } else {
616
+ this.kinds.push(toU8(kind))
617
+ }
618
+ jsonValuePut(this.first, v, first)
619
+ jsonValuePut(this.count, v, count)
620
+ jsonValuePut(this.room, v, 0)
621
+ jsonValuePut(this.parent, v, -1)
622
+ this.top = v + 1
623
+ return v
624
+ }
625
+
626
+ // ---- Handles ----------------------------------------------------------------
627
+
628
+ /** Internal: the index handle `v` names in this document, or `-1` when it names nothing here. */
629
+ index(v: JsonValue): i32 {
630
+ if (v < 0 || v >> JSON_VALUE_INDEX_BITS !== this.generation) {
631
+ return -1
632
+ }
633
+ const x: i32 = v & JSON_VALUE_INDEX_MASK
634
+ return x < this.top ? x : -1
635
+ }
636
+
637
+ /** Internal: the handle of index `x` in this document's generation; a negative `x` is answered as it is. */
638
+ handle(x: i32): JsonValue {
639
+ return x < 0 ? x : (this.generation << JSON_VALUE_INDEX_BITS) | x
640
+ }
641
+
642
+ // ---- Reading ----------------------------------------------------------------
643
+
644
+ /** `v`'s `JSON_VALUE_*` kind, or `JSON_VALUE_NONE` when `v` names no value of this document's current contents. */
645
+ kind(v: JsonValue): i32 {
646
+ return this.kindAt(this.index(v))
647
+ }
648
+
649
+ /** Internal: the kind of index `x`, or `JSON_VALUE_NONE`. */
650
+ kindAt(x: i32): i32 {
651
+ const kinds: u8[] = this.kinds
652
+ if (x < 0 || x >= this.top || x >= toI32(kinds.length)) {
653
+ return JSON_VALUE_NONE
654
+ }
655
+ return toI32(kinds[x])
656
+ }
657
+
658
+ /** A boolean's value; `false` for any other value. */
659
+ boolean(v: JsonValue): boolean {
660
+ const x: i32 = this.index(v)
661
+ return this.kindAt(x) === JSON_VALUE_BOOLEAN && jsonValueGet(this.first, x) === JSON_VALUE_TRUE_WORD
662
+ }
663
+
664
+ /** How many elements an array has, or members an object has; `-1` for any other value. */
665
+ length(v: JsonValue): i32 {
666
+ return this.lengthAt(this.index(v))
667
+ }
668
+
669
+ /** Internal: `length` of index `x`. */
670
+ lengthAt(x: i32): i32 {
671
+ const k: i32 = this.kindAt(x)
672
+ return k === JSON_VALUE_ARRAY || k === JSON_VALUE_OBJECT ? jsonValueGet(this.count, x) : -1
673
+ }
674
+
675
+ /** Internal: the slot of member or element `i` of the container at index `x`, or `-1`. */
676
+ slotAt(x: i32, i: i32): i32 {
677
+ if (i < 0 || i >= this.lengthAt(x)) {
678
+ return -1
679
+ }
680
+ return jsonValueGet(this.first, x) + i
681
+ }
682
+
683
+ /** Element `i` of an array, or the value of member `i` of an object, in order; `-1` when there is none. */
684
+ at(v: JsonValue, i: i32): JsonValue {
685
+ const s: i32 = this.slotAt(this.index(v), i)
686
+ return s < 0 ? -1 : this.handle(jsonValueGet(this.slotValue, s))
687
+ }
688
+
689
+ /** The key of member `i` of an object, decoded; `""` when `v` is not an object or has no member `i`. */
690
+ keyAt(v: JsonValue, i: i32): string {
691
+ const x: i32 = this.index(v)
692
+ if (this.kindAt(x) !== JSON_VALUE_OBJECT) {
693
+ return ""
694
+ }
695
+ const s: i32 = this.slotAt(x, i)
696
+ if (s < 0) {
697
+ return ""
698
+ }
699
+ return this.textOf(jsonValueGet(this.slotKeyAt, s), jsonValueGet(this.slotKeyLength, s))
700
+ }
701
+
702
+ /** The value of the member of object `v` whose key is `key`'s bytes; `-1` when there is none. */
703
+ get(v: JsonValue, key: string): JsonValue {
704
+ const x: i32 = this.index(v)
705
+ if (this.kindAt(x) !== JSON_VALUE_OBJECT) {
706
+ return -1
707
+ }
708
+ const s: i32 = this.findKey(x, key)
709
+ return s < 0 ? -1 : this.handle(jsonValueGet(this.slotValue, s))
710
+ }
711
+
712
+ /** Internal: the slot of the member of the object at index `x` whose key is `key`'s bytes, or `-1`. */
713
+ findKey(x: i32, key: string): i32 {
714
+ const start: i32 = jsonValueGet(this.first, x)
715
+ const n: i32 = jsonValueGet(this.count, x)
716
+ for (let s: i32 = start; s < start + n; s += 1) {
717
+ if (this.bytesEqual(jsonValueGet(this.slotKeyAt, s), jsonValueGet(this.slotKeyLength, s), key)) {
718
+ return s
719
+ }
720
+ }
721
+ return -1
722
+ }
723
+
724
+ /** A string's decoded bytes as a string; `""` for any other value. */
725
+ string(v: JsonValue): string {
726
+ const x: i32 = this.index(v)
727
+ if (this.kindAt(x) !== JSON_VALUE_STRING) {
728
+ return ""
729
+ }
730
+ return this.textOf(jsonValueGet(this.first, x), jsonValueGet(this.count, x))
731
+ }
732
+
733
+ /** Whether `v` is a string whose decoded bytes are `s`'s. Allocates nothing. */
734
+ stringEquals(v: JsonValue, s: string): boolean {
735
+ const x: i32 = this.index(v)
736
+ return (
737
+ this.kindAt(x) === JSON_VALUE_STRING &&
738
+ this.bytesEqual(jsonValueGet(this.first, x), jsonValueGet(this.count, x), s)
739
+ )
740
+ }
741
+
742
+ /** A number's text, exactly as it was written or built; `""` for any other value. */
743
+ numberText(v: JsonValue): string {
744
+ const x: i32 = this.index(v)
745
+ if (this.kindAt(x) !== JSON_VALUE_NUMBER) {
746
+ return ""
747
+ }
748
+ return this.textOf(jsonValueGet(this.first, x), jsonValueGet(this.count, x))
749
+ }
750
+
751
+ /** Whether `v` is a number written without a fraction or an exponent whose value fits an `i64`. */
752
+ isI64(v: JsonValue): boolean {
753
+ return this.readNumber(this.index(v)) && this.numbers.isInteger()
754
+ }
755
+
756
+ /** A number's value as an `i64` when `isI64(v)` holds, and `0` otherwise. */
757
+ i64(v: JsonValue): i64 {
758
+ // `numberI64` is already `0` for a number that is not an `i64`.
759
+ return this.readNumber(this.index(v)) ? this.numbers.numberI64() : toI64(0)
760
+ }
761
+
762
+ /** Whether `v` is a number written without a sign, a fraction or an exponent whose value fits a `u64`. */
763
+ isU64(v: JsonValue): boolean {
764
+ this.unsigned(this.index(v))
765
+ return this.unsignedFits
766
+ }
767
+
768
+ /** A number's value as a `u64` when `isU64(v)` holds, and `0` otherwise. */
769
+ u64(v: JsonValue): u64 {
770
+ return this.unsigned(this.index(v))
771
+ }
772
+
773
+ /**
774
+ * Internal: the digits of the number at index `x` as a `u64`, setting
775
+ * `unsignedFits` to whether it is a `u64` at all: no sign, no fraction or
776
+ * exponent, and at most 2^64 - 1. Every `u64` comes from `toU64`, which is
777
+ * a BigInt under Node, and nothing here wraps, so it means the same there.
778
+ */
779
+ unsigned(x: i32): u64 {
780
+ this.unsignedFits = false
781
+ if (!this.readNumber(x) || !this.numbers.integral) {
782
+ return toU64(0)
783
+ }
784
+ const bytes: u8[] = this.bytes
785
+ const start: i32 = jsonValueGet(this.first, x)
786
+ const end: i32 = start + jsonValueGet(this.count, x)
787
+ if (start < 0 || start >= toI32(bytes.length) || toI32(bytes[start]) === JSON_VALUE_MINUS) {
788
+ return toU64(0)
789
+ }
790
+ const ten: u64 = toU64(10)
791
+ // 2^64 - 1 has no literal: 2^16 - 1 widened twice.
792
+ const quarter: u64 = toU64(65535)
793
+ const half: u64 = (quarter << toU64(16)) | quarter
794
+ const max: u64 = (half << toU64(32)) | half
795
+ let acc: u64 = toU64(0)
796
+ for (let i: i32 = start; i < end && i < toI32(bytes.length); i += 1) {
797
+ const digit: u64 = toU64(toI32(bytes[i]) - JSON_VALUE_DIGIT_0)
798
+ if (acc > (max - digit) / ten) {
799
+ return toU64(0)
800
+ }
801
+ acc = acc * ten + digit
802
+ }
803
+ this.unsignedFits = true
804
+ return acc
805
+ }
806
+
807
+ /** A number's nearest `f64`, ties to even, as `JSON.parse` reads it; `0` for any other value. */
808
+ f64(v: JsonValue): f64 {
809
+ if (!this.readNumber(this.index(v))) {
810
+ return 0
811
+ }
812
+ return this.numbers.numberF64()
813
+ }
814
+
815
+ /** Internal: points the number tokenizer at index `x`'s text and reads its one token; `false` when it is not a number. */
816
+ readNumber(x: i32): boolean {
817
+ if (this.kindAt(x) !== JSON_VALUE_NUMBER) {
818
+ return false
819
+ }
820
+ const numbers: JsonTokenizer = this.numbers
821
+ numbers.reset(this.bytes, jsonValueGet(this.first, x), jsonValueGet(this.count, x))
822
+ return numbers.next() === JSON_TOK_NUMBER
823
+ }
824
+
825
+ /** Internal: `bytes[at, at + n)` as a string, in one allocation. */
826
+ textOf(at: i32, n: i32): string {
827
+ const bytes: u8[] = this.bytes
828
+ if (at < 0 || n <= 0 || at > toI32(bytes.length) - n) {
829
+ return ""
830
+ }
831
+ return String.fromBytes(bytes, at, at + n)
832
+ }
833
+
834
+ /** Internal: whether `bytes[at, at + n)` are exactly `s`'s bytes. */
835
+ bytesEqual(at: i32, n: i32, s: string): boolean {
836
+ const bytes: u8[] = this.bytes
837
+ if (toI32(s.length) !== n || at < 0 || at > toI32(bytes.length) - n) {
838
+ return false
839
+ }
840
+ for (let i: i32 = 0; i < n && i < toI32(s.length) && at + i < toI32(bytes.length); i += 1) {
841
+ if (toI32(bytes[at + i]) !== toI32(s.charCodeAt(i))) {
842
+ return false
843
+ }
844
+ }
845
+ return true
846
+ }
847
+
848
+ // ---- Building ---------------------------------------------------------------
849
+ // Each `new*` answers a handle, or `JSON_VALUE_ERR_VALUES` when the document
850
+ // already holds `maxValues`.
851
+
852
+ newNull(): JsonValue {
853
+ return this.handle(this.newNode(JSON_VALUE_NULL, JSON_VALUE_NO_WORD, JSON_VALUE_NO_WORD))
854
+ }
855
+
856
+ newBoolean(b: boolean): JsonValue {
857
+ return this.handle(
858
+ this.newNode(JSON_VALUE_BOOLEAN, b ? JSON_VALUE_TRUE_WORD : JSON_VALUE_NO_WORD, JSON_VALUE_NO_WORD)
859
+ )
860
+ }
861
+
862
+ /** A string holding `s`'s bytes. */
863
+ newString(s: string): JsonValue {
864
+ return this.newStored(JSON_VALUE_STRING, s)
865
+ }
866
+
867
+ /** A number holding `x`'s digits. */
868
+ newI64(x: i64): JsonValue {
869
+ return this.newStored(JSON_VALUE_NUMBER, `${x}`)
870
+ }
871
+
872
+ /** A number holding `x`'s digits. */
873
+ newU64(x: u64): JsonValue {
874
+ return this.newStored(JSON_VALUE_NUMBER, `${x}`)
875
+ }
876
+
877
+ /**
878
+ * A number holding `x` as `String(x)` spells it, the shortest digits that
879
+ * read back as `x`, with `-0` as `0`: what `JsonWriter.f64` writes.
880
+ * `JSON_VALUE_ERR_NUMBER` for NaN and both infinities, which JSON cannot
881
+ * spell.
882
+ */
883
+ newF64(x: f64): JsonValue {
884
+ // `x - x` is `0` for every finite `x`, and NaN for NaN and both infinities.
885
+ if (x - x !== toF64(0)) {
886
+ return JSON_VALUE_ERR_NUMBER
887
+ }
888
+ return this.newStored(JSON_VALUE_NUMBER, `${x}`)
889
+ }
890
+
891
+ /**
892
+ * A number holding `text` exactly, which must be one JSON number and
893
+ * nothing else (RFC 8259 §6); `JSON_VALUE_ERR_NUMBER` otherwise. This is how
894
+ * a program writes a number no integer or float type holds.
895
+ */
896
+ newNumber(text: string): JsonValue {
897
+ const at: i32 = this.byteTop
898
+ const n: i32 = this.storeText(text)
899
+ const numbers: JsonTokenizer = this.numbers
900
+ numbers.reset(this.bytes, at, n)
901
+ // The tokenizer allows blanks around a value, and a number here is the text alone.
902
+ const isNumber: boolean =
903
+ numbers.next() === JSON_TOK_NUMBER && numbers.tokStart === at && numbers.tokEnd === at + n
904
+ if (!isNumber || numbers.next() !== JSON_TOK_END) {
905
+ this.byteTop = at
906
+ return JSON_VALUE_ERR_NUMBER
907
+ }
908
+ return this.handle(this.newNode(JSON_VALUE_NUMBER, at, n))
909
+ }
910
+
911
+ newArray(): JsonValue {
912
+ return this.handle(this.newNode(JSON_VALUE_ARRAY, this.slotTop, JSON_VALUE_NO_WORD))
913
+ }
914
+
915
+ newObject(): JsonValue {
916
+ return this.handle(this.newNode(JSON_VALUE_OBJECT, this.slotTop, JSON_VALUE_NO_WORD))
917
+ }
918
+
919
+ /** Appends `v` to array `a`. `JSON_VALUE_OK`, or `JSON_VALUE_ERR_HANDLE` or `JSON_VALUE_ERR_ATTACHED`. */
920
+ push(a: JsonValue, v: JsonValue): i32 {
921
+ const ax: i32 = this.index(a)
922
+ const vx: i32 = this.index(v)
923
+ if (this.kindAt(ax) !== JSON_VALUE_ARRAY) {
924
+ return JSON_VALUE_ERR_HANDLE
925
+ }
926
+ const code: i32 = this.adoptable(ax, vx)
927
+ if (code < 0) {
928
+ return code
929
+ }
930
+ this.append(ax, vx, JSON_VALUE_NO_WORD, JSON_VALUE_NO_WORD)
931
+ return JSON_VALUE_OK
932
+ }
933
+
934
+ /**
935
+ * Sets member `key` of object `o` to `v`: in place, keeping its position,
936
+ * when `o` has the key, and appended last when it does not, as assigning a
937
+ * property of a JavaScript object does. The value it replaces leaves the
938
+ * object and is in no container afterwards. `JSON_VALUE_OK`, or
939
+ * `JSON_VALUE_ERR_HANDLE` or `JSON_VALUE_ERR_ATTACHED`.
940
+ */
941
+ set(o: JsonValue, key: string, v: JsonValue): i32 {
942
+ const ox: i32 = this.index(o)
943
+ const vx: i32 = this.index(v)
944
+ if (this.kindAt(ox) !== JSON_VALUE_OBJECT) {
945
+ return JSON_VALUE_ERR_HANDLE
946
+ }
947
+ const code: i32 = this.adoptable(ox, vx)
948
+ if (code < 0) {
949
+ return code
950
+ }
951
+ const s: i32 = this.findKey(ox, key)
952
+ if (s >= 0) {
953
+ jsonValuePut(this.parent, jsonValueGet(this.slotValue, s), -1)
954
+ jsonValuePut(this.slotValue, s, vx)
955
+ jsonValuePut(this.parent, vx, ox)
956
+ return JSON_VALUE_OK
957
+ }
958
+ this.append(ox, vx, this.byteTop, this.storeText(key))
959
+ return JSON_VALUE_OK
960
+ }
961
+
962
+ /**
963
+ * Internal: whether the value at index `v` may go into the container at
964
+ * index `c`: it is a value, it is in no container, and it is not `c` or a
965
+ * container `c` is inside. Through `push` and `set`, that is what keeps
966
+ * every tree finite.
967
+ */
968
+ adoptable(c: i32, v: i32): i32 {
969
+ if (this.kindAt(v) === JSON_VALUE_NONE) {
970
+ return JSON_VALUE_ERR_HANDLE
971
+ }
972
+ if (jsonValueGet(this.parent, v) >= 0) {
973
+ return JSON_VALUE_ERR_ATTACHED
974
+ }
975
+ let p: i32 = c
976
+ while (p >= 0) {
977
+ if (p === v) {
978
+ return JSON_VALUE_ERR_ATTACHED
979
+ }
980
+ p = jsonValueGet(this.parent, p)
981
+ }
982
+ return JSON_VALUE_OK
983
+ }
984
+
985
+ /**
986
+ * Internal: adds index `v`, with the key `bytes[keyAt, keyAt + keyLength)`,
987
+ * after the last member of index `c`, unchecked: `push` and `set` check
988
+ * first. A container whose slots are full moves them to the end of the slot
989
+ * arrays with twice the room, unless they are at the end already, where they
990
+ * grow in place; the slots it leaves are not reused until `clear`.
991
+ */
992
+ append(c: i32, v: i32, keyAt: i32, keyLength: i32): void {
993
+ let start: i32 = jsonValueGet(this.first, c)
994
+ const n: i32 = jsonValueGet(this.count, c)
995
+ const capacity: i32 = jsonValueGet(this.room, c)
996
+ if (n === capacity) {
997
+ const grown: i32 = capacity < JSON_VALUE_FIRST_SLOTS ? JSON_VALUE_FIRST_SLOTS : capacity * 2
998
+ if (start + capacity !== this.slotTop) {
999
+ const moved: i32 = this.slotTop
1000
+ for (let i: i32 = 0; i < n; i += 1) {
1001
+ jsonValuePut(this.slotValue, moved + i, jsonValueGet(this.slotValue, start + i))
1002
+ jsonValuePut(this.slotKeyAt, moved + i, jsonValueGet(this.slotKeyAt, start + i))
1003
+ jsonValuePut(this.slotKeyLength, moved + i, jsonValueGet(this.slotKeyLength, start + i))
1004
+ }
1005
+ start = moved
1006
+ jsonValuePut(this.first, c, start)
1007
+ }
1008
+ this.slotTop = start + grown
1009
+ this.slotValue = jsonValueRoomI32(this.slotValue, this.slotTop)
1010
+ this.slotKeyAt = jsonValueRoomI32(this.slotKeyAt, this.slotTop)
1011
+ this.slotKeyLength = jsonValueRoomI32(this.slotKeyLength, this.slotTop)
1012
+ jsonValuePut(this.room, c, grown)
1013
+ }
1014
+ jsonValuePut(this.slotValue, start + n, v)
1015
+ jsonValuePut(this.slotKeyAt, start + n, keyAt)
1016
+ jsonValuePut(this.slotKeyLength, start + n, keyLength)
1017
+ jsonValuePut(this.count, c, n + 1)
1018
+ jsonValuePut(this.parent, v, c)
1019
+ }
1020
+
1021
+ /** Internal: a new value of `kind` holding `s`'s bytes, as a handle. */
1022
+ newStored(kind: i32, s: string): JsonValue {
1023
+ return this.handle(this.newNode(kind, this.byteTop, this.storeText(s)))
1024
+ }
1025
+
1026
+ /** Internal: `s`'s bytes onto the end of `bytes`; answers how many. */
1027
+ storeText(s: string): i32 {
1028
+ const n: i32 = toI32(s.length)
1029
+ const at: i32 = this.byteTop
1030
+ const buf: u8[] = jsonValueRoom(this.bytes, at + n)
1031
+ this.bytes = buf
1032
+ for (let i: i32 = 0; i < n && at + i < toI32(buf.length); i += 1) {
1033
+ if (at + i >= 0) {
1034
+ buf[at + i] = toU8(s.charCodeAt(i))
1035
+ }
1036
+ }
1037
+ this.byteTop = at + n
1038
+ return n
1039
+ }
1040
+
1041
+ // ---- Writing ----------------------------------------------------------------
1042
+
1043
+ /**
1044
+ * Writes `v` into `w` as one value, members in order and numbers as their
1045
+ * text; the outcome is the writer's, in `w.failed`. A value that names
1046
+ * nothing writes nothing and fails nothing. A parsed tree is never deeper
1047
+ * than the writer nests; a built one deeper than `JSON_WRITER_MAX_DEPTH`
1048
+ * ends at `JSON_WRITE_TOO_DEEP`, where the recursion stops.
1049
+ */
1050
+ write(v: JsonValue, w: JsonWriter): void {
1051
+ this.writeAt(this.index(v), w)
1052
+ }
1053
+
1054
+ /** Internal: `write` of index `x`. */
1055
+ writeAt(x: i32, w: JsonWriter): void {
1056
+ const k: i32 = this.kindAt(x)
1057
+ if (k === JSON_VALUE_NONE || w.failed !== JSON_WRITE_OK) {
1058
+ return
1059
+ }
1060
+ if (k === JSON_VALUE_NULL) {
1061
+ w.nullValue()
1062
+ } else if (k === JSON_VALUE_BOOLEAN) {
1063
+ w.boolean(jsonValueGet(this.first, x) === JSON_VALUE_TRUE_WORD)
1064
+ } else if (k === JSON_VALUE_NUMBER) {
1065
+ w.raw(this.bytes, jsonValueGet(this.first, x), jsonValueGet(this.count, x))
1066
+ } else if (k === JSON_VALUE_STRING) {
1067
+ w.stringBytes(this.bytes, jsonValueGet(this.first, x), jsonValueGet(this.count, x))
1068
+ } else {
1069
+ // A container: its members are the slots from `first`, read directly.
1070
+ const object: boolean = k === JSON_VALUE_OBJECT
1071
+ const start: i32 = jsonValueGet(this.first, x)
1072
+ const end: i32 = start + jsonValueGet(this.count, x)
1073
+ if (object) {
1074
+ w.beginObject()
1075
+ } else {
1076
+ w.beginArray()
1077
+ }
1078
+ for (let s: i32 = start; s < end && w.failed === JSON_WRITE_OK; s += 1) {
1079
+ if (object) {
1080
+ w.keyBytes(this.bytes, jsonValueGet(this.slotKeyAt, s), jsonValueGet(this.slotKeyLength, s))
1081
+ }
1082
+ this.writeAt(jsonValueGet(this.slotValue, s), w)
1083
+ }
1084
+ if (object) {
1085
+ w.endObject()
1086
+ } else {
1087
+ w.endArray()
1088
+ }
1089
+ }
1090
+ }
1091
+
1092
+ /**
1093
+ * `v` as minified JSON text: written into a buffer that doubles until it
1094
+ * fits, then made into one string. `""` when `v` names nothing or the
1095
+ * writer refuses it, which only a built tree deeper than
1096
+ * `JSON_WRITER_MAX_DEPTH` makes it do; `write` gives the code.
1097
+ */
1098
+ stringify(v: JsonValue): string {
1099
+ // Every byte stored and a few of punctuation per value: one pass fits most
1100
+ // documents, and a text with many escapes doubles from there.
1101
+ let size: i32 = this.byteTop + 8 * this.top + 64
1102
+ while (true) {
1103
+ const buf: u8[] = new Array<u8>(size)
1104
+ const w: JsonWriter = new JsonWriter(buf, 0)
1105
+ this.write(v, w)
1106
+ if (w.failed !== JSON_WRITE_FULL || size > JSON_VALUE_I32_MAX / 2) {
1107
+ return w.complete() && w.end <= toI32(buf.length) ? String.fromBytes(buf, 0, w.end) : ""
1108
+ }
1109
+ size = size * 2
1110
+ }
1111
+ }
1112
+ }
1113
+
1114
+ /** `a[i]`, or `-1` when `i` is outside `a`. */
1115
+ const jsonValueGet = (a: i32[], i: i32): i32 => (i >= 0 && i < toI32(a.length) ? a[i] : -1)
1116
+
1117
+ /** `a[i] = x`, growing `a` by one when `i` is its length; an `i` further out writes nothing. */
1118
+ const jsonValuePut = (a: i32[], i: i32, x: i32): void => {
1119
+ if (i >= 0 && i < toI32(a.length)) {
1120
+ a[i] = x
1121
+ } else if (i === toI32(a.length)) {
1122
+ a.push(x)
1123
+ }
1124
+ }
1125
+
1126
+ /**
1127
+ * `a` when it holds at least `n` elements, and otherwise a copy of it at
1128
+ * least twice as long, for the caller to keep in `a`'s place. Doubling is
1129
+ * what keeps a run of appends linear, and the old array is left in the arena.
1130
+ */
1131
+ const jsonValueRoom = (a: u8[], n: i32): u8[] => {
1132
+ const have: i32 = toI32(a.length)
1133
+ if (n <= have) {
1134
+ return a
1135
+ }
1136
+ const grown: u8[] = new Array<u8>(n > have * 2 ? n : have * 2)
1137
+ grown.set(a, 0)
1138
+ return grown
1139
+ }
1140
+
1141
+ /** `jsonValueRoom` for an `i32[]`. */
1142
+ const jsonValueRoomI32 = (a: i32[], n: i32): i32[] => {
1143
+ const have: i32 = toI32(a.length)
1144
+ if (n <= have) {
1145
+ return a
1146
+ }
1147
+ const grown: i32[] = new Array<i32>(n > have * 2 ? n : have * 2)
1148
+ grown.set(a, 0)
1149
+ return grown
1150
+ }
1151
+
1152
+ /** `bytes[a, a + an)` and `bytes[b, b + bn)` compared byte by byte, a shorter prefix first: negative, `0` or positive. */
1153
+ const jsonValueCompareBytes = (bytes: u8[], a: i32, an: i32, b: i32, bn: i32): i32 => {
1154
+ const n: i32 = an < bn ? an : bn
1155
+ for (let i: i32 = 0; i < n; i += 1) {
1156
+ const x: i32 = a + i >= 0 && a + i < toI32(bytes.length) ? toI32(bytes[a + i]) : 0
1157
+ const y: i32 = b + i >= 0 && b + i < toI32(bytes.length) ? toI32(bytes[b + i]) : 0
1158
+ if (x !== y) {
1159
+ return x - y
1160
+ }
1161
+ }
1162
+ return an - bn
1163
+ }