@sofa-buffers/corelib 0.8.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/dist/index.js ADDED
@@ -0,0 +1,1936 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
7
+ // src/public.ts
8
+ var public_exports = {};
9
+ __export(public_exports, {
10
+ API_VERSION: () => API_VERSION,
11
+ ARRAY_MAX: () => ARRAY_MAX,
12
+ ArrayKind: () => ArrayKind,
13
+ Cursor: () => Cursor,
14
+ DecodeStatus: () => DecodeStatus,
15
+ FIXLEN_MAX: () => FIXLEN_MAX,
16
+ FixlenSubtype: () => FixlenSubtype,
17
+ I64_MAX: () => I64_MAX,
18
+ I64_MIN: () => I64_MIN,
19
+ ID_MAX: () => ID_MAX,
20
+ IStream: () => IStream,
21
+ Long: () => Long,
22
+ MAX_DEPTH: () => MAX_DEPTH,
23
+ OStream: () => OStream,
24
+ SofabError: () => SofabError,
25
+ SofabErrorCode: () => SofabErrorCode,
26
+ U64_MAX: () => U64_MAX,
27
+ WireType: () => WireType,
28
+ decode: () => decode,
29
+ getKernel: () => getKernel,
30
+ jsKernel: () => jsKernel,
31
+ loadNativeKernel: () => loadNativeKernel,
32
+ loadWasmKernel: () => loadWasmKernel,
33
+ setKernel: () => setKernel
34
+ });
35
+
36
+ // src/constants.ts
37
+ var API_VERSION = 1;
38
+ var WireType = {
39
+ /** Unsigned varint scalar. */
40
+ Unsigned: 0,
41
+ /** Signed varint scalar (zig-zag encoded). */
42
+ Signed: 1,
43
+ /** Fixed-length value: fp32, fp64, string or blob (see {@link FixlenSubtype}). */
44
+ Fixlen: 2,
45
+ /** Array of unsigned varints. */
46
+ ArrayUnsigned: 3,
47
+ /** Array of signed (zig-zag) varints. */
48
+ ArraySigned: 4,
49
+ /** Array of fixed-length values (fp32 / fp64 only). */
50
+ ArrayFixlen: 5,
51
+ /** Opens a nested sequence (new id scope). */
52
+ SequenceStart: 6,
53
+ /** Closes the current sequence. Encoded as the single byte `0x07`. */
54
+ SequenceEnd: 7
55
+ };
56
+ var FixlenSubtype = {
57
+ /** IEEE-754 32-bit float, little-endian. */
58
+ Fp32: 0,
59
+ /** IEEE-754 64-bit double, little-endian. */
60
+ Fp64: 1,
61
+ /** UTF-8 string (no null terminator). */
62
+ String: 2,
63
+ /** Arbitrary binary data. */
64
+ Blob: 3
65
+ };
66
+ var ArrayKind = {
67
+ /** Unsigned-integer elements. */
68
+ Unsigned: 0,
69
+ /** Signed-integer (zig-zag) elements. */
70
+ Signed: 1,
71
+ /** IEEE-754 32-bit float elements. */
72
+ Fp32: 2,
73
+ /** IEEE-754 64-bit double elements. */
74
+ Fp64: 3
75
+ };
76
+ var ID_MAX = 2147483647;
77
+ var FIXLEN_MAX = 2147483647;
78
+ var ARRAY_MAX = 2147483647;
79
+ var U64_MAX = 0xffffffffffffffffn;
80
+ var I64_MIN = -0x8000000000000000n;
81
+ var I64_MAX = 0x7fffffffffffffffn;
82
+ var VARINT_MAX_BYTES = 10;
83
+ var MAX_DEPTH = 255;
84
+ var DecodeStatus = {
85
+ /** The bytes ended exactly at a field boundary — a valid message. */
86
+ Complete: "COMPLETE",
87
+ /** The bytes ended inside a field; more bytes could complete it (not an error). */
88
+ Incomplete: "INCOMPLETE",
89
+ /** The bytes are malformed regardless of what follows. */
90
+ Invalid: "INVALID"
91
+ };
92
+
93
+ // src/errors.ts
94
+ var SofabErrorCode = {
95
+ /** A caller argument was invalid (e.g. id out of range, empty array). */
96
+ Argument: "ARGUMENT",
97
+ /** The API was used incorrectly (e.g. unbalanced sequence end). */
98
+ Usage: "USAGE",
99
+ /** The output buffer is full and no flush sink was provided. */
100
+ BufferFull: "BUFFER_FULL",
101
+ /** The input being decoded is malformed regardless of what follows (`INVALID`). */
102
+ InvalidMsg: "INVALID_MSG",
103
+ /**
104
+ * The input being decoded ends inside a field (`INCOMPLETE`, MESSAGE_SPEC §7):
105
+ * an unterminated varint, a payload shorter than its declared length, an array
106
+ * that runs off the end, or a nested sequence never closed. Not a malformed
107
+ * message — more bytes could complete it, and the caller owns end-of-input.
108
+ */
109
+ Incomplete: "INCOMPLETE",
110
+ /**
111
+ * A receiver-configured decode limit was exceeded — a dynamic array, string or
112
+ * blob on the wire claims more elements / bytes than the caller's
113
+ * {@link DecodeLimits} (`maxArrayCount` / `maxStringLen` / `maxBlobLen`)
114
+ * allows. Deliberately distinct from {@link SofabErrorCode.InvalidMsg}:
115
+ * exceeding a limit is *policy*, not wire malformation — the identical bytes
116
+ * decode fine under a looser limit — so differential fuzzing must not read it
117
+ * as a conformance divergence. The decoder never clamps or truncates; it
118
+ * rejects, before the offending field is materialized.
119
+ */
120
+ LimitExceeded: "LIMIT_EXCEEDED"
121
+ };
122
+ var SofabError = class _SofabError extends Error {
123
+ constructor(code, message) {
124
+ super(message);
125
+ this.name = "SofabError";
126
+ this.code = code;
127
+ Object.setPrototypeOf(this, _SofabError.prototype);
128
+ }
129
+ };
130
+ function argumentError(message) {
131
+ return new SofabError(SofabErrorCode.Argument, message);
132
+ }
133
+ function usageError(message) {
134
+ return new SofabError(SofabErrorCode.Usage, message);
135
+ }
136
+ function bufferFullError(message) {
137
+ return new SofabError(SofabErrorCode.BufferFull, message);
138
+ }
139
+ function invalidMsgError(message) {
140
+ return new SofabError(SofabErrorCode.InvalidMsg, message);
141
+ }
142
+ function incompleteError(message) {
143
+ return new SofabError(SofabErrorCode.Incomplete, message);
144
+ }
145
+ function limitExceededError(message) {
146
+ return new SofabError(SofabErrorCode.LimitExceeded, message);
147
+ }
148
+
149
+ // src/long.ts
150
+ var _Long = class _Long {
151
+ constructor(low, high) {
152
+ this.low = low >>> 0;
153
+ this.high = high >>> 0;
154
+ }
155
+ /** Construct from raw 32-bit halves. */
156
+ static fromBits(low, high) {
157
+ return new _Long(low, high);
158
+ }
159
+ /** Split a `bigint` into its low/high 32-bit halves (two's complement). */
160
+ static fromBigInt(value) {
161
+ return new _Long(Number(value & 0xffffffffn) >>> 0, Number(value >> 32n & 0xffffffffn) >>> 0);
162
+ }
163
+ /** From an integer `number` (`|n| < 2^53`); sign handled via `bigint` once. */
164
+ static fromNumber(n) {
165
+ return _Long.fromBigInt(BigInt(Math.trunc(n)));
166
+ }
167
+ /** Accept a `Long` as-is, or convert a `bigint` / `number` once. */
168
+ static fromValue(v) {
169
+ if (v instanceof _Long) return v;
170
+ return typeof v === "bigint" ? _Long.fromBigInt(v) : _Long.fromNumber(v);
171
+ }
172
+ /** Materialise as a `bigint`. `signed` reads the high bit as two's complement. */
173
+ toBigInt(signed = false) {
174
+ let r = BigInt(this.high >>> 0) << 32n | BigInt(this.low >>> 0);
175
+ if (signed && (this.high & 2147483648) !== 0) r -= 0x10000000000000000n;
176
+ return r;
177
+ }
178
+ /** Decimal string (`signed` interprets the high bit as two's complement). */
179
+ toString(signed = false) {
180
+ return this.toBigInt(signed).toString();
181
+ }
182
+ };
183
+ /**
184
+ * The 64-bit zero. `Long` is immutable (readonly halves), so this single shared
185
+ * instance is safe to reuse anywhere a zero default is needed — generated code
186
+ * uses it for fixed-count array defaults and pad-fill instead of
187
+ * `Long.fromValue(0)`, which would run `bigint` arithmetic per call on the hot
188
+ * decode/encode path.
189
+ */
190
+ _Long.ZERO = new _Long(0, 0);
191
+ var Long = _Long;
192
+
193
+ // src/varint/leb128.ts
194
+ function varintSize(value) {
195
+ let lo = Number(value & 0xffffffffn) >>> 0;
196
+ let hi = Number(value >> 32n & 0xffffffffn) >>> 0;
197
+ let n = 0;
198
+ while (hi !== 0) {
199
+ n++;
200
+ const next = (lo >>> 7 | hi << 25) >>> 0;
201
+ hi >>>= 7;
202
+ lo = next;
203
+ }
204
+ while (lo > 127) {
205
+ n++;
206
+ lo >>>= 7;
207
+ }
208
+ return n + 1;
209
+ }
210
+ function encodeVarint(value, out, pos) {
211
+ let lo = Number(value & 0xffffffffn) >>> 0;
212
+ let hi = Number(value >> 32n & 0xffffffffn) >>> 0;
213
+ while (hi !== 0) {
214
+ out[pos++] = lo & 127 | 128;
215
+ lo = (lo >>> 7 | hi << 25) >>> 0;
216
+ hi >>>= 7;
217
+ }
218
+ while (lo > 127) {
219
+ out[pos++] = lo & 127 | 128;
220
+ lo >>>= 7;
221
+ }
222
+ out[pos++] = lo;
223
+ return pos;
224
+ }
225
+ function encodeVarintLoHi(lo, hi, out, pos) {
226
+ lo >>>= 0;
227
+ hi >>>= 0;
228
+ while (hi !== 0) {
229
+ out[pos++] = lo & 127 | 128;
230
+ lo = (lo >>> 7 | hi << 25) >>> 0;
231
+ hi >>>= 7;
232
+ }
233
+ while (lo > 127) {
234
+ out[pos++] = lo & 127 | 128;
235
+ lo >>>= 7;
236
+ }
237
+ out[pos++] = lo;
238
+ return pos;
239
+ }
240
+ function varintSizeNum(value) {
241
+ let n = 1;
242
+ while (value > 127) {
243
+ n++;
244
+ value = Math.floor(value / 128);
245
+ }
246
+ return n;
247
+ }
248
+ function encodeVarintNum(value, out, pos) {
249
+ if (value < 4294967296) {
250
+ let v = value;
251
+ while (v > 127) {
252
+ out[pos++] = v & 127 | 128;
253
+ v >>>= 7;
254
+ }
255
+ out[pos++] = v;
256
+ return pos;
257
+ }
258
+ while (value > 127) {
259
+ out[pos++] = value % 128 | 128;
260
+ value = Math.floor(value / 128);
261
+ }
262
+ out[pos++] = value;
263
+ return pos;
264
+ }
265
+
266
+ // src/varint/num64.ts
267
+ var SCRATCH = new DataView(new ArrayBuffer(8));
268
+ function toBigInt(value) {
269
+ if (typeof value === "bigint") return value;
270
+ if (!Number.isInteger(value)) {
271
+ throw new RangeError(`expected an integer, got ${value}`);
272
+ }
273
+ return BigInt(value);
274
+ }
275
+ function inU64(value) {
276
+ return value >= 0n && value <= U64_MAX;
277
+ }
278
+ function inI64(value) {
279
+ return value >= I64_MIN && value <= I64_MAX;
280
+ }
281
+ function packFp32(out, pos, value) {
282
+ SCRATCH.setFloat32(0, value, true);
283
+ out[pos] = SCRATCH.getUint8(0);
284
+ out[pos + 1] = SCRATCH.getUint8(1);
285
+ out[pos + 2] = SCRATCH.getUint8(2);
286
+ out[pos + 3] = SCRATCH.getUint8(3);
287
+ return pos + 4;
288
+ }
289
+ function packFp64(out, pos, value) {
290
+ SCRATCH.setFloat64(0, value, true);
291
+ for (let i = 0; i < 8; i++) out[pos + i] = SCRATCH.getUint8(i);
292
+ return pos + 8;
293
+ }
294
+ function unpackFp32(buf, pos) {
295
+ SCRATCH.setUint8(0, buf[pos]);
296
+ SCRATCH.setUint8(1, buf[pos + 1]);
297
+ SCRATCH.setUint8(2, buf[pos + 2]);
298
+ SCRATCH.setUint8(3, buf[pos + 3]);
299
+ return SCRATCH.getFloat32(0, true);
300
+ }
301
+ function unpackFp64(buf, pos) {
302
+ for (let i = 0; i < 8; i++) SCRATCH.setUint8(i, buf[pos + i]);
303
+ return SCRATCH.getFloat64(0, true);
304
+ }
305
+
306
+ // src/varint/zigzag.ts
307
+ function zigzagEncode(value) {
308
+ return (value << 1n ^ value >> 63n) & U64_MAX;
309
+ }
310
+ function zigzagDecode(value) {
311
+ return value >> 1n ^ -(value & 1n);
312
+ }
313
+
314
+ // src/backend/js.ts
315
+ var SIGNED_FAST_MAX = 4503599627370496;
316
+ var jsKernel = {
317
+ name: "js",
318
+ encodeUnsignedVarints(values, out, pos) {
319
+ for (let i = 0; i < values.length; i++) {
320
+ const v = values[i];
321
+ if (typeof v === "number" && v >= 0 && v <= Number.MAX_SAFE_INTEGER && Number.isInteger(v)) {
322
+ pos = encodeVarintNum(v, out, pos);
323
+ } else {
324
+ pos = encodeVarint(toBigInt(v), out, pos);
325
+ }
326
+ }
327
+ return pos;
328
+ },
329
+ encodeSignedVarints(values, out, pos) {
330
+ for (let i = 0; i < values.length; i++) {
331
+ const v = values[i];
332
+ if (typeof v === "number" && v >= -SIGNED_FAST_MAX && v <= SIGNED_FAST_MAX && Number.isInteger(v)) {
333
+ pos = encodeVarintNum(v >= 0 ? v * 2 : -v * 2 - 1, out, pos);
334
+ } else {
335
+ pos = encodeVarint(zigzagEncode(toBigInt(v)), out, pos);
336
+ }
337
+ }
338
+ return pos;
339
+ },
340
+ packFp32Array(values, out, pos) {
341
+ for (let i = 0; i < values.length; i++) {
342
+ pos = packFp32(out, pos, values[i]);
343
+ }
344
+ return pos;
345
+ },
346
+ packFp64Array(values, out, pos) {
347
+ for (let i = 0; i < values.length; i++) {
348
+ pos = packFp64(out, pos, values[i]);
349
+ }
350
+ return pos;
351
+ }
352
+ };
353
+
354
+ // src/backend/kernel.ts
355
+ var active = jsKernel;
356
+ function setKernel(kernel) {
357
+ validateKernel(kernel);
358
+ active = kernel;
359
+ }
360
+ function getKernel() {
361
+ return active;
362
+ }
363
+ function validateKernel(kernel) {
364
+ const required = [
365
+ "encodeUnsignedVarints",
366
+ "encodeSignedVarints",
367
+ "packFp32Array",
368
+ "packFp64Array"
369
+ ];
370
+ for (const m of required) {
371
+ if (typeof kernel[m] !== "function") {
372
+ throw new TypeError(`kernel "${kernel?.name}" is missing ${String(m)}()`);
373
+ }
374
+ }
375
+ }
376
+
377
+ // src/encode/fixlen.ts
378
+ var UTF8 = new TextEncoder();
379
+ function unpairedSurrogate(index) {
380
+ return argumentError(
381
+ `unpaired surrogate at index ${index}: string value is not valid UTF-8`
382
+ );
383
+ }
384
+ function encodeUtf8(text) {
385
+ utf8Length(text);
386
+ return UTF8.encode(text);
387
+ }
388
+ function utf8Length(text) {
389
+ let len = 0;
390
+ for (let i = 0; i < text.length; i++) {
391
+ const c = text.charCodeAt(i);
392
+ if (c < 128) {
393
+ len += 1;
394
+ } else if (c < 2048) {
395
+ len += 2;
396
+ } else if (c >= 55296 && c <= 56319) {
397
+ const c2 = i + 1 < text.length ? text.charCodeAt(i + 1) : 0;
398
+ if (c2 >= 56320 && c2 <= 57343) {
399
+ i++;
400
+ len += 4;
401
+ } else {
402
+ throw unpairedSurrogate(i);
403
+ }
404
+ } else if (c >= 56320 && c <= 57343) {
405
+ throw unpairedSurrogate(i);
406
+ } else {
407
+ len += 3;
408
+ }
409
+ }
410
+ return len;
411
+ }
412
+ function utf8Write(text, out, pos) {
413
+ for (let i = 0; i < text.length; i++) {
414
+ let c = text.charCodeAt(i);
415
+ if (c < 128) {
416
+ out[pos++] = c;
417
+ } else if (c < 2048) {
418
+ out[pos++] = 192 | c >> 6;
419
+ out[pos++] = 128 | c & 63;
420
+ } else if (c >= 55296 && c <= 56319) {
421
+ const c2 = i + 1 < text.length ? text.charCodeAt(i + 1) : 0;
422
+ if (c2 >= 56320 && c2 <= 57343) {
423
+ i++;
424
+ c = 65536 + (c - 55296 << 10) + (c2 - 56320);
425
+ out[pos++] = 240 | c >> 18;
426
+ out[pos++] = 128 | c >> 12 & 63;
427
+ out[pos++] = 128 | c >> 6 & 63;
428
+ out[pos++] = 128 | c & 63;
429
+ } else {
430
+ throw unpairedSurrogate(i);
431
+ }
432
+ } else if (c >= 56320 && c <= 57343) {
433
+ throw unpairedSurrogate(i);
434
+ } else {
435
+ out[pos++] = 224 | c >> 12;
436
+ out[pos++] = 128 | c >> 6 & 63;
437
+ out[pos++] = 128 | c & 63;
438
+ }
439
+ }
440
+ return pos;
441
+ }
442
+
443
+ // src/encode/ostream.ts
444
+ var DEFAULT_CAPACITY = 256;
445
+ var SIGNED_FAST_MAX2 = 4503599627370496;
446
+ var OStream = class {
447
+ constructor(buffer, offset = 0, flush) {
448
+ this.depth = 0;
449
+ this.kernel = getKernel();
450
+ if (buffer === void 0) {
451
+ this.buf = new Uint8Array(DEFAULT_CAPACITY);
452
+ this.start = 0;
453
+ this.pos = 0;
454
+ this.flushSink = void 0;
455
+ this.canGrow = true;
456
+ } else {
457
+ if (offset < 0 || offset > buffer.length) {
458
+ throw argumentError(`offset ${offset} out of range`);
459
+ }
460
+ this.buf = buffer;
461
+ this.start = offset;
462
+ this.pos = offset;
463
+ this.flushSink = flush;
464
+ this.canGrow = false;
465
+ }
466
+ }
467
+ /** Bytes currently held in the buffer (since construction or the last flush). */
468
+ get bytesUsed() {
469
+ return this.pos - this.start;
470
+ }
471
+ /**
472
+ * The encoded message so far, as a view into the working buffer.
473
+ * Meaningful for the in-memory mode; in streaming mode it is only the
474
+ * not-yet-flushed tail. The view is valid until the next write.
475
+ */
476
+ bytes() {
477
+ return this.buf.subarray(this.start, this.pos);
478
+ }
479
+ /** Drain buffered bytes to the flush sink (no-op without one). */
480
+ flush() {
481
+ if (this.flushSink && this.pos > this.start) {
482
+ this.flushSink(this.buf.subarray(this.start, this.pos));
483
+ this.pos = this.start;
484
+ }
485
+ }
486
+ /**
487
+ * Install a fresh output buffer to write into, mid-stream. Intended for the
488
+ * streaming (flush-sink) mode: call it from inside your flush callback to hand
489
+ * the encoder a new buffer for the next batch of bytes, so encoding continues
490
+ * without interruption. `offset` reserves space at the front of the new
491
+ * buffer. Any not-yet-flushed bytes in the old buffer are dropped, so
492
+ * {@link flush} first (the flush callback fires before you swap).
493
+ */
494
+ setBuffer(buffer, offset = 0) {
495
+ if (offset < 0 || offset > buffer.length) {
496
+ throw argumentError(`offset ${offset} out of range`);
497
+ }
498
+ this.buf = buffer;
499
+ this.start = offset;
500
+ this.pos = offset;
501
+ }
502
+ /**
503
+ * Rewind the encoder to empty, reusing the existing buffer. Lets a caller pool
504
+ * one OStream across many messages instead of allocating a fresh buffer per
505
+ * encode. Any view previously returned by {@link bytes} is invalidated.
506
+ */
507
+ reset() {
508
+ this.pos = this.start;
509
+ this.depth = 0;
510
+ }
511
+ // --- scalars ------------------------------------------------------------
512
+ /** Write an unsigned integer field. */
513
+ writeUnsigned(id, value) {
514
+ if (typeof value === "number" && value >= 0 && value <= Number.MAX_SAFE_INTEGER && Number.isInteger(value)) {
515
+ this.header(id, WireType.Unsigned);
516
+ this.putVarintNum(value);
517
+ return;
518
+ }
519
+ const v = toBigInt(value);
520
+ if (!inU64(v)) throw argumentError(`unsigned value ${v} out of 64-bit range`);
521
+ this.header(id, WireType.Unsigned);
522
+ this.putVarint(v);
523
+ }
524
+ /** Write a signed integer field (zig-zag encoded). */
525
+ writeSigned(id, value) {
526
+ if (typeof value === "number" && value >= -SIGNED_FAST_MAX2 && value <= SIGNED_FAST_MAX2 && Number.isInteger(value)) {
527
+ this.header(id, WireType.Signed);
528
+ this.putVarintNum(value >= 0 ? value * 2 : -value * 2 - 1);
529
+ return;
530
+ }
531
+ const v = toBigInt(value);
532
+ if (!inI64(v)) throw argumentError(`signed value ${v} out of 64-bit range`);
533
+ this.header(id, WireType.Signed);
534
+ this.putVarint(zigzagEncode(v));
535
+ }
536
+ /** Write a boolean field (encoded as the unsigned value 0 or 1). */
537
+ writeBoolean(id, value) {
538
+ this.header(id, WireType.Unsigned);
539
+ this.putVarintNum(value ? 1 : 0);
540
+ }
541
+ /** Write an IEEE-754 32-bit float field. */
542
+ writeFp32(id, value) {
543
+ this.fixlenHead(id, 4, FixlenSubtype.Fp32);
544
+ this.ensure(4);
545
+ this.pos = packFp32(this.buf, this.pos, value);
546
+ }
547
+ /** Write an IEEE-754 64-bit double field. */
548
+ writeFp64(id, value) {
549
+ this.fixlenHead(id, 8, FixlenSubtype.Fp64);
550
+ this.ensure(8);
551
+ this.pos = packFp64(this.buf, this.pos, value);
552
+ }
553
+ /** Write a UTF-8 string field. */
554
+ writeString(id, text) {
555
+ if (this.canGrow) {
556
+ const byteLen = utf8Length(text);
557
+ if (byteLen > FIXLEN_MAX) {
558
+ throw argumentError(`fixlen length ${byteLen} exceeds ${FIXLEN_MAX}`);
559
+ }
560
+ this.fixlenHead(id, byteLen, FixlenSubtype.String);
561
+ this.ensure(byteLen);
562
+ this.pos = utf8Write(text, this.buf, this.pos);
563
+ return;
564
+ }
565
+ this.writeFixlen(id, encodeUtf8(text), FixlenSubtype.String);
566
+ }
567
+ /** Write a blob (arbitrary bytes) field. */
568
+ writeBlob(id, data) {
569
+ this.writeFixlen(id, data, FixlenSubtype.Blob);
570
+ }
571
+ /** Write a fixed-length field of the given subtype from raw bytes. */
572
+ writeFixlen(id, data, subtype) {
573
+ if (data.length > FIXLEN_MAX) {
574
+ throw argumentError(`fixlen length ${data.length} exceeds ${FIXLEN_MAX}`);
575
+ }
576
+ this.fixlenHead(id, data.length, subtype);
577
+ this.writeRaw(data);
578
+ }
579
+ // --- arrays -------------------------------------------------------------
580
+ /** Write an array of unsigned integers (each a varint). */
581
+ writeUnsignedArray(id, values) {
582
+ this.arrayHead(id, WireType.ArrayUnsigned, values.length);
583
+ if (this.canGrow) {
584
+ this.ensure(values.length * VARINT_MAX_BYTES);
585
+ this.pos = this.kernel.encodeUnsignedVarints(values, this.buf, this.pos);
586
+ } else {
587
+ for (let i = 0; i < values.length; i++) {
588
+ const v = toBigInt(values[i]);
589
+ if (!inU64(v)) throw argumentError(`unsigned value ${v} out of range`);
590
+ this.ensure(VARINT_MAX_BYTES);
591
+ this.pos = encodeVarint(v, this.buf, this.pos);
592
+ }
593
+ }
594
+ }
595
+ /** Write an array of signed integers (each zig-zag + varint). */
596
+ writeSignedArray(id, values) {
597
+ this.arrayHead(id, WireType.ArraySigned, values.length);
598
+ if (this.canGrow) {
599
+ this.ensure(values.length * VARINT_MAX_BYTES);
600
+ this.pos = this.kernel.encodeSignedVarints(values, this.buf, this.pos);
601
+ } else {
602
+ for (let i = 0; i < values.length; i++) {
603
+ const v = toBigInt(values[i]);
604
+ if (!inI64(v)) throw argumentError(`signed value ${v} out of range`);
605
+ this.ensure(VARINT_MAX_BYTES);
606
+ this.pos = encodeVarint(zigzagEncode(v), this.buf, this.pos);
607
+ }
608
+ }
609
+ }
610
+ /**
611
+ * Write an unsigned 64-bit array from {@link Long}[] — the `bigint`-free path.
612
+ * Produces the identical wire to {@link writeUnsignedArray}; reads each Long's
613
+ * 32-bit halves directly, so no `bigint` is created per element.
614
+ */
615
+ writeUnsignedArrayLong(id, values) {
616
+ this.arrayHead(id, WireType.ArrayUnsigned, values.length);
617
+ this.ensure(values.length * VARINT_MAX_BYTES);
618
+ let pos = this.pos;
619
+ const buf = this.buf;
620
+ for (let i = 0; i < values.length; i++) {
621
+ const v = values[i];
622
+ pos = encodeVarintLoHi(v.low, v.high, buf, pos);
623
+ }
624
+ this.pos = pos;
625
+ }
626
+ /**
627
+ * Write a signed 64-bit array (zig-zag) from {@link Long}[] — the `bigint`-free
628
+ * path. Zig-zag `(n << 1) ^ (n >> 63)` is computed on the lo/hi pair.
629
+ */
630
+ writeSignedArrayLong(id, values) {
631
+ this.arrayHead(id, WireType.ArraySigned, values.length);
632
+ this.ensure(values.length * VARINT_MAX_BYTES);
633
+ let pos = this.pos;
634
+ const buf = this.buf;
635
+ for (let i = 0; i < values.length; i++) {
636
+ const v = values[i];
637
+ const lo = v.low;
638
+ const hi = v.high;
639
+ const sgn = -(hi >>> 31) >>> 0;
640
+ const zLo = (lo << 1 >>> 0 ^ sgn) >>> 0;
641
+ const zHi = ((hi << 1 | lo >>> 31) >>> 0 ^ sgn) >>> 0;
642
+ pos = encodeVarintLoHi(zLo, zHi, buf, pos);
643
+ }
644
+ this.pos = pos;
645
+ }
646
+ /** Write an array of IEEE-754 32-bit floats. */
647
+ writeFp32Array(id, values) {
648
+ this.arrayHead(id, WireType.ArrayFixlen, values.length);
649
+ this.putVarintNum(4 * 8 + FixlenSubtype.Fp32);
650
+ if (this.canGrow) {
651
+ this.ensure(values.length * 4);
652
+ this.pos = this.kernel.packFp32Array(values, this.buf, this.pos);
653
+ } else {
654
+ for (let i = 0; i < values.length; i++) {
655
+ this.ensure(4);
656
+ this.pos = packFp32(this.buf, this.pos, values[i]);
657
+ }
658
+ }
659
+ }
660
+ /** Write an array of IEEE-754 64-bit doubles. */
661
+ writeFp64Array(id, values) {
662
+ this.arrayHead(id, WireType.ArrayFixlen, values.length);
663
+ this.putVarintNum(8 * 8 + FixlenSubtype.Fp64);
664
+ if (this.canGrow) {
665
+ this.ensure(values.length * 8);
666
+ this.pos = this.kernel.packFp64Array(values, this.buf, this.pos);
667
+ } else {
668
+ for (let i = 0; i < values.length; i++) {
669
+ this.ensure(8);
670
+ this.pos = packFp64(this.buf, this.pos, values[i]);
671
+ }
672
+ }
673
+ }
674
+ // --- sequences ----------------------------------------------------------
675
+ /** Open a nested sequence (a fresh id scope). */
676
+ writeSequenceBegin(id) {
677
+ if (this.depth >= MAX_DEPTH) {
678
+ throw usageError(`nesting exceeds MAX_DEPTH (${MAX_DEPTH})`);
679
+ }
680
+ this.header(id, WireType.SequenceStart);
681
+ this.depth++;
682
+ }
683
+ /** Close the current sequence. */
684
+ writeSequenceEnd() {
685
+ if (this.depth <= 0) throw usageError("sequence end without matching begin");
686
+ this.ensure(1);
687
+ this.buf[this.pos++] = WireType.SequenceEnd;
688
+ this.depth--;
689
+ }
690
+ // --- internals ----------------------------------------------------------
691
+ /** Ensure exactly `value`'s varint size, then write it (bigint path). */
692
+ putVarint(value) {
693
+ this.ensure(varintSize(value));
694
+ this.pos = encodeVarint(value, this.buf, this.pos);
695
+ }
696
+ /** Ensure exactly `value`'s varint size, then write it (number fast path). */
697
+ putVarintNum(value) {
698
+ this.ensure(varintSizeNum(value));
699
+ this.pos = encodeVarintNum(value, this.buf, this.pos);
700
+ }
701
+ header(id, type) {
702
+ if (id < 0 || id > ID_MAX || !Number.isInteger(id)) {
703
+ throw argumentError(`field id ${id} out of range 0..${ID_MAX}`);
704
+ }
705
+ this.putVarintNum(id * 8 + type);
706
+ }
707
+ fixlenHead(id, length, subtype) {
708
+ this.header(id, WireType.Fixlen);
709
+ this.putVarintNum(length * 8 + subtype);
710
+ }
711
+ arrayHead(id, type, count) {
712
+ if (count < 0 || count > ARRAY_MAX) {
713
+ throw argumentError(`array count ${count} out of range 0..${ARRAY_MAX}`);
714
+ }
715
+ this.header(id, type);
716
+ this.putVarintNum(count);
717
+ }
718
+ /** Copy `data` out, flushing/growing as needed (large payloads stay chunked). */
719
+ writeRaw(data) {
720
+ let off = 0;
721
+ while (off < data.length) {
722
+ const room = this.ensureSome(data.length - off);
723
+ this.buf.set(data.subarray(off, off + room), this.pos);
724
+ this.pos += room;
725
+ off += room;
726
+ }
727
+ }
728
+ /** Ensure `n` contiguous bytes are free at `pos`; returns `pos` for chaining. */
729
+ ensure(n) {
730
+ if (this.buf.length - this.pos >= n) return this.pos;
731
+ this.flush();
732
+ if (this.buf.length - this.pos >= n) return this.pos;
733
+ if (this.canGrow) {
734
+ this.growTo(this.pos + n);
735
+ return this.pos;
736
+ }
737
+ throw bufferFullError(
738
+ `output buffer full: need ${n} more bytes, have ${this.buf.length - this.pos}`
739
+ );
740
+ }
741
+ /** Ensure *some* room (up to `want`); returns how many bytes are available. */
742
+ ensureSome(want) {
743
+ let room = this.buf.length - this.pos;
744
+ if (room === 0) {
745
+ this.flush();
746
+ room = this.buf.length - this.pos;
747
+ if (room === 0) {
748
+ if (this.canGrow) {
749
+ this.growTo(this.pos + want);
750
+ room = this.buf.length - this.pos;
751
+ } else {
752
+ throw bufferFullError("output buffer full");
753
+ }
754
+ }
755
+ }
756
+ return Math.min(room, want);
757
+ }
758
+ growTo(needed) {
759
+ let cap = this.buf.length * 2;
760
+ if (cap < needed) cap = needed;
761
+ const next = new Uint8Array(cap);
762
+ next.set(this.buf.subarray(0, this.pos));
763
+ this.buf = next;
764
+ }
765
+ };
766
+
767
+ // src/decode/fast.ts
768
+ var TWO32 = 4294967296;
769
+ function decodeContiguous(buf, root, limits) {
770
+ new FastDecoder(buf, limits).run(root);
771
+ }
772
+ var FastDecoder = class {
773
+ constructor(buf, limits) {
774
+ this.p = 0;
775
+ // Last varint, as two unsigned 32-bit halves (see readVarint).
776
+ this.lo = 0;
777
+ this.hi = 0;
778
+ this.buf = buf;
779
+ this.n = buf.length;
780
+ this.view = new DataView(buf.buffer, buf.byteOffset, buf.length);
781
+ this.maxArrayCount = limits?.maxArrayCount ?? Infinity;
782
+ this.maxStringLen = limits?.maxStringLen ?? Infinity;
783
+ this.maxBlobLen = limits?.maxBlobLen ?? Infinity;
784
+ }
785
+ run(root) {
786
+ const stack = [root];
787
+ let top = root;
788
+ while (this.p < this.n) {
789
+ this.readVarint();
790
+ const type = this.lo & 7;
791
+ if (type === WireType.SequenceEnd) {
792
+ if (stack.length <= 1) throw invalidMsgError("unbalanced sequence end");
793
+ top.sequenceEnd?.();
794
+ stack.pop();
795
+ top = stack[stack.length - 1];
796
+ continue;
797
+ }
798
+ const id = this.upper();
799
+ if (id > ID_MAX) throw invalidMsgError(`field id ${id} out of range`);
800
+ switch (type) {
801
+ case WireType.Unsigned: {
802
+ this.readVarint();
803
+ top.unsigned?.(id, this.unsignedValue());
804
+ break;
805
+ }
806
+ case WireType.Signed: {
807
+ this.readVarint();
808
+ top.signed?.(id, this.signedValue());
809
+ break;
810
+ }
811
+ case WireType.Fixlen: {
812
+ this.readVarint();
813
+ const sub = this.lo & 7;
814
+ const len = this.upper();
815
+ if (sub > FixlenSubtype.Blob) throw invalidMsgError(`invalid fixlen subtype ${sub}`);
816
+ if (len > FIXLEN_MAX) throw invalidMsgError("fixlen length out of range");
817
+ if (sub === FixlenSubtype.String && len > this.maxStringLen) {
818
+ throw limitExceededError(`string length ${len} exceeds maxStringLen ${this.maxStringLen}`);
819
+ }
820
+ if (sub === FixlenSubtype.Blob && len > this.maxBlobLen) {
821
+ throw limitExceededError(`blob length ${len} exceeds maxBlobLen ${this.maxBlobLen}`);
822
+ }
823
+ if (sub === FixlenSubtype.Fp32 || sub === FixlenSubtype.Fp64) {
824
+ const want = sub === FixlenSubtype.Fp32 ? 4 : 8;
825
+ if (len !== want) throw invalidMsgError("fixlen float length mismatch");
826
+ const value = sub === FixlenSubtype.Fp32 ? this.readFp32() : this.readFp64();
827
+ if (sub === FixlenSubtype.Fp32) top.fp32?.(id, value);
828
+ else top.fp64?.(id, value);
829
+ } else {
830
+ const chunk = this.take(len);
831
+ if (sub === FixlenSubtype.String) top.string?.(id, len, 0, chunk);
832
+ else top.blob?.(id, len, 0, chunk);
833
+ }
834
+ break;
835
+ }
836
+ case WireType.ArrayUnsigned: {
837
+ const count = this.arrayCount();
838
+ top.arrayBegin?.(id, ArrayKind.Unsigned, count);
839
+ for (let i = 0; i < count; i++) {
840
+ this.readVarint();
841
+ top.arrayUnsigned?.(id, i, this.unsignedValue());
842
+ }
843
+ top.arrayEnd?.(id);
844
+ break;
845
+ }
846
+ case WireType.ArraySigned: {
847
+ const count = this.arrayCount();
848
+ top.arrayBegin?.(id, ArrayKind.Signed, count);
849
+ for (let i = 0; i < count; i++) {
850
+ this.readVarint();
851
+ top.arraySigned?.(id, i, this.signedValue());
852
+ }
853
+ top.arrayEnd?.(id);
854
+ break;
855
+ }
856
+ case WireType.ArrayFixlen: {
857
+ const count = this.arrayCount();
858
+ this.readVarint();
859
+ const sub = this.lo & 7;
860
+ const size = this.upper();
861
+ let kind;
862
+ if (sub === FixlenSubtype.Fp32 && size === 4) kind = ArrayKind.Fp32;
863
+ else if (sub === FixlenSubtype.Fp64 && size === 8) kind = ArrayKind.Fp64;
864
+ else throw invalidMsgError("invalid fixlen array element type");
865
+ top.arrayBegin?.(id, kind, count);
866
+ if (kind === ArrayKind.Fp32) {
867
+ for (let i = 0; i < count; i++) {
868
+ const value = this.readFp32();
869
+ top.arrayFp32?.(id, i, value);
870
+ }
871
+ } else {
872
+ for (let i = 0; i < count; i++) {
873
+ const value = this.readFp64();
874
+ top.arrayFp64?.(id, i, value);
875
+ }
876
+ }
877
+ top.arrayEnd?.(id);
878
+ break;
879
+ }
880
+ case WireType.SequenceStart: {
881
+ if (stack.length - 1 >= MAX_DEPTH) {
882
+ throw invalidMsgError(`nesting exceeds MAX_DEPTH (${MAX_DEPTH})`);
883
+ }
884
+ const child = top.sequenceBegin?.(id);
885
+ top = child ?? top;
886
+ stack.push(top);
887
+ break;
888
+ }
889
+ default:
890
+ throw invalidMsgError(`invalid wire type ${type}`);
891
+ }
892
+ }
893
+ if (stack.length > 1) throw incompleteError("truncated message: unbalanced sequence");
894
+ }
895
+ // --- field helpers ------------------------------------------------------
896
+ /** Read and validate an array count word (0..ARRAY_MAX; §4.7/§4.8). */
897
+ arrayCount() {
898
+ this.readVarint();
899
+ const count = this.num();
900
+ if (count > ARRAY_MAX) throw invalidMsgError("array count out of range");
901
+ if (count > this.maxArrayCount) {
902
+ throw limitExceededError(`array count ${count} exceeds maxArrayCount ${this.maxArrayCount}`);
903
+ }
904
+ return count;
905
+ }
906
+ /** Hand back a zero-copy view of the next `len` bytes, advancing the cursor. */
907
+ take(len) {
908
+ const start = this.p;
909
+ const end = start + len;
910
+ if (end > this.n) throw incompleteError("truncated fixlen payload");
911
+ this.p = end;
912
+ return this.buf.subarray(start, end);
913
+ }
914
+ readFp32() {
915
+ const p = this.p;
916
+ if (p + 4 > this.n) throw incompleteError("truncated fp32");
917
+ this.p = p + 4;
918
+ return this.view.getFloat32(p, true);
919
+ }
920
+ readFp64() {
921
+ const p = this.p;
922
+ if (p + 8 > this.n) throw incompleteError("truncated fp64");
923
+ this.p = p + 8;
924
+ return this.view.getFloat64(p, true);
925
+ }
926
+ // --- varint reading -----------------------------------------------------
927
+ /** The last varint's full value as a `bigint` (64-bit fidelity). */
928
+ big() {
929
+ return this.hi === 0 ? BigInt(this.lo >>> 0) : BigInt(this.hi >>> 0) << 32n | BigInt(this.lo >>> 0);
930
+ }
931
+ /**
932
+ * The last varint as an unsigned value, number-first: a `number` when it fits
933
+ * exactly (`≤ 2^53-1` — all ids, u8..u32 and small u64s), a `bigint` only
934
+ * beyond that. Skips the per-value bigint allocation on the common path.
935
+ */
936
+ unsignedValue() {
937
+ const hi = this.hi >>> 0;
938
+ return hi <= 2097151 ? hi * TWO32 + (this.lo >>> 0) : this.big();
939
+ }
940
+ /** The last zig-zag varint as a signed value, number-first (see {@link unsignedValue}). */
941
+ signedValue() {
942
+ const hi = this.hi >>> 0;
943
+ if (hi <= 2097151) {
944
+ const r = hi * TWO32 + (this.lo >>> 0);
945
+ return r % 2 === 0 ? r / 2 : -(r + 1) / 2;
946
+ }
947
+ return zigzagDecode(this.big());
948
+ }
949
+ /** The last varint's value as a JS number — exact for ids/lengths/counts. */
950
+ num() {
951
+ return this.hi * TWO32 + (this.lo >>> 0);
952
+ }
953
+ /** The last varint with its low 3 tag bits stripped (`value >> 3`). */
954
+ upper() {
955
+ return (this.hi >>> 0) * (TWO32 / 8) + (this.lo >>> 3);
956
+ }
957
+ /**
958
+ * Decode one LEB128 varint at the cursor into {@link lo} / {@link hi} (each an
959
+ * unsigned 32-bit half), advancing {@link p}. Throws on truncation or a value
960
+ * spilling past 64 bits (>10 bytes). Unrolled, number-only — no `bigint`.
961
+ */
962
+ readVarint() {
963
+ const buf = this.buf;
964
+ const n = this.n;
965
+ let p = this.p;
966
+ let b;
967
+ let lo;
968
+ let hi = 0;
969
+ if (p >= n) throw incompleteError("truncated varint");
970
+ b = buf[p++];
971
+ lo = b & 127;
972
+ if (b < 128) return this.set(lo, 0, p);
973
+ if (p >= n) throw incompleteError("truncated varint");
974
+ b = buf[p++];
975
+ lo |= (b & 127) << 7;
976
+ if (b < 128) return this.set(lo, 0, p);
977
+ if (p >= n) throw incompleteError("truncated varint");
978
+ b = buf[p++];
979
+ lo |= (b & 127) << 14;
980
+ if (b < 128) return this.set(lo, 0, p);
981
+ if (p >= n) throw incompleteError("truncated varint");
982
+ b = buf[p++];
983
+ lo |= (b & 127) << 21;
984
+ if (b < 128) return this.set(lo, 0, p);
985
+ if (p >= n) throw incompleteError("truncated varint");
986
+ b = buf[p++];
987
+ lo |= (b & 15) << 28;
988
+ hi = b >> 4 & 7;
989
+ if (b < 128) return this.set(lo, hi, p);
990
+ if (p >= n) throw incompleteError("truncated varint");
991
+ b = buf[p++];
992
+ hi |= (b & 127) << 3;
993
+ if (b < 128) return this.set(lo, hi, p);
994
+ if (p >= n) throw incompleteError("truncated varint");
995
+ b = buf[p++];
996
+ hi |= (b & 127) << 10;
997
+ if (b < 128) return this.set(lo, hi, p);
998
+ if (p >= n) throw incompleteError("truncated varint");
999
+ b = buf[p++];
1000
+ hi |= (b & 127) << 17;
1001
+ if (b < 128) return this.set(lo, hi, p);
1002
+ if (p >= n) throw incompleteError("truncated varint");
1003
+ b = buf[p++];
1004
+ hi |= (b & 127) << 24;
1005
+ if (b < 128) return this.set(lo, hi, p);
1006
+ if (p >= n) throw incompleteError("truncated varint");
1007
+ b = buf[p++];
1008
+ if ((b & 127) >> 1 !== 0) throw invalidMsgError("varint overflow");
1009
+ hi |= (b & 127) << 31;
1010
+ if (b < 128) return this.set(lo, hi, p);
1011
+ throw invalidMsgError("varint overflow");
1012
+ }
1013
+ set(lo, hi, p) {
1014
+ this.lo = lo;
1015
+ this.hi = hi;
1016
+ this.p = p;
1017
+ }
1018
+ };
1019
+
1020
+ // src/decode/state.ts
1021
+ var TWO322 = 4294967296;
1022
+ var DecoderState = class {
1023
+ constructor(limits) {
1024
+ this.state = 0 /* Header */;
1025
+ this.stack = [];
1026
+ // current field
1027
+ this.id = 0;
1028
+ // Resumable varint accumulator, as two unsigned 32-bit halves (vLo / vHi)
1029
+ // plus the byte count so far. Number-only: a `bigint` is built once, at the
1030
+ // end, and only for full 64-bit *values* (not ids, lengths or counts).
1031
+ this.vLo = 0;
1032
+ this.vHi = 0;
1033
+ this.vBytes = 0;
1034
+ this.vComplete = false;
1035
+ // fixlen / fp scratch
1036
+ this.scratch = new Uint8Array(8);
1037
+ this.need = 0;
1038
+ this.have = 0;
1039
+ // fixlen string/blob streaming
1040
+ this.fixSub = FixlenSubtype.String;
1041
+ this.fixLen = 0;
1042
+ this.fixOff = 0;
1043
+ // array
1044
+ this.arrKind = ArrayKind.Unsigned;
1045
+ this.arrIsFixlen = false;
1046
+ this.arrCount = 0;
1047
+ this.arrIndex = 0;
1048
+ this.maxArrayCount = limits?.maxArrayCount ?? Infinity;
1049
+ this.maxStringLen = limits?.maxStringLen ?? Infinity;
1050
+ this.maxBlobLen = limits?.maxBlobLen ?? Infinity;
1051
+ }
1052
+ /** Feed `input` to the machine, dispatching to `root` and its sub-visitors. */
1053
+ push(input, root) {
1054
+ if (this.stack.length === 0) this.stack.push(root);
1055
+ let i = 0;
1056
+ const n = input.length;
1057
+ while (i < n) {
1058
+ switch (this.state) {
1059
+ case 0 /* Header */: {
1060
+ i = this.varintStep(input, i);
1061
+ if (!this.vComplete) return;
1062
+ const type = this.vTag();
1063
+ if (type === WireType.SequenceEnd) {
1064
+ this.resetVarint();
1065
+ this.endSequence();
1066
+ break;
1067
+ }
1068
+ const id = this.vUpper();
1069
+ this.resetVarint();
1070
+ if (id > ID_MAX) throw invalidMsgError(`field id ${id} out of range`);
1071
+ this.id = id;
1072
+ this.dispatch(type);
1073
+ break;
1074
+ }
1075
+ case 1 /* ScalarU */: {
1076
+ i = this.varintStep(input, i);
1077
+ if (!this.vComplete) return;
1078
+ const value = this.vUnsigned();
1079
+ this.resetVarint();
1080
+ this.top().unsigned?.(this.id, value);
1081
+ this.state = 0 /* Header */;
1082
+ break;
1083
+ }
1084
+ case 2 /* ScalarS */: {
1085
+ i = this.varintStep(input, i);
1086
+ if (!this.vComplete) return;
1087
+ const value = this.vSigned();
1088
+ this.resetVarint();
1089
+ this.top().signed?.(this.id, value);
1090
+ this.state = 0 /* Header */;
1091
+ break;
1092
+ }
1093
+ case 3 /* FixlenLen */: {
1094
+ i = this.varintStep(input, i);
1095
+ if (!this.vComplete) return;
1096
+ const sub = this.vTag();
1097
+ const len = this.vUpper();
1098
+ this.resetVarint();
1099
+ if (sub > FixlenSubtype.Blob) throw invalidMsgError(`invalid fixlen subtype ${sub}`);
1100
+ if (len > FIXLEN_MAX) throw invalidMsgError("fixlen length out of range");
1101
+ if (sub === FixlenSubtype.String && len > this.maxStringLen) {
1102
+ throw limitExceededError(`string length ${len} exceeds maxStringLen ${this.maxStringLen}`);
1103
+ }
1104
+ if (sub === FixlenSubtype.Blob && len > this.maxBlobLen) {
1105
+ throw limitExceededError(`blob length ${len} exceeds maxBlobLen ${this.maxBlobLen}`);
1106
+ }
1107
+ this.fixSub = sub;
1108
+ this.fixLen = len;
1109
+ this.fixOff = 0;
1110
+ if (sub === FixlenSubtype.Fp32 || sub === FixlenSubtype.Fp64) {
1111
+ const want = sub === FixlenSubtype.Fp32 ? 4 : 8;
1112
+ if (this.fixLen !== want) throw invalidMsgError("fixlen float length mismatch");
1113
+ this.need = want;
1114
+ this.have = 0;
1115
+ this.state = 4 /* FixlenFp */;
1116
+ } else {
1117
+ if (this.fixLen === 0) {
1118
+ this.emitBytes(input.subarray(0, 0));
1119
+ this.state = 0 /* Header */;
1120
+ } else {
1121
+ this.state = 5 /* FixlenBytes */;
1122
+ }
1123
+ }
1124
+ break;
1125
+ }
1126
+ case 4 /* FixlenFp */: {
1127
+ i = this.fpStep(input, i);
1128
+ if (this.have < this.need) return;
1129
+ const value = this.fixSub === FixlenSubtype.Fp32 ? unpackFp32(this.scratch, 0) : unpackFp64(this.scratch, 0);
1130
+ if (this.fixSub === FixlenSubtype.Fp32) this.top().fp32?.(this.id, value);
1131
+ else this.top().fp64?.(this.id, value);
1132
+ this.state = 0 /* Header */;
1133
+ break;
1134
+ }
1135
+ case 5 /* FixlenBytes */: {
1136
+ const take = Math.min(n - i, this.fixLen - this.fixOff);
1137
+ this.emitBytes(input.subarray(i, i + take));
1138
+ i += take;
1139
+ this.fixOff += take;
1140
+ if (this.fixOff === this.fixLen) this.state = 0 /* Header */;
1141
+ break;
1142
+ }
1143
+ case 6 /* ArrayCount */: {
1144
+ i = this.varintStep(input, i);
1145
+ if (!this.vComplete) return;
1146
+ const count = this.vNum();
1147
+ this.resetVarint();
1148
+ if (count > ARRAY_MAX) throw invalidMsgError("array count out of range");
1149
+ if (count > this.maxArrayCount) {
1150
+ throw limitExceededError(`array count ${count} exceeds maxArrayCount ${this.maxArrayCount}`);
1151
+ }
1152
+ this.arrCount = count;
1153
+ this.arrIndex = 0;
1154
+ if (this.arrIsFixlen) {
1155
+ this.state = 9 /* ArrayElemLen */;
1156
+ } else if (count === 0) {
1157
+ this.top().arrayBegin?.(this.id, this.arrKind, 0);
1158
+ this.top().arrayEnd?.(this.id);
1159
+ this.state = 0 /* Header */;
1160
+ } else {
1161
+ this.top().arrayBegin?.(this.id, this.arrKind, this.arrCount);
1162
+ this.state = this.arrKind === ArrayKind.Unsigned ? 7 /* ArrayUElem */ : 8 /* ArraySElem */;
1163
+ }
1164
+ break;
1165
+ }
1166
+ case 7 /* ArrayUElem */: {
1167
+ i = this.varintStep(input, i);
1168
+ if (!this.vComplete) return;
1169
+ const value = this.vUnsigned();
1170
+ this.resetVarint();
1171
+ this.top().arrayUnsigned?.(this.id, this.arrIndex, value);
1172
+ this.advanceArray();
1173
+ break;
1174
+ }
1175
+ case 8 /* ArraySElem */: {
1176
+ i = this.varintStep(input, i);
1177
+ if (!this.vComplete) return;
1178
+ const value = this.vSigned();
1179
+ this.resetVarint();
1180
+ this.top().arraySigned?.(this.id, this.arrIndex, value);
1181
+ this.advanceArray();
1182
+ break;
1183
+ }
1184
+ case 9 /* ArrayElemLen */: {
1185
+ i = this.varintStep(input, i);
1186
+ if (!this.vComplete) return;
1187
+ const sub = this.vTag();
1188
+ const size = this.vUpper();
1189
+ this.resetVarint();
1190
+ if (sub === FixlenSubtype.Fp32 && size === 4) {
1191
+ this.arrKind = ArrayKind.Fp32;
1192
+ this.need = 4;
1193
+ } else if (sub === FixlenSubtype.Fp64 && size === 8) {
1194
+ this.arrKind = ArrayKind.Fp64;
1195
+ this.need = 8;
1196
+ } else {
1197
+ throw invalidMsgError("invalid fixlen array element type");
1198
+ }
1199
+ this.top().arrayBegin?.(this.id, this.arrKind, this.arrCount);
1200
+ if (this.arrCount === 0) {
1201
+ this.top().arrayEnd?.(this.id);
1202
+ this.state = 0 /* Header */;
1203
+ } else {
1204
+ this.have = 0;
1205
+ this.state = 10 /* ArrayFp */;
1206
+ }
1207
+ break;
1208
+ }
1209
+ case 10 /* ArrayFp */: {
1210
+ i = this.fpStep(input, i);
1211
+ if (this.have < this.need) return;
1212
+ const value = this.arrKind === ArrayKind.Fp32 ? unpackFp32(this.scratch, 0) : unpackFp64(this.scratch, 0);
1213
+ if (this.arrKind === ArrayKind.Fp32) this.top().arrayFp32?.(this.id, this.arrIndex, value);
1214
+ else this.top().arrayFp64?.(this.id, this.arrIndex, value);
1215
+ this.have = 0;
1216
+ this.advanceArray();
1217
+ break;
1218
+ }
1219
+ }
1220
+ }
1221
+ }
1222
+ /**
1223
+ * Report the terminal decode outcome (MESSAGE_SPEC §7) *without* promoting it
1224
+ * to an error. Returns {@link DecodeStatus.Complete} when the stream ended
1225
+ * exactly at a field boundary, or {@link DecodeStatus.Incomplete} when it
1226
+ * ended inside a field (a partial varint, an unfinished payload / array, or a
1227
+ * still-open nested sequence). This is a pure accessor — the finish-less spec
1228
+ * has no finalize step, and a trailing `Incomplete` is a truncation the caller
1229
+ * decides how to treat, not an error this machine raises. A genuinely
1230
+ * malformed message has already thrown from {@link push}.
1231
+ */
1232
+ finish() {
1233
+ const atBoundary = this.state === 0 /* Header */ && this.vBytes === 0 && this.stack.length <= 1;
1234
+ return atBoundary ? DecodeStatus.Complete : DecodeStatus.Incomplete;
1235
+ }
1236
+ // --- helpers ------------------------------------------------------------
1237
+ dispatch(type) {
1238
+ switch (type) {
1239
+ case WireType.Unsigned:
1240
+ this.state = 1 /* ScalarU */;
1241
+ break;
1242
+ case WireType.Signed:
1243
+ this.state = 2 /* ScalarS */;
1244
+ break;
1245
+ case WireType.Fixlen:
1246
+ this.state = 3 /* FixlenLen */;
1247
+ break;
1248
+ case WireType.ArrayUnsigned:
1249
+ this.arrKind = ArrayKind.Unsigned;
1250
+ this.arrIsFixlen = false;
1251
+ this.state = 6 /* ArrayCount */;
1252
+ break;
1253
+ case WireType.ArraySigned:
1254
+ this.arrKind = ArrayKind.Signed;
1255
+ this.arrIsFixlen = false;
1256
+ this.state = 6 /* ArrayCount */;
1257
+ break;
1258
+ case WireType.ArrayFixlen:
1259
+ this.arrIsFixlen = true;
1260
+ this.state = 6 /* ArrayCount */;
1261
+ break;
1262
+ case WireType.SequenceStart: {
1263
+ if (this.stack.length - 1 >= MAX_DEPTH) {
1264
+ throw invalidMsgError(`nesting exceeds MAX_DEPTH (${MAX_DEPTH})`);
1265
+ }
1266
+ const child = this.top().sequenceBegin?.(this.id);
1267
+ this.stack.push(child ?? this.top());
1268
+ this.state = 0 /* Header */;
1269
+ break;
1270
+ }
1271
+ default:
1272
+ throw invalidMsgError(`invalid wire type ${type}`);
1273
+ }
1274
+ }
1275
+ endSequence() {
1276
+ if (this.stack.length <= 1) throw invalidMsgError("unbalanced sequence end");
1277
+ this.top().sequenceEnd?.();
1278
+ this.stack.pop();
1279
+ this.state = 0 /* Header */;
1280
+ }
1281
+ advanceArray() {
1282
+ this.arrIndex++;
1283
+ if (this.arrIndex === this.arrCount) {
1284
+ this.top().arrayEnd?.(this.id);
1285
+ this.state = 0 /* Header */;
1286
+ }
1287
+ }
1288
+ emitBytes(chunk) {
1289
+ const v = this.top();
1290
+ if (this.fixSub === FixlenSubtype.String) v.string?.(this.id, this.fixLen, this.fixOff, chunk);
1291
+ else v.blob?.(this.id, this.fixLen, this.fixOff, chunk);
1292
+ }
1293
+ top() {
1294
+ return this.stack[this.stack.length - 1];
1295
+ }
1296
+ /**
1297
+ * Consume varint bytes from `input` at `i` into the {@link vLo} / {@link vHi}
1298
+ * accumulator, resuming across chunk boundaries; sets {@link vComplete} when a
1299
+ * terminator byte arrives. Number-only — no per-byte `bigint`.
1300
+ */
1301
+ varintStep(input, i) {
1302
+ let lo = this.vLo;
1303
+ let hi = this.vHi;
1304
+ let k = this.vBytes;
1305
+ const n = input.length;
1306
+ while (i < n) {
1307
+ if (k >= VARINT_MAX_BYTES) throw invalidMsgError("varint overflow");
1308
+ const b = input[i++];
1309
+ if (k < 4) lo |= (b & 127) << 7 * k;
1310
+ else if (k === 4) {
1311
+ lo |= (b & 15) << 28;
1312
+ hi |= b >> 4 & 7;
1313
+ } else {
1314
+ if (k === 9 && (b & 127) >> 1 !== 0) throw invalidMsgError("varint overflow");
1315
+ hi |= (b & 127) << 7 * k - 32;
1316
+ }
1317
+ k++;
1318
+ if ((b & 128) === 0) {
1319
+ this.vLo = lo;
1320
+ this.vHi = hi;
1321
+ this.vBytes = k;
1322
+ this.vComplete = true;
1323
+ return i;
1324
+ }
1325
+ }
1326
+ this.vLo = lo;
1327
+ this.vHi = hi;
1328
+ this.vBytes = k;
1329
+ this.vComplete = false;
1330
+ return i;
1331
+ }
1332
+ resetVarint() {
1333
+ this.vLo = 0;
1334
+ this.vHi = 0;
1335
+ this.vBytes = 0;
1336
+ this.vComplete = false;
1337
+ }
1338
+ /** The accumulated varint as a `bigint` (full 64-bit fidelity). */
1339
+ vBig() {
1340
+ return this.vHi === 0 ? BigInt(this.vLo >>> 0) : BigInt(this.vHi >>> 0) << 32n | BigInt(this.vLo >>> 0);
1341
+ }
1342
+ /**
1343
+ * The accumulated varint as an unsigned value, number-first: a `number` when
1344
+ * it fits exactly (`≤ 2^53-1`, which covers all ids, u8..u32 and small u64s),
1345
+ * a `bigint` only beyond that. Avoids a bigint allocation on the common path.
1346
+ */
1347
+ vUnsigned() {
1348
+ const hi = this.vHi >>> 0;
1349
+ return hi <= 2097151 ? hi * TWO322 + (this.vLo >>> 0) : this.vBig();
1350
+ }
1351
+ /** The accumulated zig-zag varint as a signed value, number-first (see {@link vUnsigned}). */
1352
+ vSigned() {
1353
+ const hi = this.vHi >>> 0;
1354
+ if (hi <= 2097151) {
1355
+ const r = hi * TWO322 + (this.vLo >>> 0);
1356
+ return r % 2 === 0 ? r / 2 : -(r + 1) / 2;
1357
+ }
1358
+ return zigzagDecode(this.vBig());
1359
+ }
1360
+ /** The accumulated varint as a JS number — exact for ids/lengths/counts. */
1361
+ vNum() {
1362
+ return this.vHi * TWO322 + (this.vLo >>> 0);
1363
+ }
1364
+ /** The accumulated varint's low 3 tag bits (the wire type / fixlen subtype). */
1365
+ vTag() {
1366
+ return this.vLo & 7;
1367
+ }
1368
+ /** The accumulated varint with its low 3 tag bits stripped (`value >> 3`). */
1369
+ vUpper() {
1370
+ return (this.vHi >>> 0) * (TWO322 / 8) + (this.vLo >>> 3);
1371
+ }
1372
+ /** Accumulate `need` raw bytes into {@link scratch}. */
1373
+ fpStep(input, i) {
1374
+ while (this.have < this.need && i < input.length) {
1375
+ this.scratch[this.have++] = input[i++];
1376
+ }
1377
+ return i;
1378
+ }
1379
+ };
1380
+
1381
+ // src/decode/istream.ts
1382
+ var IStream = class {
1383
+ /**
1384
+ * @param limits Optional opt-in decode caps ({@link DecodeLimits}). An
1385
+ * over-limit array count or string / blob length throws {@link SofabError}
1386
+ * (`LIMIT_EXCEEDED`) from {@link feed}, at the offending field's header and
1387
+ * before any of its payload is streamed to the visitor. Omit for no caps.
1388
+ */
1389
+ constructor(limits) {
1390
+ this.state = new DecoderState(limits);
1391
+ }
1392
+ /**
1393
+ * Feed a chunk of bytes, dispatching decoded fields to `visitor`. Throws
1394
+ * {@link SofabError} (`INVALID_MSG`) only if the bytes are *malformed*;
1395
+ * running out of bytes mid-field is not an error — it simply suspends until
1396
+ * the next chunk (see {@link end}).
1397
+ */
1398
+ feed(chunk, visitor) {
1399
+ this.state.push(chunk, visitor);
1400
+ }
1401
+ /**
1402
+ * Report whether the stream ended exactly at a field boundary. Call after the
1403
+ * final {@link feed}: returns {@link DecodeStatus.Complete} at a clean field
1404
+ * boundary, or {@link DecodeStatus.Incomplete} if the last chunk ended inside
1405
+ * a field (a partial varint, an unfinished payload / array, or a still-open
1406
+ * nested sequence).
1407
+ *
1408
+ * Per the finish-less spec (MESSAGE_SPEC §7) this is a pure accessor: it never
1409
+ * throws and never promotes an incomplete decode to an error — the caller owns
1410
+ * end-of-input and decides whether a trailing `Incomplete` is a truncation
1411
+ * error. (A *malformed* message has already thrown from {@link feed}.)
1412
+ */
1413
+ end() {
1414
+ return this.state.finish();
1415
+ }
1416
+ };
1417
+ function decode(bytes, visitor, limits) {
1418
+ decodeContiguous(bytes, visitor, limits);
1419
+ }
1420
+
1421
+ // src/decode/cursor.ts
1422
+ var TWO323 = 4294967296;
1423
+ var _utf8 = new TextDecoder("utf-8", { fatal: true });
1424
+ var Cursor = class {
1425
+ constructor(buf, limits) {
1426
+ /** Field id of the header last accepted by {@link readHeader}. */
1427
+ this.id = 0;
1428
+ /** Wire type of the header last accepted by {@link readHeader}. */
1429
+ this.wire = 0;
1430
+ /**
1431
+ * Fixlen subtype of the header last accepted by {@link readHeader} — one of
1432
+ * {@link FixlenSubtype} — when its {@link wire} is {@link WireType.Fixlen} or
1433
+ * {@link WireType.ArrayFixlen}; `-1` otherwise (a non-fixlen field, or a
1434
+ * fixlen field whose subtype word is truncated away).
1435
+ *
1436
+ * The four fixlen subtypes (`fp32`, `fp64`, `string`, `blob`) all share one
1437
+ * {@link wire} type, so {@link wire} alone cannot separate them. This is the
1438
+ * companion accessor that can: a generated guard reads it right after
1439
+ * {@link readHeader} to skip a field whose delivered subtype contradicts the
1440
+ * schema (MESSAGE_SPEC §7.3), exactly as it already does on {@link wire} for
1441
+ * the other kinds:
1442
+ *
1443
+ * ```ts
1444
+ * case 9: if (c.wire !== WireType.Fixlen || c.fixSub !== FixlenSubtype.Fp64) {
1445
+ * c.skip(c.wire); break;
1446
+ * } o.somefp64 = c.readFp64(); break;
1447
+ * ```
1448
+ *
1449
+ * It is *peeked* — the subtype word is not consumed — so the matching typed
1450
+ * reader (or {@link skip}) still reads and validates it, and a malformed or
1451
+ * truncated word surfaces `INVALID` / `INCOMPLETE` there as before.
1452
+ */
1453
+ this.fixSub = -1;
1454
+ this.p = 0;
1455
+ // Last varint, as two unsigned 32-bit halves (see readVarint).
1456
+ this.lo = 0;
1457
+ this.hi = 0;
1458
+ // Number of nested sequences currently open (0 = root). Incremented when
1459
+ // readHeader accepts a SequenceStart, decremented when it consumes the matching
1460
+ // SequenceEnd (or when skip() discards a whole nested sequence). Lets the pull
1461
+ // parser tell a root-level dangling sequence-end (INVALID) and an unclosed
1462
+ // sequence at end-of-buffer (INCOMPLETE) apart from a clean boundary.
1463
+ this.depth = 0;
1464
+ this.buf = buf;
1465
+ this.n = buf.length;
1466
+ this.view = new DataView(buf.buffer, buf.byteOffset, buf.length);
1467
+ this.maxArrayCount = limits?.maxArrayCount ?? Infinity;
1468
+ this.maxStringLen = limits?.maxStringLen ?? Infinity;
1469
+ this.maxBlobLen = limits?.maxBlobLen ?? Infinity;
1470
+ }
1471
+ /**
1472
+ * Advance to the next field header. Returns `true` and sets {@link id} /
1473
+ * {@link wire} when a field follows; returns `false` — consuming the marker —
1474
+ * at the end of the buffer *or* at the sequence-end that closes the sequence
1475
+ * this decoder is reading. So a generated per-type decoder loops uniformly:
1476
+ *
1477
+ * ```ts
1478
+ * while (c.readHeader()) {
1479
+ * switch (c.id) {
1480
+ * case 4: this.u32 = Number(c.readUnsigned()); break;
1481
+ * case 10: this.child = Child.decodeFrom(c); break; // nested sequence
1482
+ * default: c.skip(c.wire); break; // unknown field
1483
+ * }
1484
+ * }
1485
+ * ```
1486
+ *
1487
+ * At the root the loop ends at end-of-buffer; inside a nested sequence it ends
1488
+ * at the matching {@link WireType.SequenceEnd} (which is consumed). A field
1489
+ * whose id is out of range throws {@link SofabError} (`INVALID_MSG`).
1490
+ */
1491
+ readHeader() {
1492
+ if (this.p >= this.n) {
1493
+ if (this.depth > 0) {
1494
+ throw incompleteError("truncated message: unbalanced sequence");
1495
+ }
1496
+ return false;
1497
+ }
1498
+ this.readVarint();
1499
+ const wire = this.lo & 7;
1500
+ if (wire === WireType.SequenceEnd) {
1501
+ if (this.depth === 0) {
1502
+ throw invalidMsgError("unbalanced sequence end");
1503
+ }
1504
+ this.depth--;
1505
+ return false;
1506
+ }
1507
+ const id = this.upper();
1508
+ if (id > ID_MAX) throw invalidMsgError(`field id ${id} out of range`);
1509
+ if (wire === WireType.SequenceStart) this.depth++;
1510
+ this.id = id;
1511
+ this.wire = wire;
1512
+ this.fixSub = this.peekFixSub(wire);
1513
+ return true;
1514
+ }
1515
+ /** Read an unsigned scalar (wire {@link WireType.Unsigned}), number-first. */
1516
+ readUnsigned() {
1517
+ this.readVarint();
1518
+ return this.unsignedValue();
1519
+ }
1520
+ /** Read a signed scalar (wire {@link WireType.Signed}), zig-zag, number-first. */
1521
+ readSigned() {
1522
+ this.readVarint();
1523
+ return this.signedValue();
1524
+ }
1525
+ /** Read a 32-bit float scalar (wire {@link WireType.Fixlen}, subtype fp32). */
1526
+ readFp32() {
1527
+ this.fixlenHeader(FixlenSubtype.Fp32, 4);
1528
+ return this.rawFp32();
1529
+ }
1530
+ /** Read a 64-bit float scalar (wire {@link WireType.Fixlen}, subtype fp64). */
1531
+ readFp64() {
1532
+ this.fixlenHeader(FixlenSubtype.Fp64, 8);
1533
+ return this.rawFp64();
1534
+ }
1535
+ /** Read a UTF-8 string scalar (wire {@link WireType.Fixlen}, subtype string). */
1536
+ readString() {
1537
+ const len = this.fixlenLen(FixlenSubtype.String);
1538
+ const bytes = this.take(len);
1539
+ try {
1540
+ return _utf8.decode(bytes);
1541
+ } catch {
1542
+ throw invalidMsgError("invalid UTF-8 in string");
1543
+ }
1544
+ }
1545
+ /**
1546
+ * Read a blob scalar (wire {@link WireType.Fixlen}, subtype blob) as a
1547
+ * zero-copy {@link Uint8Array} view into the source buffer.
1548
+ */
1549
+ readBlob() {
1550
+ const len = this.fixlenLen(FixlenSubtype.Blob);
1551
+ return this.take(len);
1552
+ }
1553
+ /** Read an unsigned array (wire {@link WireType.ArrayUnsigned}), number-first per element. */
1554
+ readUnsignedArray() {
1555
+ const count = this.arrayCount();
1556
+ const out = new Array(count);
1557
+ for (let i = 0; i < count; i++) {
1558
+ this.readVarint();
1559
+ out[i] = this.unsignedValue();
1560
+ }
1561
+ return out;
1562
+ }
1563
+ /** Read a signed array (wire {@link WireType.ArraySigned}), zig-zag, number-first per element. */
1564
+ readSignedArray() {
1565
+ const count = this.arrayCount();
1566
+ const out = new Array(count);
1567
+ for (let i = 0; i < count; i++) {
1568
+ this.readVarint();
1569
+ out[i] = this.signedValue();
1570
+ }
1571
+ return out;
1572
+ }
1573
+ /**
1574
+ * Read an unsigned 64-bit array into {@link Long}[] — the `bigint`-free path.
1575
+ * Each element keeps the raw lo/hi halves; call {@link Long.toBigInt} to
1576
+ * materialise only the values the caller actually needs.
1577
+ */
1578
+ readUnsignedArrayLong() {
1579
+ const count = this.arrayCount();
1580
+ const out = new Array(count);
1581
+ for (let i = 0; i < count; i++) {
1582
+ this.readVarint();
1583
+ out[i] = new Long(this.lo, this.hi);
1584
+ }
1585
+ return out;
1586
+ }
1587
+ /** Read a signed 64-bit array (zig-zag) into {@link Long}[] — the `bigint`-free path. */
1588
+ readSignedArrayLong() {
1589
+ const count = this.arrayCount();
1590
+ const out = new Array(count);
1591
+ for (let i = 0; i < count; i++) {
1592
+ this.readVarint();
1593
+ const lo = this.lo >>> 0;
1594
+ const hi = this.hi >>> 0;
1595
+ const mask = -(lo & 1) >>> 0;
1596
+ out[i] = new Long((lo >>> 1 | hi << 31) >>> 0 ^ mask, hi >>> 1 >>> 0 ^ mask);
1597
+ }
1598
+ return out;
1599
+ }
1600
+ /** Read an fp32 array (wire {@link WireType.ArrayFixlen}, element subtype fp32). */
1601
+ readFp32Array() {
1602
+ const count = this.arrayFixlenHeader(FixlenSubtype.Fp32, 4);
1603
+ const out = new Array(count);
1604
+ for (let i = 0; i < count; i++) out[i] = this.rawFp32();
1605
+ return out;
1606
+ }
1607
+ /** Read an fp64 array (wire {@link WireType.ArrayFixlen}, element subtype fp64). */
1608
+ readFp64Array() {
1609
+ const count = this.arrayFixlenHeader(FixlenSubtype.Fp64, 8);
1610
+ const out = new Array(count);
1611
+ for (let i = 0; i < count; i++) out[i] = this.rawFp64();
1612
+ return out;
1613
+ }
1614
+ /**
1615
+ * Consume the value of the field whose header {@link readHeader} just accepted,
1616
+ * discarding it — for a `default:` branch that keeps the cursor in sync on an
1617
+ * unknown id. Pass {@link wire}. A {@link WireType.SequenceStart} skips the
1618
+ * whole nested sequence.
1619
+ */
1620
+ skip(wire) {
1621
+ if (wire === WireType.SequenceStart) {
1622
+ this.skipSequence();
1623
+ this.depth--;
1624
+ return;
1625
+ }
1626
+ this.skipValue(wire);
1627
+ }
1628
+ // --- value skipping -----------------------------------------------------
1629
+ skipValue(wire) {
1630
+ switch (wire) {
1631
+ case WireType.Unsigned:
1632
+ case WireType.Signed:
1633
+ this.readVarint();
1634
+ return;
1635
+ case WireType.Fixlen: {
1636
+ this.readVarint();
1637
+ const sub = this.lo & 7;
1638
+ const len = this.upper();
1639
+ if (sub > FixlenSubtype.Blob) throw invalidMsgError(`invalid fixlen subtype ${sub}`);
1640
+ if (sub === FixlenSubtype.Fp32 || sub === FixlenSubtype.Fp64) {
1641
+ if (len !== (sub === FixlenSubtype.Fp32 ? 4 : 8)) {
1642
+ throw invalidMsgError("fixlen float length mismatch");
1643
+ }
1644
+ } else if (len > FIXLEN_MAX) {
1645
+ throw invalidMsgError("fixlen length out of range");
1646
+ }
1647
+ this.take(len);
1648
+ return;
1649
+ }
1650
+ case WireType.ArrayUnsigned:
1651
+ case WireType.ArraySigned: {
1652
+ const count = this.arrayCount();
1653
+ for (let i = 0; i < count; i++) this.readVarint();
1654
+ return;
1655
+ }
1656
+ case WireType.ArrayFixlen: {
1657
+ this.readVarint();
1658
+ const count = this.num();
1659
+ if (count > ARRAY_MAX) throw invalidMsgError("array count out of range");
1660
+ if (count > this.maxArrayCount) {
1661
+ throw limitExceededError(
1662
+ `array count ${count} exceeds maxArrayCount ${this.maxArrayCount}`
1663
+ );
1664
+ }
1665
+ this.readVarint();
1666
+ const sub = this.lo & 7;
1667
+ const size = this.upper();
1668
+ const ok = sub === FixlenSubtype.Fp32 && size === 4 || sub === FixlenSubtype.Fp64 && size === 8;
1669
+ if (!ok) throw invalidMsgError("invalid fixlen array element type");
1670
+ this.take(count * size);
1671
+ return;
1672
+ }
1673
+ default:
1674
+ throw invalidMsgError(`invalid wire type ${wire}`);
1675
+ }
1676
+ }
1677
+ skipSequence() {
1678
+ let depth = 1;
1679
+ while (depth > 0) {
1680
+ if (this.p >= this.n) throw incompleteError("truncated message: unbalanced sequence");
1681
+ this.readVarint();
1682
+ const wire = this.lo & 7;
1683
+ if (wire === WireType.SequenceEnd) {
1684
+ depth--;
1685
+ continue;
1686
+ }
1687
+ const id = this.upper();
1688
+ if (id > ID_MAX) throw invalidMsgError(`field id ${id} out of range`);
1689
+ if (wire === WireType.SequenceStart) depth++;
1690
+ else this.skipValue(wire);
1691
+ }
1692
+ }
1693
+ // --- field helpers ------------------------------------------------------
1694
+ /**
1695
+ * Peek the delivered fixlen subtype of the field {@link readHeader} just
1696
+ * accepted, **without advancing the cursor** — the readers / {@link skip}
1697
+ * still re-read and validate the word. Returns one of {@link FixlenSubtype}
1698
+ * (0..3), a reserved value (4..7), or `-1` when the wire is not a fixlen kind
1699
+ * or the subtype word is truncated away.
1700
+ *
1701
+ * The subtype is the low 3 bits of the fixlen sub-header word, and the low
1702
+ * bits of a LEB128 word live entirely in its **first** byte — so this only
1703
+ * reads one byte, it never decodes a varint.
1704
+ */
1705
+ peekFixSub(wire) {
1706
+ if (wire === WireType.Fixlen) {
1707
+ return this.p < this.n ? this.buf[this.p] & 7 : -1;
1708
+ }
1709
+ if (wire === WireType.ArrayFixlen) {
1710
+ let p = this.p;
1711
+ while (p < this.n && this.buf[p] >= 128) p++;
1712
+ p++;
1713
+ return p < this.n ? this.buf[p] & 7 : -1;
1714
+ }
1715
+ return -1;
1716
+ }
1717
+ /** Read and validate an array count word (0..ARRAY_MAX; §4.7/§4.8). */
1718
+ arrayCount() {
1719
+ this.readVarint();
1720
+ const count = this.num();
1721
+ if (count > ARRAY_MAX) throw invalidMsgError("array count out of range");
1722
+ if (count > this.maxArrayCount) {
1723
+ throw limitExceededError(
1724
+ `array count ${count} exceeds maxArrayCount ${this.maxArrayCount}`
1725
+ );
1726
+ }
1727
+ if (count > this.n - this.p) throw incompleteError("truncated array");
1728
+ return count;
1729
+ }
1730
+ /** Read a scalar fixlen sub-header, asserting subtype and exact byte length (floats). */
1731
+ fixlenHeader(wantSub, wantLen) {
1732
+ this.readVarint();
1733
+ const sub = this.lo & 7;
1734
+ const len = this.upper();
1735
+ if (sub !== wantSub) throw invalidMsgError(`invalid fixlen subtype ${sub}`);
1736
+ if (len !== wantLen) throw invalidMsgError("fixlen float length mismatch");
1737
+ }
1738
+ /** Read a scalar fixlen sub-header for a string/blob, asserting subtype; returns byte length. */
1739
+ fixlenLen(wantSub) {
1740
+ this.readVarint();
1741
+ const sub = this.lo & 7;
1742
+ const len = this.upper();
1743
+ if (sub !== wantSub) throw invalidMsgError(`invalid fixlen subtype ${sub}`);
1744
+ if (len > FIXLEN_MAX) throw invalidMsgError("fixlen length out of range");
1745
+ const limit = wantSub === FixlenSubtype.String ? this.maxStringLen : this.maxBlobLen;
1746
+ if (len > limit) {
1747
+ const what = wantSub === FixlenSubtype.String ? "string" : "blob";
1748
+ const name = wantSub === FixlenSubtype.String ? "maxStringLen" : "maxBlobLen";
1749
+ throw limitExceededError(
1750
+ `${what} length ${len} exceeds ${name} ${limit}`
1751
+ );
1752
+ }
1753
+ return len;
1754
+ }
1755
+ /** Read an array fixlen element header (count + element type); returns the count. */
1756
+ arrayFixlenHeader(wantSub, wantSize) {
1757
+ this.readVarint();
1758
+ const count = this.num();
1759
+ if (count > ARRAY_MAX) throw invalidMsgError("array count out of range");
1760
+ if (count > this.maxArrayCount) {
1761
+ throw limitExceededError(
1762
+ `array count ${count} exceeds maxArrayCount ${this.maxArrayCount}`
1763
+ );
1764
+ }
1765
+ this.readVarint();
1766
+ const sub = this.lo & 7;
1767
+ const size = this.upper();
1768
+ if (sub !== wantSub || size !== wantSize) {
1769
+ throw invalidMsgError("invalid fixlen array element type");
1770
+ }
1771
+ if (count > (this.n - this.p) / wantSize) {
1772
+ throw incompleteError("truncated fixlen array");
1773
+ }
1774
+ return count;
1775
+ }
1776
+ /** Hand back a zero-copy view of the next `len` bytes, advancing the cursor. */
1777
+ take(len) {
1778
+ const start = this.p;
1779
+ const end = start + len;
1780
+ if (end > this.n) throw incompleteError("truncated fixlen payload");
1781
+ this.p = end;
1782
+ return this.buf.subarray(start, end);
1783
+ }
1784
+ rawFp32() {
1785
+ const p = this.p;
1786
+ if (p + 4 > this.n) throw incompleteError("truncated fp32");
1787
+ this.p = p + 4;
1788
+ return this.view.getFloat32(p, true);
1789
+ }
1790
+ rawFp64() {
1791
+ const p = this.p;
1792
+ if (p + 8 > this.n) throw incompleteError("truncated fp64");
1793
+ this.p = p + 8;
1794
+ return this.view.getFloat64(p, true);
1795
+ }
1796
+ // --- varint reading (shared verbatim with ./fast) -----------------------
1797
+ /**
1798
+ * The last varint's full value as a `bigint` (64-bit fidelity). Only ever
1799
+ * called from {@link unsignedValue} / {@link signedValue} on the `hi` overflow
1800
+ * path (`this.hi >>> 0 > 0x1fffff`), so `hi` is always non-zero here.
1801
+ */
1802
+ big() {
1803
+ return BigInt(this.hi >>> 0) << 32n | BigInt(this.lo >>> 0);
1804
+ }
1805
+ /**
1806
+ * The last varint as an unsigned value, number-first: a `number` when it fits
1807
+ * exactly (`≤ 2^53-1`), a `bigint` only beyond that.
1808
+ */
1809
+ unsignedValue() {
1810
+ const hi = this.hi >>> 0;
1811
+ return hi <= 2097151 ? hi * TWO323 + (this.lo >>> 0) : this.big();
1812
+ }
1813
+ /** The last zig-zag varint as a signed value, number-first. */
1814
+ signedValue() {
1815
+ const hi = this.hi >>> 0;
1816
+ if (hi <= 2097151) {
1817
+ const r = hi * TWO323 + (this.lo >>> 0);
1818
+ return r % 2 === 0 ? r / 2 : -(r + 1) / 2;
1819
+ }
1820
+ return zigzagDecode(this.big());
1821
+ }
1822
+ /** The last varint's value as a JS number — exact for ids/lengths/counts. */
1823
+ num() {
1824
+ return this.hi * TWO323 + (this.lo >>> 0);
1825
+ }
1826
+ /** The last varint with its low 3 tag bits stripped (`value >> 3`). */
1827
+ upper() {
1828
+ return (this.hi >>> 0) * (TWO323 / 8) + (this.lo >>> 3);
1829
+ }
1830
+ /**
1831
+ * Decode one LEB128 varint at the cursor into {@link lo} / {@link hi} (each an
1832
+ * unsigned 32-bit half), advancing {@link p}. Throws on truncation or a value
1833
+ * spilling past 64 bits (>10 bytes). Unrolled, number-only — no `bigint`.
1834
+ */
1835
+ readVarint() {
1836
+ const buf = this.buf;
1837
+ const n = this.n;
1838
+ let p = this.p;
1839
+ let b;
1840
+ let lo;
1841
+ let hi = 0;
1842
+ if (p >= n) throw incompleteError("truncated varint");
1843
+ b = buf[p++];
1844
+ lo = b & 127;
1845
+ if (b < 128) return this.set(lo, 0, p);
1846
+ if (p >= n) throw incompleteError("truncated varint");
1847
+ b = buf[p++];
1848
+ lo |= (b & 127) << 7;
1849
+ if (b < 128) return this.set(lo, 0, p);
1850
+ if (p >= n) throw incompleteError("truncated varint");
1851
+ b = buf[p++];
1852
+ lo |= (b & 127) << 14;
1853
+ if (b < 128) return this.set(lo, 0, p);
1854
+ if (p >= n) throw incompleteError("truncated varint");
1855
+ b = buf[p++];
1856
+ lo |= (b & 127) << 21;
1857
+ if (b < 128) return this.set(lo, 0, p);
1858
+ if (p >= n) throw incompleteError("truncated varint");
1859
+ b = buf[p++];
1860
+ lo |= (b & 15) << 28;
1861
+ hi = b >> 4 & 7;
1862
+ if (b < 128) return this.set(lo, hi, p);
1863
+ if (p >= n) throw incompleteError("truncated varint");
1864
+ b = buf[p++];
1865
+ hi |= (b & 127) << 3;
1866
+ if (b < 128) return this.set(lo, hi, p);
1867
+ if (p >= n) throw incompleteError("truncated varint");
1868
+ b = buf[p++];
1869
+ hi |= (b & 127) << 10;
1870
+ if (b < 128) return this.set(lo, hi, p);
1871
+ if (p >= n) throw incompleteError("truncated varint");
1872
+ b = buf[p++];
1873
+ hi |= (b & 127) << 17;
1874
+ if (b < 128) return this.set(lo, hi, p);
1875
+ if (p >= n) throw incompleteError("truncated varint");
1876
+ b = buf[p++];
1877
+ hi |= (b & 127) << 24;
1878
+ if (b < 128) return this.set(lo, hi, p);
1879
+ if (p >= n) throw incompleteError("truncated varint");
1880
+ b = buf[p++];
1881
+ if ((b & 127) >> 1 !== 0) throw invalidMsgError("varint overflow");
1882
+ hi |= (b & 127) << 31;
1883
+ if (b < 128) return this.set(lo, hi, p);
1884
+ throw invalidMsgError("varint overflow");
1885
+ }
1886
+ set(lo, hi, p) {
1887
+ this.lo = lo;
1888
+ this.hi = hi;
1889
+ this.p = p;
1890
+ }
1891
+ };
1892
+
1893
+ // src/backend/native.ts
1894
+ var NATIVE_PACKAGE = "@sofa-buffers/corelib-native";
1895
+ function isNode() {
1896
+ return typeof process !== "undefined" && !!process.versions?.node;
1897
+ }
1898
+ async function loadNativeKernel() {
1899
+ if (!isNode()) return false;
1900
+ try {
1901
+ const { createRequire } = await import('module');
1902
+ const require2 = createRequire(import.meta.url);
1903
+ const mod = require2(NATIVE_PACKAGE);
1904
+ const kernel = mod.kernel ?? mod;
1905
+ setKernel(kernel);
1906
+ return true;
1907
+ } catch {
1908
+ return false;
1909
+ }
1910
+ }
1911
+
1912
+ // src/backend/wasm.ts
1913
+ async function loadWasmKernel(source, factory, imports = {}) {
1914
+ let instance;
1915
+ if (source instanceof WebAssembly.Module) {
1916
+ instance = await WebAssembly.instantiate(source, imports);
1917
+ } else if (typeof Response !== "undefined" && (source instanceof Response || isThenable(source))) {
1918
+ const result = await WebAssembly.instantiateStreaming(
1919
+ source,
1920
+ imports
1921
+ );
1922
+ instance = result.instance;
1923
+ } else {
1924
+ const result = await WebAssembly.instantiate(source, imports);
1925
+ instance = result.instance;
1926
+ }
1927
+ setKernel(factory(instance.exports));
1928
+ return true;
1929
+ }
1930
+ function isThenable(x) {
1931
+ return typeof x === "object" && x !== null && typeof x.then === "function";
1932
+ }
1933
+
1934
+ export { API_VERSION, ARRAY_MAX, ArrayKind, Cursor, DecodeStatus, FIXLEN_MAX, FixlenSubtype, I64_MAX, I64_MIN, ID_MAX, IStream, Long, MAX_DEPTH, OStream, SofabError, SofabErrorCode, U64_MAX, WireType, decode, getKernel, jsKernel, loadNativeKernel, loadWasmKernel, setKernel, public_exports as sofab };
1935
+ //# sourceMappingURL=index.js.map
1936
+ //# sourceMappingURL=index.js.map