json-as 1.5.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -1
- package/README.md +42 -0
- package/assembly/deserialize/error.ts +21 -0
- package/assembly/deserialize/index/arbitrary.ts +29 -8
- package/assembly/deserialize/index/array.ts +2 -1
- package/assembly/deserialize/index/bool.ts +1 -1
- package/assembly/deserialize/index/object.ts +3 -0
- package/assembly/deserialize/index/string.ts +37 -0
- package/assembly/deserialize/index.ts +0 -1
- package/assembly/deserialize/naive/array/arbitrary.ts +3 -2
- package/assembly/deserialize/naive/array/array.ts +1 -0
- package/assembly/deserialize/naive/array/bool.ts +21 -11
- package/assembly/deserialize/naive/array/box.ts +13 -33
- package/assembly/deserialize/naive/array/float.ts +23 -13
- package/assembly/deserialize/naive/array/integer.ts +33 -21
- package/assembly/deserialize/naive/array/object.ts +1 -0
- package/assembly/deserialize/naive/array/string.ts +29 -16
- package/assembly/deserialize/naive/bool.ts +17 -5
- package/assembly/deserialize/naive/float.ts +1 -2
- package/assembly/deserialize/naive/map.ts +339 -39
- package/assembly/deserialize/naive/object.ts +122 -65
- package/assembly/deserialize/naive/raw.ts +13 -1
- package/assembly/deserialize/naive/set.ts +0 -1
- package/assembly/deserialize/naive/staticarray.ts +3 -2
- package/assembly/deserialize/naive/string.ts +41 -52
- package/assembly/deserialize/parseMode.ts +216 -0
- package/assembly/deserialize/simd/array/integer.ts +6 -3
- package/assembly/deserialize/simd/float.ts +35 -29
- package/assembly/deserialize/simd/string.ts +79 -17
- package/assembly/deserialize/string-validation.ts +34 -0
- package/assembly/deserialize/swar/array/array.ts +63 -13
- package/assembly/deserialize/swar/array/bool.ts +14 -3
- package/assembly/deserialize/swar/array/float.ts +394 -13
- package/assembly/deserialize/swar/array/generic.ts +12 -2
- package/assembly/deserialize/swar/array/integer.ts +22 -62
- package/assembly/deserialize/swar/array/object.ts +11 -2
- package/assembly/deserialize/swar/array/shared.ts +1 -1
- package/assembly/deserialize/swar/array/string.ts +34 -5
- package/assembly/deserialize/swar/array/struct.ts +109 -15
- package/assembly/deserialize/swar/float.ts +19 -12
- package/assembly/deserialize/swar/string.ts +70 -111
- package/assembly/index.d.ts +6 -0
- package/assembly/index.ts +411 -33
- package/assembly/serialize/index/bool.ts +1 -1
- package/assembly/serialize/index/float.ts +1 -5
- package/assembly/serialize/index/integer.ts +1 -1
- package/assembly/serialize/index/object.ts +17 -0
- package/assembly/serialize/naive/array.ts +64 -0
- package/assembly/serialize/naive/float.ts +0 -5
- package/assembly/serialize/naive/map.ts +37 -0
- package/assembly/serialize/naive/set.ts +0 -1
- package/assembly/serialize/naive/staticarray.ts +0 -1
- package/assembly/serialize/naive/string.ts +0 -6
- package/assembly/serialize/naive/typedarray.ts +0 -1
- package/assembly/util/eisel-lemire.ts +179 -0
- package/assembly/util/prettyWhitespaceSimd.ts +69 -0
- package/assembly/util/scanValueEndSimd.ts +59 -36
- package/assembly/util/validateJson.ts +338 -0
- package/lib/as-bs.ts +28 -6
- package/package.json +17 -7
- package/transform/lib/index.d.ts +6 -0
- package/transform/lib/index.js +773 -112
- package/transform/lib/types.d.ts +1 -0
- package/transform/lib/types.js +3 -0
- package/assembly/deserialize/index/struct.ts +0 -1
- package/assembly/deserialize/naive/struct.ts +0 -21
|
@@ -4,6 +4,8 @@ import { __heap_base } from "memory";
|
|
|
4
4
|
import { BACK_SLASH, QUOTE } from "../../custom/chars";
|
|
5
5
|
import { DESERIALIZE_ESCAPE_TABLE } from "../../globals/tables";
|
|
6
6
|
import { hex4_to_u16_swar } from "../../util/swar";
|
|
7
|
+
import { markProductionParseError } from "../error";
|
|
8
|
+
import { isValidStringEscape } from "../string-validation";
|
|
7
9
|
|
|
8
10
|
// Overflow Pattern for Unicode Escapes (READ)
|
|
9
11
|
// \u0001 0 \u00|01__ + 4
|
|
@@ -71,7 +73,7 @@ function deserializeEscapedString_SWAR(
|
|
|
71
73
|
}
|
|
72
74
|
|
|
73
75
|
let srcStart = escapeStart;
|
|
74
|
-
const srcEnd8 = srcEnd
|
|
76
|
+
const srcEnd8 = srcEnd - 8;
|
|
75
77
|
|
|
76
78
|
while (srcStart <= srcEnd8) {
|
|
77
79
|
const block = load<u64>(srcStart);
|
|
@@ -107,6 +109,11 @@ function deserializeEscapedString_SWAR(
|
|
|
107
109
|
const srcIdx = srcStart + laneIdx;
|
|
108
110
|
if ((load<u32>(srcIdx) & 0xffff) !== 0x5c) continue; // false positive
|
|
109
111
|
bs.offset += laneIdx;
|
|
112
|
+
if (!isValidStringEscape(srcIdx, srcEnd)) {
|
|
113
|
+
bs.offset = bs.buffer + outStart;
|
|
114
|
+
markProductionParseError();
|
|
115
|
+
return changetype<string>(0);
|
|
116
|
+
}
|
|
110
117
|
const code = load<u16>(srcIdx, 2);
|
|
111
118
|
if (code !== 0x75) {
|
|
112
119
|
store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + code));
|
|
@@ -134,6 +141,11 @@ function deserializeEscapedString_SWAR(
|
|
|
134
141
|
srcStart += 2;
|
|
135
142
|
continue;
|
|
136
143
|
}
|
|
144
|
+
if (!isValidStringEscape(srcStart, srcEnd)) {
|
|
145
|
+
bs.offset = bs.buffer + outStart;
|
|
146
|
+
markProductionParseError();
|
|
147
|
+
return changetype<string>(0);
|
|
148
|
+
}
|
|
137
149
|
const code = load<u16>(srcStart, 2);
|
|
138
150
|
if (code !== 0x75) {
|
|
139
151
|
store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + code));
|
|
@@ -256,16 +268,25 @@ function deserializeEscapedStringField_SWAR(
|
|
|
256
268
|
): usize {
|
|
257
269
|
const prefixLen = <u32>(escapeStart - payloadStart);
|
|
258
270
|
bs.offset = bs.buffer;
|
|
259
|
-
|
|
271
|
+
// `srcEnd` may be the end of a containing map/document when a generated
|
|
272
|
+
// parser is cursor-driven. Reserving that entire remainder for one escaped
|
|
273
|
+
// field retained multi-megabyte scratch buffers. Grow with the decoded
|
|
274
|
+
// string instead; escapes only shrink relative to the source.
|
|
275
|
+
bs.ensureSize(prefixLen + 1024);
|
|
260
276
|
if (prefixLen != 0) {
|
|
261
277
|
memory.copy(bs.buffer, payloadStart, prefixLen);
|
|
262
278
|
bs.offset += prefixLen;
|
|
263
279
|
}
|
|
264
280
|
|
|
265
281
|
let srcStart = escapeStart;
|
|
266
|
-
const srcEnd8 = srcEnd
|
|
282
|
+
const srcEnd8 = srcEnd - 8;
|
|
283
|
+
let scratchEnd = bs.buffer + bs.bufferSize - 8;
|
|
267
284
|
|
|
268
285
|
while (srcStart <= srcEnd8) {
|
|
286
|
+
if (bs.offset > scratchEnd) {
|
|
287
|
+
bs.ensureSize(1024);
|
|
288
|
+
scratchEnd = bs.buffer + bs.bufferSize - 8;
|
|
289
|
+
}
|
|
269
290
|
const block = load<u64>(srcStart);
|
|
270
291
|
let mask = backslash_or_quote_mask(block);
|
|
271
292
|
if (mask == 0) {
|
|
@@ -285,6 +306,10 @@ function deserializeEscapedStringField_SWAR(
|
|
|
285
306
|
srcStart += 8;
|
|
286
307
|
}
|
|
287
308
|
const runLen = <u32>(srcStart - runStart);
|
|
309
|
+
if (bs.offset + runLen > scratchEnd) {
|
|
310
|
+
bs.ensureSize(runLen + 1024);
|
|
311
|
+
scratchEnd = bs.buffer + bs.bufferSize - 8;
|
|
312
|
+
}
|
|
288
313
|
memory.copy(bs.offset, runStart, runLen);
|
|
289
314
|
bs.offset += runLen;
|
|
290
315
|
}
|
|
@@ -310,6 +335,11 @@ function deserializeEscapedStringField_SWAR(
|
|
|
310
335
|
bs.offset = bs.buffer;
|
|
311
336
|
return srcIdx + 2;
|
|
312
337
|
}
|
|
338
|
+
if (!isValidStringEscape(srcIdx, srcEnd)) {
|
|
339
|
+
bs.offset = bs.buffer;
|
|
340
|
+
markProductionParseError();
|
|
341
|
+
return 0;
|
|
342
|
+
}
|
|
313
343
|
const code = load<u16>(srcIdx, 2);
|
|
314
344
|
if (code !== 0x75) {
|
|
315
345
|
store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + code));
|
|
@@ -330,6 +360,7 @@ function deserializeEscapedStringField_SWAR(
|
|
|
330
360
|
}
|
|
331
361
|
|
|
332
362
|
// scalar tail (< 8 bytes remaining)
|
|
363
|
+
bs.ensureSize(<u32>(srcEnd - srcStart) + 2);
|
|
333
364
|
while (srcStart < srcEnd) {
|
|
334
365
|
const char = load<u16>(srcStart);
|
|
335
366
|
if (char == QUOTE) {
|
|
@@ -343,6 +374,11 @@ function deserializeEscapedStringField_SWAR(
|
|
|
343
374
|
srcStart += 2;
|
|
344
375
|
continue;
|
|
345
376
|
}
|
|
377
|
+
if (!isValidStringEscape(srcStart, srcEnd)) {
|
|
378
|
+
bs.offset = bs.buffer;
|
|
379
|
+
markProductionParseError();
|
|
380
|
+
return 0;
|
|
381
|
+
}
|
|
346
382
|
const code = load<u16>(srcStart, 2);
|
|
347
383
|
if (code !== 0x75) {
|
|
348
384
|
store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + code));
|
|
@@ -356,122 +392,37 @@ function deserializeEscapedStringField_SWAR(
|
|
|
356
392
|
}
|
|
357
393
|
|
|
358
394
|
bs.offset = bs.buffer;
|
|
359
|
-
|
|
360
|
-
return
|
|
395
|
+
markProductionParseError();
|
|
396
|
+
return 0;
|
|
361
397
|
}
|
|
362
398
|
|
|
363
|
-
function
|
|
364
|
-
lastPtr: usize,
|
|
399
|
+
export function deserializeStringField_SWAR<T extends string | null>(
|
|
365
400
|
srcStart: usize,
|
|
366
401
|
srcEnd: usize,
|
|
367
|
-
|
|
402
|
+
dstObj: usize,
|
|
403
|
+
dstOffset: usize = 0,
|
|
368
404
|
): usize {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
const blockStart = srcStart;
|
|
373
|
-
let mask = backslash_or_quote_mask(load<u64>(srcStart));
|
|
374
|
-
if (mask === 0) {
|
|
375
|
-
srcStart += 8;
|
|
376
|
-
continue;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
do {
|
|
380
|
-
const laneIdx = usize(ctz(mask) >> 3);
|
|
381
|
-
mask &= mask - 1;
|
|
382
|
-
const srcIdx = srcStart + laneIdx;
|
|
383
|
-
const char = load<u16>(srcIdx);
|
|
384
|
-
if (char == QUOTE) {
|
|
385
|
-
const runLen = <u32>(srcIdx - lastPtr);
|
|
386
|
-
if (runLen != 0) {
|
|
387
|
-
memory.copy(bs.offset, lastPtr, runLen);
|
|
388
|
-
bs.offset += runLen;
|
|
389
|
-
}
|
|
390
|
-
writeStringToField(
|
|
391
|
-
dstFieldPtr,
|
|
392
|
-
bs.buffer,
|
|
393
|
-
<u32>(bs.offset - bs.buffer),
|
|
394
|
-
);
|
|
395
|
-
bs.offset = bs.buffer;
|
|
396
|
-
return srcIdx + 2;
|
|
397
|
-
}
|
|
398
|
-
if (char != BACK_SLASH) continue;
|
|
399
|
-
|
|
400
|
-
const runLen = <u32>(srcIdx - lastPtr);
|
|
401
|
-
if (runLen != 0) {
|
|
402
|
-
memory.copy(bs.offset, lastPtr, runLen);
|
|
403
|
-
bs.offset += runLen;
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
const chunk = load<u32>(srcIdx);
|
|
407
|
-
const code = <u16>(chunk >> 16);
|
|
408
|
-
if (code !== 0x75) {
|
|
409
|
-
store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + code));
|
|
410
|
-
bs.offset += 2;
|
|
411
|
-
lastPtr = srcIdx + 4;
|
|
412
|
-
} else {
|
|
413
|
-
store<u16>(bs.offset, hex4_to_u16_swar(load<u64>(srcIdx, 4)));
|
|
414
|
-
bs.offset += 2;
|
|
415
|
-
lastPtr = srcIdx + 12;
|
|
416
|
-
}
|
|
417
|
-
srcStart = lastPtr;
|
|
418
|
-
break;
|
|
419
|
-
} while (mask !== 0);
|
|
420
|
-
|
|
421
|
-
if (srcStart == blockStart) srcStart += 8;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
while (srcStart < srcEnd) {
|
|
425
|
-
const tailChar = load<u16>(srcStart);
|
|
426
|
-
if (tailChar == QUOTE) {
|
|
427
|
-
const runLen = <u32>(srcStart - lastPtr);
|
|
428
|
-
if (runLen != 0) {
|
|
429
|
-
memory.copy(bs.offset, lastPtr, runLen);
|
|
430
|
-
bs.offset += runLen;
|
|
431
|
-
}
|
|
432
|
-
writeStringToField(dstFieldPtr, bs.buffer, <u32>(bs.offset - bs.buffer));
|
|
433
|
-
bs.offset = bs.buffer;
|
|
434
|
-
return srcStart + 2;
|
|
435
|
-
}
|
|
436
|
-
if (tailChar != BACK_SLASH) {
|
|
437
|
-
srcStart += 2;
|
|
438
|
-
continue;
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
const runLen = <u32>(srcStart - lastPtr);
|
|
442
|
-
if (runLen != 0) {
|
|
443
|
-
memory.copy(bs.offset, lastPtr, runLen);
|
|
444
|
-
bs.offset += runLen;
|
|
445
|
-
}
|
|
446
|
-
const tailCode = load<u16>(srcStart, 2);
|
|
447
|
-
if (tailCode !== 0x75) {
|
|
448
|
-
store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + tailCode));
|
|
449
|
-
bs.offset += 2;
|
|
450
|
-
srcStart += 4;
|
|
451
|
-
} else {
|
|
452
|
-
store<u16>(bs.offset, hex4_to_u16_swar(load<u64>(srcStart, 4)));
|
|
453
|
-
bs.offset += 2;
|
|
454
|
-
srcStart += 12;
|
|
455
|
-
}
|
|
456
|
-
lastPtr = srcStart;
|
|
405
|
+
if (srcStart + 2 > srcEnd || load<u16>(srcStart) != QUOTE) {
|
|
406
|
+
markProductionParseError();
|
|
407
|
+
return 0;
|
|
457
408
|
}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
409
|
+
return deserializeStringFieldTrusted_SWAR(
|
|
410
|
+
srcStart + 2,
|
|
411
|
+
srcEnd,
|
|
412
|
+
dstObj,
|
|
413
|
+
dstOffset,
|
|
414
|
+
);
|
|
461
415
|
}
|
|
462
416
|
|
|
463
|
-
export function
|
|
464
|
-
|
|
417
|
+
export function deserializeStringFieldTrusted_SWAR(
|
|
418
|
+
payloadStart: usize,
|
|
465
419
|
srcEnd: usize,
|
|
466
420
|
dstObj: usize,
|
|
467
421
|
dstOffset: usize = 0,
|
|
468
422
|
): usize {
|
|
469
423
|
const dstFieldPtr = dstObj + dstOffset;
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
const payloadStart = srcStart + 2;
|
|
474
|
-
srcStart = payloadStart;
|
|
424
|
+
let srcStart = payloadStart;
|
|
425
|
+
let pendingMask: u64 = 0;
|
|
475
426
|
|
|
476
427
|
// Wide pre-scan: skip 16 bytes per iter while both halves are clean. The
|
|
477
428
|
// common case (plain ASCII payloads, no escape) hits this loop exclusively
|
|
@@ -482,9 +433,15 @@ export function deserializeStringField_SWAR<T extends string | null>(
|
|
|
482
433
|
// Test the first word before loading the second: short values and keys
|
|
483
434
|
// close (or escape) within the first 8 bytes, so this skips the second
|
|
484
435
|
// load on the common case while still skipping 16 bytes when both clean.
|
|
485
|
-
|
|
486
|
-
if (
|
|
436
|
+
const firstMask = backslash_or_quote_mask(load<u64>(srcStart));
|
|
437
|
+
if (firstMask != 0) {
|
|
438
|
+
pendingMask = firstMask;
|
|
439
|
+
break;
|
|
440
|
+
}
|
|
441
|
+
const secondMask = backslash_or_quote_mask(load<u64>(srcStart, 8));
|
|
442
|
+
if (secondMask != 0) {
|
|
487
443
|
srcStart += 8;
|
|
444
|
+
pendingMask = secondMask;
|
|
488
445
|
break;
|
|
489
446
|
}
|
|
490
447
|
srcStart += 16;
|
|
@@ -493,7 +450,9 @@ export function deserializeStringField_SWAR<T extends string | null>(
|
|
|
493
450
|
|
|
494
451
|
const srcEnd8 = srcEnd - 8;
|
|
495
452
|
while (srcStart <= srcEnd8) {
|
|
496
|
-
let mask =
|
|
453
|
+
let mask = pendingMask;
|
|
454
|
+
if (mask == 0) mask = backslash_or_quote_mask(load<u64>(srcStart));
|
|
455
|
+
pendingMask = 0;
|
|
497
456
|
if (mask === 0) {
|
|
498
457
|
srcStart += 8;
|
|
499
458
|
continue;
|
|
@@ -545,8 +504,8 @@ export function deserializeStringField_SWAR<T extends string | null>(
|
|
|
545
504
|
srcStart += 2;
|
|
546
505
|
}
|
|
547
506
|
|
|
548
|
-
|
|
549
|
-
return
|
|
507
|
+
markProductionParseError();
|
|
508
|
+
return 0;
|
|
550
509
|
}
|
|
551
510
|
|
|
552
511
|
/**
|
package/assembly/index.d.ts
CHANGED
|
@@ -267,6 +267,12 @@ declare function deserializer(
|
|
|
267
267
|
*/
|
|
268
268
|
declare const JSON_MODE: JSONMode;
|
|
269
269
|
|
|
270
|
+
/**
|
|
271
|
+
* Whether strict RFC 8259 validation is enabled. Injected by the transform from
|
|
272
|
+
* the `JSON_STRICT` build-time environment variable (default `false`).
|
|
273
|
+
*/
|
|
274
|
+
declare const JSON_STRICT: bool;
|
|
275
|
+
|
|
270
276
|
/**
|
|
271
277
|
* Whether the string cache is enabled (default off). Injected from the
|
|
272
278
|
* `JSON_CACHE` build-time environment variable. When on, repeated strings are
|