json-as 1.4.0 → 1.6.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 (108) hide show
  1. package/CHANGELOG.md +54 -29
  2. package/README.md +126 -33
  3. package/assembly/custom/chars.ts +39 -78
  4. package/assembly/deserialize/error.ts +21 -0
  5. package/assembly/deserialize/index/arbitrary.ts +50 -11
  6. package/assembly/deserialize/index/array.ts +2 -1
  7. package/assembly/deserialize/index/bool.ts +1 -1
  8. package/assembly/deserialize/index/float.ts +2 -4
  9. package/assembly/deserialize/index/integer.ts +2 -4
  10. package/assembly/deserialize/index/object.ts +9 -1
  11. package/assembly/deserialize/index/string.ts +39 -7
  12. package/assembly/deserialize/index/unsigned.ts +2 -4
  13. package/assembly/deserialize/index.ts +0 -1
  14. package/assembly/deserialize/naive/array/arbitrary.ts +3 -2
  15. package/assembly/deserialize/naive/array/array.ts +1 -0
  16. package/assembly/deserialize/naive/array/bool.ts +21 -11
  17. package/assembly/deserialize/naive/array/box.ts +13 -33
  18. package/assembly/deserialize/naive/array/float.ts +23 -13
  19. package/assembly/deserialize/naive/array/integer.ts +34 -22
  20. package/assembly/deserialize/naive/array/map.ts +1 -1
  21. package/assembly/deserialize/naive/array/object.ts +2 -1
  22. package/assembly/deserialize/naive/array/string.ts +29 -16
  23. package/assembly/deserialize/naive/array/struct.ts +19 -1
  24. package/assembly/deserialize/naive/bool.ts +18 -10
  25. package/assembly/deserialize/naive/date.ts +1 -2
  26. package/assembly/deserialize/naive/float.ts +3 -9
  27. package/assembly/deserialize/naive/integer.ts +1 -2
  28. package/assembly/deserialize/naive/map.ts +342 -43
  29. package/assembly/deserialize/naive/object.ts +250 -55
  30. package/assembly/deserialize/naive/raw.ts +10 -2
  31. package/assembly/deserialize/naive/set.ts +2 -5
  32. package/assembly/deserialize/naive/staticarray.ts +4 -4
  33. package/assembly/deserialize/naive/string.ts +46 -60
  34. package/assembly/deserialize/naive/unsigned.ts +1 -2
  35. package/assembly/deserialize/parseMode.ts +216 -0
  36. package/assembly/deserialize/simd/array/integer.ts +8 -10
  37. package/assembly/deserialize/simd/float.ts +38 -34
  38. package/assembly/deserialize/simd/integer.ts +2 -7
  39. package/assembly/deserialize/simd/string.ts +84 -39
  40. package/assembly/deserialize/string-validation.ts +34 -0
  41. package/assembly/deserialize/swar/array/arbitrary.ts +1 -2
  42. package/assembly/deserialize/swar/array/array.ts +64 -15
  43. package/assembly/deserialize/swar/array/bool.ts +15 -5
  44. package/assembly/deserialize/swar/array/box.ts +1 -2
  45. package/assembly/deserialize/swar/array/float.ts +399 -30
  46. package/assembly/deserialize/swar/array/generic.ts +13 -4
  47. package/assembly/deserialize/swar/array/integer.ts +29 -78
  48. package/assembly/deserialize/swar/array/map.ts +1 -2
  49. package/assembly/deserialize/swar/array/object.ts +12 -4
  50. package/assembly/deserialize/swar/array/raw.ts +1 -2
  51. package/assembly/deserialize/swar/array/shared.ts +7 -14
  52. package/assembly/deserialize/swar/array/string.ts +37 -13
  53. package/assembly/deserialize/swar/array/struct.ts +109 -21
  54. package/assembly/deserialize/swar/array.ts +1 -3
  55. package/assembly/deserialize/swar/float.ts +23 -21
  56. package/assembly/deserialize/swar/integer.ts +2 -7
  57. package/assembly/deserialize/swar/string.ts +81 -124
  58. package/assembly/deserialize/swar/typedarray.ts +4 -4
  59. package/assembly/index.d.ts +35 -24
  60. package/assembly/index.ts +1775 -281
  61. package/assembly/serialize/index/arbitrary.ts +70 -4
  62. package/assembly/serialize/index/bool.ts +1 -1
  63. package/assembly/serialize/index/float.ts +1 -5
  64. package/assembly/serialize/index/integer.ts +1 -1
  65. package/assembly/serialize/index/jsonarray.ts +51 -0
  66. package/assembly/serialize/index/object.ts +42 -3
  67. package/assembly/serialize/index/string.ts +1 -2
  68. package/assembly/serialize/index/typedarray.ts +1 -2
  69. package/assembly/serialize/index.ts +1 -0
  70. package/assembly/serialize/naive/array.ts +87 -34
  71. package/assembly/serialize/naive/bool.ts +0 -1
  72. package/assembly/serialize/naive/float.ts +15 -29
  73. package/assembly/serialize/naive/integer.ts +1 -5
  74. package/assembly/serialize/naive/map.ts +37 -0
  75. package/assembly/serialize/naive/raw.ts +1 -2
  76. package/assembly/serialize/naive/set.ts +0 -5
  77. package/assembly/serialize/naive/staticarray.ts +0 -6
  78. package/assembly/serialize/naive/string.ts +1 -10
  79. package/assembly/serialize/naive/typedarray.ts +0 -7
  80. package/assembly/serialize/simd/string.ts +1 -3
  81. package/assembly/serialize/swar/string.ts +1 -2
  82. package/assembly/util/atoi-fast.ts +4 -14
  83. package/assembly/util/bytes.ts +1 -2
  84. package/assembly/util/eisel-lemire.ts +179 -0
  85. package/assembly/util/idofd.ts +1 -2
  86. package/assembly/util/isSpace.ts +1 -2
  87. package/assembly/util/itoa-fast.ts +6 -9
  88. package/assembly/util/nextPowerOf2.ts +1 -2
  89. package/assembly/util/parsefloat-fast.ts +3 -5
  90. package/assembly/util/prettyWhitespaceSimd.ts +69 -0
  91. package/assembly/util/ptrToStr.ts +1 -2
  92. package/assembly/util/scanValueEndSimd.ts +83 -22
  93. package/assembly/util/scanValueEndSwar.ts +67 -25
  94. package/assembly/util/scientific.ts +5 -8
  95. package/assembly/util/snp.ts +1 -2
  96. package/assembly/util/swar-int.ts +5 -10
  97. package/assembly/util/swar.ts +2 -4
  98. package/assembly/util/validateJson.ts +338 -0
  99. package/lib/as-bs.ts +51 -51
  100. package/package.json +25 -8
  101. package/transform/lib/index.d.ts +6 -0
  102. package/transform/lib/index.js +874 -171
  103. package/transform/lib/types.d.ts +3 -1
  104. package/transform/lib/types.js +6 -0
  105. package/assembly/deserialize/index/struct.ts +0 -1
  106. package/assembly/deserialize/naive/struct.ts +0 -21
  107. package/assembly/util/dragonbox-cache.ts +0 -445
  108. package/assembly/util/dragonbox.ts +0 -652
