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.
- package/CHANGELOG.md +54 -29
- package/README.md +126 -33
- package/assembly/custom/chars.ts +39 -78
- package/assembly/deserialize/error.ts +21 -0
- package/assembly/deserialize/index/arbitrary.ts +50 -11
- package/assembly/deserialize/index/array.ts +2 -1
- package/assembly/deserialize/index/bool.ts +1 -1
- package/assembly/deserialize/index/float.ts +2 -4
- package/assembly/deserialize/index/integer.ts +2 -4
- package/assembly/deserialize/index/object.ts +9 -1
- package/assembly/deserialize/index/string.ts +39 -7
- package/assembly/deserialize/index/unsigned.ts +2 -4
- 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 +34 -22
- package/assembly/deserialize/naive/array/map.ts +1 -1
- package/assembly/deserialize/naive/array/object.ts +2 -1
- package/assembly/deserialize/naive/array/string.ts +29 -16
- package/assembly/deserialize/naive/array/struct.ts +19 -1
- package/assembly/deserialize/naive/bool.ts +18 -10
- package/assembly/deserialize/naive/date.ts +1 -2
- package/assembly/deserialize/naive/float.ts +3 -9
- package/assembly/deserialize/naive/integer.ts +1 -2
- package/assembly/deserialize/naive/map.ts +342 -43
- package/assembly/deserialize/naive/object.ts +250 -55
- package/assembly/deserialize/naive/raw.ts +10 -2
- package/assembly/deserialize/naive/set.ts +2 -5
- package/assembly/deserialize/naive/staticarray.ts +4 -4
- package/assembly/deserialize/naive/string.ts +46 -60
- package/assembly/deserialize/naive/unsigned.ts +1 -2
- package/assembly/deserialize/parseMode.ts +216 -0
- package/assembly/deserialize/simd/array/integer.ts +8 -10
- package/assembly/deserialize/simd/float.ts +38 -34
- package/assembly/deserialize/simd/integer.ts +2 -7
- package/assembly/deserialize/simd/string.ts +84 -39
- package/assembly/deserialize/string-validation.ts +34 -0
- package/assembly/deserialize/swar/array/arbitrary.ts +1 -2
- package/assembly/deserialize/swar/array/array.ts +64 -15
- package/assembly/deserialize/swar/array/bool.ts +15 -5
- package/assembly/deserialize/swar/array/box.ts +1 -2
- package/assembly/deserialize/swar/array/float.ts +399 -30
- package/assembly/deserialize/swar/array/generic.ts +13 -4
- package/assembly/deserialize/swar/array/integer.ts +29 -78
- package/assembly/deserialize/swar/array/map.ts +1 -2
- package/assembly/deserialize/swar/array/object.ts +12 -4
- package/assembly/deserialize/swar/array/raw.ts +1 -2
- package/assembly/deserialize/swar/array/shared.ts +7 -14
- package/assembly/deserialize/swar/array/string.ts +37 -13
- package/assembly/deserialize/swar/array/struct.ts +109 -21
- package/assembly/deserialize/swar/array.ts +1 -3
- package/assembly/deserialize/swar/float.ts +23 -21
- package/assembly/deserialize/swar/integer.ts +2 -7
- package/assembly/deserialize/swar/string.ts +81 -124
- package/assembly/deserialize/swar/typedarray.ts +4 -4
- package/assembly/index.d.ts +35 -24
- package/assembly/index.ts +1775 -281
- package/assembly/serialize/index/arbitrary.ts +70 -4
- 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/jsonarray.ts +51 -0
- package/assembly/serialize/index/object.ts +42 -3
- package/assembly/serialize/index/string.ts +1 -2
- package/assembly/serialize/index/typedarray.ts +1 -2
- package/assembly/serialize/index.ts +1 -0
- package/assembly/serialize/naive/array.ts +87 -34
- package/assembly/serialize/naive/bool.ts +0 -1
- package/assembly/serialize/naive/float.ts +15 -29
- package/assembly/serialize/naive/integer.ts +1 -5
- package/assembly/serialize/naive/map.ts +37 -0
- package/assembly/serialize/naive/raw.ts +1 -2
- package/assembly/serialize/naive/set.ts +0 -5
- package/assembly/serialize/naive/staticarray.ts +0 -6
- package/assembly/serialize/naive/string.ts +1 -10
- package/assembly/serialize/naive/typedarray.ts +0 -7
- package/assembly/serialize/simd/string.ts +1 -3
- package/assembly/serialize/swar/string.ts +1 -2
- package/assembly/util/atoi-fast.ts +4 -14
- package/assembly/util/bytes.ts +1 -2
- package/assembly/util/eisel-lemire.ts +179 -0
- package/assembly/util/idofd.ts +1 -2
- package/assembly/util/isSpace.ts +1 -2
- package/assembly/util/itoa-fast.ts +6 -9
- package/assembly/util/nextPowerOf2.ts +1 -2
- package/assembly/util/parsefloat-fast.ts +3 -5
- package/assembly/util/prettyWhitespaceSimd.ts +69 -0
- package/assembly/util/ptrToStr.ts +1 -2
- package/assembly/util/scanValueEndSimd.ts +83 -22
- package/assembly/util/scanValueEndSwar.ts +67 -25
- package/assembly/util/scientific.ts +5 -8
- package/assembly/util/snp.ts +1 -2
- package/assembly/util/swar-int.ts +5 -10
- package/assembly/util/swar.ts +2 -4
- package/assembly/util/validateJson.ts +338 -0
- package/lib/as-bs.ts +51 -51
- package/package.json +25 -8
- package/transform/lib/index.d.ts +6 -0
- package/transform/lib/index.js +874 -171
- package/transform/lib/types.d.ts +3 -1
- package/transform/lib/types.js +6 -0
- package/assembly/deserialize/index/struct.ts +0 -1
- package/assembly/deserialize/naive/struct.ts +0 -21
- package/assembly/util/dragonbox-cache.ts +0 -445
- package/assembly/util/dragonbox.ts +0 -652
package/assembly/custom/chars.ts
CHANGED
|
@@ -1,85 +1,46 @@
|
|
|
1
1
|
// Characters
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
81
|
-
|
|
82
|
-
//
|
|
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 {
|
|
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 (
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
)
|
|
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
|
-
|
|
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
|
-
|
|
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,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
|
-
|
|
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`.
|
|
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 (
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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.
|
|
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 (
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
66
|
+
if (srcStart >= srcEnd) {
|
|
67
|
+
markProductionParseError();
|
|
68
|
+
return changetype<T>(0);
|
|
69
|
+
}
|
|
60
70
|
}
|
|
61
71
|
|
|
62
72
|
return out;
|