@@ -1,85 +1,46 @@
1
1
  // Characters
2
- // @ts-ignore = Decorator is valid here
3
- @inline export const COMMA = 44;
4
- // @ts-ignore = Decorator is valid here
5
- @inline export const QUOTE = 34;
6
- // @ts-ignore = Decorator is valid here
7
- @inline export const BACK_SLASH = 92;
8
- // @ts-ignore: Decorator is valid here
9
- @inline export const FWD_SLASH = 47;
10
- // @ts-ignore: Decorator is valid here
11
- @inline export const BRACE_LEFT = 123;
12
- // @ts-ignore: Decorator is valid here
13
- @inline export const BRACE_RIGHT = 125;
14
- // @ts-ignore: Decorator is valid here
15
- @inline export const BRACKET_LEFT = 91;
16
- // @ts-ignore: Decorator is valid here
17
- @inline export const BRACKET_RIGHT = 93;
18
- // @ts-ignore: Decorator is valid here
19
- @inline export const COLON = 58;
20
- // @ts-ignore: Decorator is valid here
21
- @inline export const CHAR_T = 116;
22
- // @ts-ignore: Decorator is valid here
23
- @inline export const CHAR_R = 114;
24
- // @ts-ignore: Decorator is valid here
25
- @inline export const CHAR_U = 117;
26
- // @ts-ignore: Decorator is valid here
27
- @inline export const CHAR_E = 101;
28
- // @ts-ignore: Decorator is valid here
29
- @inline export const CHAR_F = 102;
30
- // @ts-ignore: Decorator is valid here
31
- @inline export const CHAR_A = 97;
32
- // @ts-ignore: Decorator is valid here
33
- @inline export const CHAR_L = 108;
34
- // @ts-ignore: Decorator is valid here
35
- @inline export const CHAR_S = 115;
36
- // @ts-ignore = Decorator is valid here
37
- @inline export const CHAR_N = 110;
38
- // @ts-ignore = Decorator is valid here
39
- @inline export const CHAR_B = 98;
2
+ export const COMMA = 44;
3
+ export const QUOTE = 34;
4
+ export const BACK_SLASH = 92;
5
+ export const FWD_SLASH = 47;
6
+ export const BRACE_LEFT = 123;
7
+ export const BRACE_RIGHT = 125;
8
+ export const BRACKET_LEFT = 91;
9
+ export const BRACKET_RIGHT = 93;
10
+ export const COLON = 58;
11
+ export const CHAR_T = 116;
12
+ export const CHAR_R = 114;
13
+ export const CHAR_U = 117;
14
+ export const CHAR_E = 101;
15
+ export const CHAR_F = 102;
16
+ export const CHAR_A = 97;
17
+ export const CHAR_L = 108;
18
+ export const CHAR_S = 115;
19
+ export const CHAR_N = 110;
20
+ export const CHAR_B = 98;
40
21
  // Strings
41
- // @ts-ignore: Decorator is valid here
42
- @inline export const TRUE_WORD = "true";
43
- // @ts-ignore: Decorator is valid here
44
- @inline export const FALSE_WORD = "false";
45
- // @ts-ignore: Decorator is valid here
46
- @inline export const NULL_WORD = "null";
47
- // @ts-ignore: Decorator is valid here
48
- @inline export const BRACE_LEFT_WORD = "{";
49
- // @ts-ignore: Decorator is valid here
50
- @inline export const BRACKET_LEFT_WORD = "[";
51
- // @ts-ignore: Decorator is valid here
52
- @inline export const EMPTY_BRACKET_WORD = "[]";
53
- // @ts-ignore: Decorator is valid here
54
- @inline export const COLON_WORD = ":";
55
- // @ts-ignore: Decorator is valid here
56
- @inline export const COMMA_WORD = ",";
57
- // @ts-ignore: Decorator is valid here
58
- @inline export const BRACE_RIGHT_WORD = "}";
59
- // @ts-ignore: Decorator is valid here
60
- @inline export const BRACKET_RIGHT_WORD = "]";
61
- // @ts-ignore: Decorator is valid here
62
- @inline export const QUOTE_WORD = '"';
63
- // @ts-ignore: Decorator is valid here
64
- @inline export const EMPTY_QUOTE_WORD = '""';
22
+ export const TRUE_WORD = "true";
23
+ export const FALSE_WORD = "false";
24
+ export const NULL_WORD = "null";
25
+ export const BRACE_LEFT_WORD = "{";
26
+ export const BRACKET_LEFT_WORD = "[";
27
+ export const EMPTY_BRACKET_WORD = "[]";
28
+ export const COLON_WORD = ":";
29
+ export const COMMA_WORD = ",";
30
+ export const BRACE_RIGHT_WORD = "}";
31
+ export const BRACKET_RIGHT_WORD = "]";
32
+ export const QUOTE_WORD = '"';
33
+ export const EMPTY_QUOTE_WORD = '""';
65
34
 
66
35
  // Escape Codes
67
- // @ts-ignore: Decorator is valid here
68
- @inline export const BACKSPACE = 8; // \b
69
- // @ts-ignore: Decorator is valid here
70
- @inline export const TAB = 9; // \t
71
- // @ts-ignore: Decorator is valid here
72
- @inline export const NEW_LINE = 10; // \n
73
- // @ts-ignore: Decorator is valid here
74
- @inline export const FORM_FEED = 12; // \f
75
- // @ts-ignore: Decorator is valid here
76
- @inline export const CARRIAGE_RETURN = 13; // \r
36
+ export const BACKSPACE = 8; // \b
37
+ export const TAB = 9; // \t
38
+ export const NEW_LINE = 10; // \n
39
+ export const FORM_FEED = 12; // \f
40
+ export const CARRIAGE_RETURN = 13; // \r
77
41
 
78
42
  // Pre-encoded u64 constants for common JSON literals
79
43
  // These represent the UTF-16 encoded bytes stored as u64 for fast comparison/storage
80
- // @ts-ignore: Decorator is valid here
81
- @inline export const NULL_WORD_U64: u64 = 30399761348886638; // "null" as u64 (n=110, u=117, l=108, l=108)
82
- // @ts-ignore: Decorator is valid here
83
- @inline export const TRUE_WORD_U64: u64 = 28429475166421108; // "true" as u64 (t=116, r=114, u=117, e=101)
84
- // @ts-ignore: Decorator is valid here
85
- @inline export const FALSE_WORD_U64: u64 = 32370086184550502; // "fals" as u64 (f=102, a=97, l=108, s=115) - first 4 chars of "false"
44
+ export const NULL_WORD_U64: u64 = 30399761348886638; // "null" as u64 (n=110, u=117, l=108, l=108)
45
+ export const TRUE_WORD_U64: u64 = 28429475166421108; // "true" as u64 (t=116, r=114, u=117, e=101)
46
+ export const FALSE_WORD_U64: u64 = 32370086184550502; // "fals" as u64 (f=102, a=97, l=108, s=115) - first 4 chars of "false"
@@ -0,0 +1,21 @@
1
+ // Malformed-range failures are recorded only on the cold error path and
2
+ // consumed at a public JSON.parse boundary. Keeping the final throw there
3
+ // makes it catchable by try-as without adding a success-path store or a
4
+ // second validation scan.
5
+ let productionParseError = false;
6
+
7
+ export function markProductionParseError(): void {
8
+ productionParseError = true;
9
+ }
10
+
11
+ export function takeProductionParseError(): bool {
12
+ if (!productionParseError) return false;
13
+ productionParseError = false;
14
+ return true;
15
+ }
16
+
17
+ /** Mark a malformed cold path and return the shared zero cursor sentinel. */
18
+ export function failProductionParse(): usize {
19
+ productionParseError = true;
20
+ return 0;
21
+ }
@@ -1,29 +1,68 @@
1
1
  import { JSON } from "../..";
2
- import { deserializeArray } from "./array";
3
- import { deserializeBoolean } from "./bool";
2
+ import { deserializeBooleanCode } from "./bool";
4
3
  import { deserializeFloat } from "./float";
5
- import { deserializeObject } from "./object";
4
+ import { deserializeObject, deserializeJsonArray, getParseSrc } from "./object";
6
5
  import { deserializeString } from "./string";
7
6
  import { BRACE_LEFT, BRACKET_LEFT, CHAR_N, QUOTE } from "../../custom/chars";
8
7
 
8
+ const NULL_WORD: u64 = 30399761348886638;
9
+
9
10
  export function deserializeArbitrary(
10
11
  srcStart: usize,
11
12
  srcEnd: usize,
12
13
  dst: usize,
13
14
  ): JSON.Value {
15
+ const v = parseArbitraryValue(srcStart, srcEnd);
16
+ if (changetype<usize>(v) == 0) return v;
17
+ // Reuse path (`JSON.parse<JSON.Value>(data, out)`): write the parsed bits into
18
+ // the caller's handle (with the GC barrier for any managed payload).
19
+ return dst != 0 ? JSON.Value.__adoptInto(dst, v) : v;
20
+ }
21
+
22
+ function parseArbitraryValue(srcStart: usize, srcEnd: usize): JSON.Value {
23
+ if (srcStart >= srcEnd) return changetype<JSON.Value>(0);
14
24
  const firstChar = load<u16>(srcStart);
15
- if (firstChar == QUOTE) {
16
- return JSON.Value.from(deserializeString(srcStart, srcEnd));
17
- } else if (firstChar == BRACE_LEFT) {
18
- return JSON.Value.from(deserializeObject(srcStart, srcEnd, 0));
25
+ if (
26
+ firstChar == QUOTE ||
27
+ firstChar == BRACE_LEFT ||
28
+ firstChar == BRACKET_LEFT
29
+ ) {
30
+ // Lazy by default: when a parse is in flight (source anchor present), defer
31
+ // strings and composites (the allocating shapes) - store the exact raw slice
32
+ // and materialize on first access. Cheap primitives stay eager below.
33
+ const src = getParseSrc();
34
+ if (src.length != 0) {
35
+ const end = JSON.Util.scanValueEnd<JSON.Value>(srcStart, srcEnd);
36
+ // A zero end is the scanner's failure sentinel. Never retain it in a
37
+ // lazy slice: subtracting the source base from zero would underflow and
38
+ // later materialization could read outside the source value.
39
+ if (end == 0) return changetype<JSON.Value>(0);
40
+ return JSON.Value.fromSlice(srcStart, end, src);
41
+ }
42
+ if (firstChar == QUOTE) {
43
+ const value = deserializeString(srcStart, srcEnd);
44
+ return changetype<usize>(value) != 0
45
+ ? JSON.Value.from(value)
46
+ : changetype<JSON.Value>(0);
47
+ }
48
+ const composite =
49
+ firstChar == BRACE_LEFT
50
+ ? changetype<usize>(deserializeObject(srcStart, srcEnd, 0))
51
+ : changetype<usize>(deserializeJsonArray(srcStart, srcEnd, 0));
52
+ return composite != 0
53
+ ? firstChar == BRACE_LEFT
54
+ ? JSON.Value.from(changetype<JSON.Obj>(composite))
55
+ : JSON.Value.from(changetype<JSON.Arr>(composite))
56
+ : changetype<JSON.Value>(0);
19
57
  } else if (firstChar - 48 <= 9 || firstChar == 45) {
20
58
  return JSON.Value.from(deserializeFloat<f64>(srcStart, srcEnd));
21
- } else if (firstChar == BRACKET_LEFT) {
22
- return JSON.Value.from(deserializeArray<JSON.Value[]>(srcStart, srcEnd, 0));
23
59
  } else if (firstChar == 116 || firstChar == 102) {
24
- return JSON.Value.from(deserializeBoolean(srcStart, srcEnd));
60
+ const code = deserializeBooleanCode(srcStart, srcEnd);
61
+ return code != 0 ? JSON.Value.from(code == 2) : changetype<JSON.Value>(0);
25
62
  } else if (firstChar == CHAR_N) {
63
+ if (srcEnd - srcStart < 8 || load<u64>(srcStart) != NULL_WORD)
64
+ return changetype<JSON.Value>(0);
26
65
  return JSON.Value.from<usize>(0);
27
66
  }
28
- return unreachable();
67
+ return changetype<JSON.Value>(0);
29
68
  }
@@ -11,6 +11,7 @@ import { deserializeObjectArray } from "../naive/array/object";
11
11
  import { deserializeRawArray } from "../naive/array/raw";
12
12
  import { deserializeStringArray_NAIVE } from "../naive/array/string";
13
13
  import { deserializeStructArray } from "../naive/array/struct";
14
+ import { deserializeStructArray_SWAR } from "../swar/array/struct";
14
15
  import { deserializeIntegerArray_SIMD } from "../simd/array/integer";
15
16
  import { deserializeIntegerArray_SWAR } from "../swar/array/integer";
16
17
  import { deserializeFloatArray_SWAR } from "../swar/array/float";
@@ -82,7 +83,7 @@ export function deserializeArray<T extends unknown[]>(
82
83
  isDefined(type.__DESERIALIZE_SLOW) ||
83
84
  isDefined(type.__DESERIALIZE_FAST)
84
85
  ) {
85
- return deserializeStructArray<T>(srcStart, srcEnd, dst);
86
+ return deserializeStructArray_SWAR<T>(srcStart, srcEnd, dst);
86
87
  }
87
88
  throw new Error("Could not parse array of type " + nameof<T>() + "!");
88
89
  } else {
@@ -1 +1 @@
1
- export { deserializeBoolean } from "../naive/bool";
1
+ export { deserializeBoolean, deserializeBooleanCode } from "../naive/bool";
@@ -12,8 +12,7 @@ import {
12
12
  deserializeFloatField_SIMD,
13
13
  } from "../simd/float";
14
14
 
15
- // @ts-ignore: inline
16
- @inline export function deserializeFloat<T>(srcStart: usize, srcEnd: usize): T {
15
+ export function deserializeFloat<T>(srcStart: usize, srcEnd: usize): T {
17
16
  if (JSON_MODE == JSONMode.SIMD) {
18
17
  return deserializeFloat_SIMD<T>(srcStart, srcEnd);
19
18
  } else if (JSON_MODE == JSONMode.NAIVE) {
@@ -23,8 +22,7 @@ import {
23
22
  }
24
23
  }
25
24
 
26
- // @ts-ignore: inline
27
- @inline export function deserializeFloatField<T extends number>(
25
+ export function deserializeFloatField<T extends number>(
28
26
  srcStart: usize,
29
27
  srcEnd: usize,
30
28
  dstObj: usize,
@@ -21,8 +21,7 @@ import {
21
21
  * @param srcEnd Pointer just past the last code unit.
22
22
  * @returns The parsed value, truncated to `T`.
23
23
  */
24
- // @ts-expect-error: @inline is a valid decorator
25
- @inline export function deserializeInteger<T extends number>(
24
+ export function deserializeInteger<T extends number>(
26
25
  srcStart: usize,
27
26
  srcEnd: usize,
28
27
  ): T {
@@ -46,8 +45,7 @@ import {
46
45
  * @param dstOffset Byte offset of the field within `dstObj`.
47
46
  * @returns The source position immediately after the last digit consumed.
48
47
  */
49
- // @ts-expect-error: @inline is a valid decorator
50
- @inline export function deserializeIntegerField<T extends number>(
48
+ export function deserializeIntegerField<T extends number>(
51
49
  srcStart: usize,
52
50
  srcEnd: usize,
53
51
  dstObj: usize,
@@ -1 +1,9 @@
1
- export { deserializeObject } from "../naive/object";
1
+ export {
2
+ deserializeObject,
3
+ deserializeJsonArray,
4
+ setParseSrc,
5
+ getParseSrc,
6
+ markProductionParseError,
7
+ takeProductionParseError,
8
+ } from "../naive/object";
9
+ export { failProductionParse } from "../error";
@@ -2,21 +2,24 @@ import { JSONMode } from "../..";
2
2
  import {
3
3
  deserializeString_NAIVE,
4
4
  deserializeStringField_NAIVE,
5
+ deserializeStringFieldTrusted_NAIVE,
5
6
  } from "../naive/string";
6
7
  import {
7
8
  deserializeString_SIMD,
8
9
  deserializeStringField_SIMD,
10
+ deserializeStringFieldTrusted_SIMD,
9
11
  } from "../simd/string";
10
12
  import {
11
13
  deserializeString_SWAR,
12
14
  deserializeStringField_SWAR,
15
+ deserializeStringFieldTrusted_SWAR,
13
16
  } from "../swar/string";
14
17
 
15
-
16
- @inline export function deserializeString(
17
- srcStart: usize,
18
- srcEnd: usize,
19
- ): string {
18
+ export function deserializeString(srcStart: usize, srcEnd: usize): string {
19
+ // Whole-value decoders strip two UTF-16 code units before entering their
20
+ // optimized loops. Guard the actual memory-safety invariant here; complete
21
+ // RFC quote framing remains the strict-mode validator's job.
22
+ if (srcEnd - srcStart < 4) return changetype<string>(0);
20
23
  if (JSON_MODE == JSONMode.SIMD) {
21
24
  return deserializeString_SIMD(srcStart, srcEnd);
22
25
  } else if (JSON_MODE == JSONMode.NAIVE) {
@@ -26,8 +29,7 @@ import {
26
29
  }
27
30
  }
28
31
 
29
-
30
- @inline export function deserializeStringField<T extends string | null>(
32
+ export function deserializeStringField<T extends string | null>(
31
33
  srcStart: usize,
32
34
  srcEnd: usize,
33
35
  dstObj: usize,
@@ -41,3 +43,33 @@ import {
41
43
  return deserializeStringField_SWAR<T>(srcStart, srcEnd, dstObj, dstOffset);
42
44
  }
43
45
  }
46
+
47
+ export function deserializeStringFieldTrusted(
48
+ payloadStart: usize,
49
+ srcEnd: usize,
50
+ dstObj: usize,
51
+ dstOffset: usize = 0,
52
+ ): usize {
53
+ if (JSON_MODE == JSONMode.SIMD) {
54
+ return deserializeStringFieldTrusted_SIMD(
55
+ payloadStart,
56
+ srcEnd,
57
+ dstObj,
58
+ dstOffset,
59
+ );
60
+ } else if (JSON_MODE == JSONMode.NAIVE) {
61
+ return deserializeStringFieldTrusted_NAIVE(
62
+ payloadStart,
63
+ srcEnd,
64
+ dstObj,
65
+ dstOffset,
66
+ );
67
+ } else {
68
+ return deserializeStringFieldTrusted_SWAR(
69
+ payloadStart,
70
+ srcEnd,
71
+ dstObj,
72
+ dstOffset,
73
+ );
74
+ }
75
+ }
@@ -21,8 +21,7 @@ import {
21
21
  * @param srcEnd Pointer just past the last code unit.
22
22
  * @returns The parsed value, truncated to `T`.
23
23
  */
24
- // @ts-expect-error: @inline is a valid decorator
25
- @inline export function deserializeUnsigned<T extends number>(
24
+ export function deserializeUnsigned<T extends number>(
26
25
  srcStart: usize,
27
26
  srcEnd: usize,
28
27
  ): T {
@@ -46,8 +45,7 @@ import {
46
45
  * @param dstOffset Byte offset of the field within `dstObj`.
47
46
  * @returns The source position immediately after the last digit consumed.
48
47
  */
49
- // @ts-expect-error: @inline is a valid decorator
50
- @inline export function deserializeUnsignedField<T extends number>(
48
+ export function deserializeUnsignedField<T extends number>(
51
49
  srcStart: usize,
52
50
  srcEnd: usize,
53
51
  dstObj: usize,
@@ -10,6 +10,5 @@ export * from "./index/raw";
10
10
  export * from "./index/set";
11
11
  export * from "./index/staticarray";
12
12
  export * from "./index/string";
13
- export * from "./index/struct";
14
13
  export * from "./index/typedarray";
15
14
  export * from "./index/unsigned";
@@ -10,6 +10,7 @@ export function deserializeArbitraryArray(
10
10
  dst || changetype<usize>(instantiate<JSON.Value[]>()),
11
11
  );
12
12
  // Skip the opening '[' and parse elements single-pass until the matching ']'.
13
- parseArrayBody(out, srcStart + 2, srcEnd);
14
- return out;
13
+ return parseArrayBody(out, srcStart + 2, srcEnd) != 0
14
+ ? out
15
+ : changetype<JSON.Value[]>(0);
15
16
  }
@@ -28,6 +28,7 @@ export function deserializeArrayArray<T extends unknown[][]>(
28
28
  if (load<u16>(srcStart) == BRACKET_LEFT) {
29
29
  const inner = instantiate<JSON.Value[]>();
30
30
  srcStart = parseArrayBody(inner, srcStart + 2, srcEnd);
31
+ if (srcStart == 0) return changetype<T>(0);
31
32
  // @ts-ignore: valueof<T> is JSON.Value[] in this branch
32
33
  out.push(changetype<valueof<T>>(changetype<usize>(inner)));
33
34
  } else {
@@ -6,13 +6,15 @@ import {
6
6
  FALSE_WORD_U64,
7
7
  TRUE_WORD_U64,
8
8
  } from "../../../custom/chars";
9
+ import { markProductionParseError } from "../../error";
9
10
 
10
11
  /**
11
12
  * Strict boolean-array deserializer (`bool[]`, every JSON_MODE).
12
13
  *
13
14
  * Enforces RFC 8259 array structure: `[`-framed, single-comma separated, no
14
15
  * leading / trailing / doubled commas, and each element must be exactly the
15
- * literal `true` or `false`. Throws on any deviation.
16
+ * literal `true` or `false`. Returns the shared failure sentinel on any
17
+ * deviation.
16
18
  *
17
19
  * The token check is SWAR-shaped: one `u64` load matches all four chars of
18
20
  * `true`; `false` adds one `u16` load to confirm the trailing `e`.
@@ -27,12 +29,15 @@ export function deserializeBooleanArray<T extends boolean[]>(
27
29
  );
28
30
  out.length = 0; // dst may arrive pre-sized; re-parse from empty via push
29
31
 
30
- while (srcStart < srcEnd && isSpace(load<u16>(srcStart))) srcStart += 2;
31
32
  while (srcEnd > srcStart && isSpace(load<u16>(srcEnd - 2))) srcEnd -= 2;
32
- if (srcStart >= srcEnd || load<u16>(srcStart) != BRACKET_LEFT)
33
- throw new Error("Invalid JSON array: expected '['");
34
- if (load<u16>(srcEnd - 2) != BRACKET_RIGHT)
35
- throw new Error("Invalid JSON array: expected ']'");
33
+ if (
34
+ srcStart >= srcEnd ||
35
+ load<u16>(srcStart) != BRACKET_LEFT ||
36
+ load<u16>(srcEnd - 2) != BRACKET_RIGHT
37
+ ) {
38
+ markProductionParseError();
39
+ return changetype<T>(0);
40
+ }
36
41
  srcStart += 2; // past '['
37
42
  srcEnd -= 2; // before ']'
38
43
 
@@ -51,17 +56,22 @@ export function deserializeBooleanArray<T extends boolean[]>(
51
56
  out.push(false);
52
57
  srcStart += 10;
53
58
  } else {
54
- throw new Error("Invalid JSON array: expected 'true' or 'false'");
59
+ markProductionParseError();
60
+ return changetype<T>(0);
55
61
  }
56
62
 
57
63
  while (srcStart < srcEnd && isSpace(load<u16>(srcStart))) srcStart += 2;
58
64
  if (srcStart >= srcEnd) break;
59
- if (load<u16>(srcStart) != COMMA)
60
- throw new Error("Invalid JSON array: expected ',' or ']'");
65
+ if (load<u16>(srcStart) != COMMA) {
66
+ markProductionParseError();
67
+ return changetype<T>(0);
68
+ }
61
69
  srcStart += 2;
62
70
  while (srcStart < srcEnd && isSpace(load<u16>(srcStart))) srcStart += 2;
63
- if (srcStart >= srcEnd)
64
- throw new Error("Invalid JSON array: trailing comma");
71
+ if (srcStart >= srcEnd) {
72
+ markProductionParseError();
73
+ return changetype<T>(0);
74
+ }
65
75
  }
66
76
 
67
77
  return out;
@@ -10,42 +10,22 @@ export function deserializeBoxArray<T extends JSON.Box<any>[]>(
10
10
  const out = changetype<nonnull<T>>(
11
11
  dst || changetype<usize>(instantiate<T>()),
12
12
  );
13
- if (isBoolean<valueof<T>>()) {
14
- srcStart += 2; // skip [
15
- while (srcStart < srcEnd) {
16
- const block = load<u64>(srcStart);
17
- if (block == 28429475166421108) {
18
- out.push(JSON.Box.from(true));
19
- srcStart += 10;
20
- } else if (block == 32370086184550502 && load<u16>(srcStart, 8) == 101) {
21
- out.push(JSON.Box.from(false));
22
- srcStart += 12;
23
- } else {
24
- srcStart += 2;
25
- }
26
- }
27
- return out;
28
- } else {
29
- let lastIndex: usize = 0;
30
- while (srcStart < srcEnd) {
31
- const code = load<u16>(srcStart);
32
- if (code - 48 <= 9 || code == 45) {
33
- lastIndex = srcStart;
34
- srcStart += 2;
35
- while (srcStart < srcEnd) {
36
- const code = load<u16>(srcStart);
37
- if (code == COMMA || code == BRACKET_RIGHT || isSpace(code)) {
38
- out.push(JSON.__deserialize<valueof<T>>(lastIndex, srcStart));
39
- // while (isSpace(load<u16>((srcStart += 2)))) {
40
- // /* empty */
41
- // }
42
- break;
43
- }
44
- srcStart += 2;
13
+ let lastIndex: usize = 0;
14
+ while (srcStart < srcEnd) {
15
+ const code = load<u16>(srcStart);
16
+ if (code - 48 <= 9 || code == 45) {
17
+ lastIndex = srcStart;
18
+ srcStart += 2;
19
+ while (srcStart < srcEnd) {
20
+ const code = load<u16>(srcStart);
21
+ if (code == COMMA || code == BRACKET_RIGHT || isSpace(code)) {
22
+ out.push(JSON.__deserialize<valueof<T>>(lastIndex, srcStart));
23
+ break;
45
24
  }
25
+ srcStart += 2;
46
26
  }
47
- srcStart += 2;
48
27
  }
28
+ srcStart += 2;
49
29
  }
50
30
  return out;
51
31
  }
@@ -1,6 +1,7 @@
1
1
  import { isSpace } from "../../../util";
2
2
  import { COMMA, BRACKET_LEFT, BRACKET_RIGHT } from "../../../custom/chars";
3
3
  import { JSON } from "../../..";
4
+ import { markProductionParseError } from "../../error";
4
5
 
5
6
  /**
6
7
  * Strict float-array deserializer (`f64[]` / `f32[]`).
@@ -8,8 +9,8 @@ import { JSON } from "../../..";
8
9
  * Enforces RFC 8259 array structure: `[`-framed, single-comma separated, no
9
10
  * leading / trailing / doubled commas, and no garbage between values. Each
10
11
  * element token is validated by `deserializeFloat_NAIVE` (via `JSON.__deserialize`),
11
- * so malformed numbers like `0e` / `-01` / `1.` are rejected here too. Throws on
12
- * any deviation.
12
+ * so malformed numbers like `0e` / `-01` / `1.` are rejected here too. Returns
13
+ * the shared failure sentinel on any deviation.
13
14
  */
14
15
  export function deserializeFloatArray_NAIVE<T extends number[]>(
15
16
  srcStart: usize,
@@ -24,12 +25,15 @@ export function deserializeFloatArray_NAIVE<T extends number[]>(
24
25
  out.length = 0;
25
26
 
26
27
  // Trim surrounding whitespace and require the enclosing brackets.
27
- while (srcStart < srcEnd && isSpace(load<u16>(srcStart))) srcStart += 2;
28
28
  while (srcEnd > srcStart && isSpace(load<u16>(srcEnd - 2))) srcEnd -= 2;
29
- if (srcStart >= srcEnd || load<u16>(srcStart) != BRACKET_LEFT)
30
- throw new Error("Invalid JSON array: expected '['");
31
- if (load<u16>(srcEnd - 2) != BRACKET_RIGHT)
32
- throw new Error("Invalid JSON array: expected ']'");
29
+ if (
30
+ srcStart >= srcEnd ||
31
+ load<u16>(srcStart) != BRACKET_LEFT ||
32
+ load<u16>(srcEnd - 2) != BRACKET_RIGHT
33
+ ) {
34
+ markProductionParseError();
35
+ return changetype<T>(0);
36
+ }
33
37
  srcStart += 2; // past '['
34
38
  srcEnd -= 2; // before ']'
35
39
 
@@ -45,18 +49,24 @@ export function deserializeFloatArray_NAIVE<T extends number[]>(
45
49
  if (c == COMMA || isSpace(c)) break;
46
50
  srcStart += 2;
47
51
  }
48
- if (srcStart == tokenStart)
49
- throw new Error("Invalid JSON array: missing value");
52
+ if (srcStart == tokenStart) {
53
+ markProductionParseError();
54
+ return changetype<T>(0);
55
+ }
50
56
  out.push(JSON.__deserialize<valueof<T>>(tokenStart, srcStart));
51
57
 
52
58
  while (srcStart < srcEnd && isSpace(load<u16>(srcStart))) srcStart += 2;
53
59
  if (srcStart >= srcEnd) break; // end of array body
54
- if (load<u16>(srcStart) != COMMA)
55
- throw new Error("Invalid JSON array: expected ',' or ']'");
60
+ if (load<u16>(srcStart) != COMMA) {
61
+ markProductionParseError();
62
+ return changetype<T>(0);
63
+ }
56
64
  srcStart += 2; // past ','
57
65
  while (srcStart < srcEnd && isSpace(load<u16>(srcStart))) srcStart += 2;
58
- if (srcStart >= srcEnd)
59
- throw new Error("Invalid JSON array: trailing comma");
66
+ if (srcStart >= srcEnd) {
67
+ markProductionParseError();
68
+ return changetype<T>(0);
69
+ }
60
70
  }
61
71
 
62
72
  return out;