json-as 1.3.6 → 1.3.8
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 +45 -0
- package/README.md +1 -1
- package/assembly/deserialize/helpers/uint.ts +4 -1
- package/assembly/deserialize/index/arbitrary.ts +7 -3
- package/assembly/deserialize/index/array.ts +42 -17
- package/assembly/deserialize/index/bool.ts +1 -1
- package/assembly/deserialize/index/date.ts +1 -1
- package/assembly/deserialize/index/float.ts +40 -1
- package/assembly/deserialize/index/integer.ts +68 -1
- package/assembly/deserialize/index/map.ts +1 -1
- package/assembly/deserialize/index/object.ts +1 -1
- package/assembly/deserialize/index/raw.ts +1 -1
- package/assembly/deserialize/index/set.ts +1 -1
- package/assembly/deserialize/index/staticarray.ts +4 -1
- package/assembly/deserialize/index/string.ts +32 -4
- package/assembly/deserialize/index/struct.ts +1 -1
- package/assembly/deserialize/index/typedarray.ts +30 -10
- package/assembly/deserialize/index/unsigned.ts +78 -1
- package/assembly/deserialize/index.ts +1 -0
- package/assembly/deserialize/{simple → naive}/array/arbitrary.ts +24 -5
- package/assembly/deserialize/{simple → naive}/array/array.ts +8 -2
- package/assembly/deserialize/naive/array/bool.ts +68 -0
- package/assembly/deserialize/{simple → naive}/array/box.ts +8 -2
- package/assembly/deserialize/naive/array/float.ts +63 -0
- package/assembly/deserialize/{simple → naive}/array/generic.ts +14 -7
- package/assembly/deserialize/naive/array/integer.ts +86 -0
- package/assembly/deserialize/naive/array/map.ts +47 -0
- package/assembly/deserialize/naive/array/object.ts +47 -0
- package/assembly/deserialize/{simple → naive}/array/raw.ts +34 -7
- package/assembly/deserialize/naive/array/string.ts +69 -0
- package/assembly/deserialize/naive/array/struct.ts +47 -0
- package/assembly/deserialize/{simple → naive}/array.ts +15 -10
- package/assembly/deserialize/{simple → naive}/bool.ts +6 -2
- package/assembly/deserialize/naive/float.ts +135 -0
- package/assembly/deserialize/{simple → naive}/integer.ts +10 -2
- package/assembly/deserialize/{simple → naive}/map.ts +106 -27
- package/assembly/deserialize/{simple → naive}/object.ts +65 -19
- package/assembly/deserialize/{simple → naive}/raw.ts +4 -1
- package/assembly/deserialize/{simple → naive}/set.ts +49 -19
- package/assembly/deserialize/{simple → naive}/staticarray/array.ts +1 -1
- package/assembly/deserialize/{simple → naive}/staticarray/bool.ts +1 -1
- package/assembly/deserialize/{simple → naive}/staticarray/float.ts +1 -1
- package/assembly/deserialize/{simple → naive}/staticarray/integer.ts +1 -1
- package/assembly/deserialize/{simple → naive}/staticarray/string.ts +11 -3
- package/assembly/deserialize/{simple → naive}/staticarray/struct.ts +1 -2
- package/assembly/deserialize/{simple → naive}/staticarray.ts +68 -18
- package/assembly/deserialize/naive/string.ts +199 -0
- package/assembly/deserialize/{simple → naive}/struct.ts +5 -1
- package/assembly/deserialize/{simple → naive}/typedarray.ts +17 -4
- package/assembly/deserialize/{simple → naive}/unsigned.ts +10 -15
- package/assembly/deserialize/simd/array/integer.ts +339 -62
- package/assembly/deserialize/simd/float.ts +303 -0
- package/assembly/deserialize/simd/integer.ts +233 -0
- package/assembly/deserialize/simd/string.ts +266 -107
- package/assembly/deserialize/swar/array/arbitrary.ts +11 -3
- package/assembly/deserialize/swar/array/array.ts +40 -9
- package/assembly/deserialize/swar/array/bool.ts +28 -5
- package/assembly/deserialize/swar/array/box.ts +11 -3
- package/assembly/deserialize/swar/array/float.ts +295 -7
- package/assembly/deserialize/swar/array/generic.ts +28 -7
- package/assembly/deserialize/swar/array/integer.ts +363 -112
- package/assembly/deserialize/swar/array/map.ts +11 -3
- package/assembly/deserialize/swar/array/object.ts +37 -25
- package/assembly/deserialize/swar/array/raw.ts +11 -3
- package/assembly/deserialize/swar/array/shared.ts +63 -14
- package/assembly/deserialize/swar/array/string.ts +140 -7
- package/assembly/deserialize/swar/array/struct.ts +66 -12
- package/assembly/deserialize/swar/array.ts +12 -51
- package/assembly/deserialize/swar/float.ts +304 -0
- package/assembly/deserialize/swar/integer.ts +246 -0
- package/assembly/deserialize/swar/string.ts +213 -294
- package/assembly/deserialize/swar/typedarray.ts +224 -0
- package/assembly/index.d.ts +3 -1
- package/assembly/index.ts +402 -261
- package/assembly/serialize/index/array.ts +1 -1
- package/assembly/serialize/index/bool.ts +1 -1
- package/assembly/serialize/index/date.ts +1 -1
- package/assembly/serialize/index/float.ts +5 -1
- package/assembly/serialize/index/integer.ts +1 -1
- package/assembly/serialize/index/map.ts +1 -1
- package/assembly/serialize/index/raw.ts +1 -1
- package/assembly/serialize/index/set.ts +1 -1
- package/assembly/serialize/index/staticarray.ts +1 -1
- package/assembly/serialize/index/string.ts +1 -1
- package/assembly/serialize/index/struct.ts +1 -1
- package/assembly/serialize/index/typedarray.ts +21 -12
- package/assembly/serialize/index.ts +1 -0
- package/assembly/serialize/naive/array.ts +351 -0
- package/assembly/serialize/{simple → naive}/float.ts +4 -1
- package/assembly/serialize/naive/integer.ts +19 -0
- package/assembly/serialize/{simple → naive}/map.ts +6 -2
- package/assembly/serialize/{simple → naive}/raw.ts +5 -1
- package/assembly/serialize/{simple → naive}/set.ts +6 -1
- package/assembly/serialize/{simple → naive}/staticarray.ts +6 -1
- package/assembly/serialize/{simple → naive}/string.ts +1 -2
- package/assembly/serialize/{simple → naive}/typedarray.ts +10 -3
- package/assembly/serialize/simd/string.ts +6 -2
- package/assembly/serialize/swar/string.ts +15 -141
- package/assembly/util/atoi-fast.ts +81 -0
- package/assembly/util/concat.ts +5 -1
- package/assembly/util/dragonbox-cache.ts +443 -2
- package/assembly/util/dragonbox.ts +53 -17
- package/assembly/util/itoa-fast.ts +241 -0
- package/assembly/util/masks.ts +18 -1
- package/assembly/util/parsefloat-fast.ts +167 -0
- package/assembly/util/scanValueEnd.ts +78 -0
- package/assembly/util/scientific.ts +132 -0
- package/assembly/util/simd-int.ts +191 -0
- package/assembly/util/snp.ts +4 -1
- package/assembly/util/swar-int.ts +248 -0
- package/assembly/util/swar.ts +13 -3
- package/lib/as-bs.ts +27 -6
- package/package.json +15 -11
- package/transform/lib/builder.d.ts.map +1 -1
- package/transform/lib/builder.js +13 -5
- package/transform/lib/builder.js.map +1 -1
- package/transform/lib/index.d.ts +5 -0
- package/transform/lib/index.d.ts.map +1 -1
- package/transform/lib/index.js +1046 -340
- package/transform/lib/index.js.map +1 -1
- package/transform/lib/linkers/alias.d.ts.map +1 -1
- package/transform/lib/linkers/alias.js.map +1 -1
- package/transform/lib/linkers/custom.d.ts.map +1 -1
- package/transform/lib/linkers/custom.js +3 -2
- package/transform/lib/linkers/custom.js.map +1 -1
- package/transform/lib/linkers/imports.d.ts.map +1 -1
- package/transform/lib/linkers/imports.js.map +1 -1
- package/transform/lib/types.d.ts.map +1 -1
- package/transform/lib/types.js +54 -16
- package/transform/lib/types.js.map +1 -1
- package/transform/lib/util.d.ts.map +1 -1
- package/transform/lib/util.js +1 -1
- package/transform/lib/util.js.map +1 -1
- package/transform/lib/visitor.d.ts.map +1 -1
- package/transform/lib/visitor.js +2 -1
- package/transform/lib/visitor.js.map +1 -1
- package/assembly/custom/util.ts +0 -310
- package/assembly/deserialize/simple/arbitrary.ts +0 -23
- package/assembly/deserialize/simple/array/bool.ts +0 -17
- package/assembly/deserialize/simple/array/float.ts +0 -28
- package/assembly/deserialize/simple/array/integer.ts +0 -27
- package/assembly/deserialize/simple/array/map.ts +0 -28
- package/assembly/deserialize/simple/array/object.ts +0 -28
- package/assembly/deserialize/simple/array/string.ts +0 -23
- package/assembly/deserialize/simple/array/struct.ts +0 -28
- package/assembly/deserialize/simple/float.ts +0 -201
- package/assembly/deserialize/simple/string.ts +0 -132
- package/assembly/serialize/simple/arbitrary.ts +0 -79
- package/assembly/serialize/simple/array.ts +0 -86
- package/assembly/serialize/simple/integer.ts +0 -20
- package/assembly/serialize/simple/object.ts +0 -42
- /package/assembly/deserialize/{simple → naive}/date.ts +0 -0
- /package/assembly/serialize/{simple → naive}/bool.ts +0 -0
- /package/assembly/serialize/{simple → naive}/date.ts +0 -0
- /package/assembly/serialize/{simple → naive}/struct.ts +0 -0
package/assembly/index.ts
CHANGED
|
@@ -2,39 +2,62 @@
|
|
|
2
2
|
|
|
3
3
|
import { bs } from "../lib/as-bs";
|
|
4
4
|
import { OBJECT, TOTAL_OVERHEAD } from "rt/common";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
5
|
+
import {
|
|
6
|
+
serializeArray,
|
|
7
|
+
serializeMap,
|
|
8
|
+
serializeDate,
|
|
9
|
+
serializeArbitrary,
|
|
10
|
+
serializeSet,
|
|
11
|
+
serializeStaticArray,
|
|
12
|
+
serializeBool,
|
|
13
|
+
serializeInteger,
|
|
14
|
+
serializeFloat,
|
|
15
|
+
serializeFloat32,
|
|
16
|
+
serializeFloat64,
|
|
17
|
+
serializeStruct,
|
|
18
|
+
serializeObject,
|
|
19
|
+
serializeRaw,
|
|
20
|
+
serializeString,
|
|
21
|
+
serializeArrayBufferUnsafe,
|
|
22
|
+
serializeDynamic,
|
|
23
|
+
serializeTypedArray,
|
|
24
|
+
} from "./serialize";
|
|
25
|
+
import {
|
|
26
|
+
deserializeBoolean,
|
|
27
|
+
deserializeArray,
|
|
28
|
+
deserializeFloat,
|
|
29
|
+
deserializeMap,
|
|
30
|
+
deserializeDate,
|
|
31
|
+
deserializeInteger,
|
|
32
|
+
deserializeUnsigned,
|
|
33
|
+
deserializeSet,
|
|
34
|
+
deserializeStaticArray,
|
|
35
|
+
deserializeArbitrary,
|
|
36
|
+
deserializeObject,
|
|
37
|
+
deserializeRaw,
|
|
38
|
+
deserializeString,
|
|
39
|
+
deserializeArrayBuffer,
|
|
40
|
+
deserializeTypedArray,
|
|
41
|
+
} from "./deserialize";
|
|
42
|
+
import {
|
|
43
|
+
BRACE_LEFT,
|
|
44
|
+
BRACE_RIGHT,
|
|
45
|
+
BRACKET_LEFT,
|
|
46
|
+
BRACKET_RIGHT,
|
|
47
|
+
COMMA,
|
|
48
|
+
NULL_WORD,
|
|
49
|
+
QUOTE,
|
|
50
|
+
NULL_WORD_U64,
|
|
51
|
+
TRUE_WORD_U64,
|
|
52
|
+
FALSE_WORD_U64,
|
|
53
|
+
} from "./custom/chars";
|
|
21
54
|
import { itoa_buffered } from "util/number";
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
import { serializeStruct } from "./serialize/index/struct";
|
|
55
|
+
import {
|
|
56
|
+
dragonbox_f32_buffered,
|
|
57
|
+
dragonbox_f64_buffered,
|
|
58
|
+
} from "./util/dragonbox";
|
|
27
59
|
import { ptrToStr } from "./util/ptrToStr";
|
|
28
60
|
import { atoi, bytes, scanStringEnd } from "./util";
|
|
29
|
-
import { deserializeArbitrary } from "./deserialize/index/arbitrary";
|
|
30
|
-
import { serializeObject } from "./serialize/index/object";
|
|
31
|
-
import { deserializeObject } from "./deserialize/index/object";
|
|
32
|
-
import { serializeRaw } from "./serialize/index/raw";
|
|
33
|
-
import { deserializeRaw } from "./deserialize/index/raw";
|
|
34
|
-
import { deserializeString } from "./deserialize/index/string";
|
|
35
|
-
import { serializeString } from "./serialize/index/string";
|
|
36
|
-
import { deserializeArrayBuffer, deserializeTypedArray } from "./deserialize/index/typedarray";
|
|
37
|
-
import { serializeArrayBufferUnsafe, serializeDynamic, serializeTypedArray } from "./serialize/index/typedarray";
|
|
38
61
|
|
|
39
62
|
/**
|
|
40
63
|
* Offset of the 'storage' property in the JSON.Value class.
|
|
@@ -71,7 +94,10 @@ export namespace JSON {
|
|
|
71
94
|
* @returns string
|
|
72
95
|
*/
|
|
73
96
|
// @ts-expect-error: inline
|
|
74
|
-
@inline export function stringify<T>(
|
|
97
|
+
@inline export function stringify<T>(
|
|
98
|
+
data: T,
|
|
99
|
+
out: string | null = null,
|
|
100
|
+
): string {
|
|
75
101
|
if (isBoolean<T>()) {
|
|
76
102
|
if (out) {
|
|
77
103
|
if (<bool>data == true) {
|
|
@@ -85,7 +111,12 @@ export namespace JSON {
|
|
|
85
111
|
return out;
|
|
86
112
|
}
|
|
87
113
|
return data ? "true" : "false";
|
|
88
|
-
} else if (
|
|
114
|
+
} else if (
|
|
115
|
+
isInteger<T>() &&
|
|
116
|
+
!isSigned<T>() &&
|
|
117
|
+
nameof<T>() == "usize" &&
|
|
118
|
+
data == 0
|
|
119
|
+
) {
|
|
89
120
|
if (out) {
|
|
90
121
|
out = changetype<string>(__renew(changetype<usize>(out), 8));
|
|
91
122
|
store<u64>(changetype<usize>(out), NULL_WORD_U64);
|
|
@@ -94,15 +125,24 @@ export namespace JSON {
|
|
|
94
125
|
return NULL_WORD;
|
|
95
126
|
} else if (isInteger<T>(data)) {
|
|
96
127
|
if (out) {
|
|
97
|
-
out = changetype<string>(
|
|
128
|
+
out = changetype<string>(
|
|
129
|
+
__renew(changetype<usize>(out), sizeof<T>() << 3),
|
|
130
|
+
);
|
|
98
131
|
|
|
99
132
|
const bytes = itoa_buffered(changetype<usize>(out), data) << 1;
|
|
100
|
-
return (out = changetype<string>(
|
|
133
|
+
return (out = changetype<string>(
|
|
134
|
+
__renew(changetype<usize>(out), bytes),
|
|
135
|
+
));
|
|
101
136
|
}
|
|
102
137
|
return data.toString();
|
|
103
138
|
} else if (isFloat<T>(data)) {
|
|
104
|
-
out = out
|
|
105
|
-
|
|
139
|
+
out = out
|
|
140
|
+
? changetype<string>(__renew(changetype<usize>(out), 64))
|
|
141
|
+
: changetype<string>(__new(64, idof<string>()));
|
|
142
|
+
const bytes =
|
|
143
|
+
(sizeof<T>() == 4
|
|
144
|
+
? dragonbox_f32_buffered(changetype<usize>(out), <f32>data)
|
|
145
|
+
: dragonbox_f64_buffered(changetype<usize>(out), <f64>data)) << 1;
|
|
106
146
|
return changetype<string>(__renew(changetype<usize>(out), bytes));
|
|
107
147
|
} else if (isNullable<T>() && changetype<usize>(data) == <usize>0) {
|
|
108
148
|
if (out) {
|
|
@@ -125,78 +165,21 @@ export namespace JSON {
|
|
|
125
165
|
inline.always(data.__SERIALIZE(changetype<usize>(data)));
|
|
126
166
|
return bs.out<string>();
|
|
127
167
|
} else if (data instanceof Date) {
|
|
128
|
-
out = out
|
|
168
|
+
out = out
|
|
169
|
+
? changetype<string>(__renew(changetype<usize>(out), 52))
|
|
170
|
+
: changetype<string>(__new(52, idof<string>()));
|
|
129
171
|
|
|
130
172
|
store<u16>(changetype<usize>(out), QUOTE);
|
|
131
|
-
memory.copy(
|
|
173
|
+
memory.copy(
|
|
174
|
+
changetype<usize>(out) + 2,
|
|
175
|
+
changetype<usize>(data.toISOString()),
|
|
176
|
+
48,
|
|
177
|
+
);
|
|
132
178
|
store<u16>(changetype<usize>(out), QUOTE, 50);
|
|
133
179
|
return changetype<string>(out);
|
|
134
|
-
} else if (data instanceof Array) {
|
|
135
|
-
// @ts-expect-error
|
|
136
|
-
inline.always(serializeArray(changetype<nonnull<T>>(data)));
|
|
137
|
-
return bs.out<string>();
|
|
138
|
-
} else if (data instanceof StaticArray) {
|
|
139
|
-
// @ts-expect-error
|
|
140
|
-
inline.always(serializeStaticArray(changetype<nonnull<T>>(data)));
|
|
141
|
-
return bs.out<string>();
|
|
142
|
-
} else if (data instanceof Int8Array) {
|
|
143
|
-
inline.always(serializeTypedArray<Int8Array>(data));
|
|
144
|
-
return bs.out<string>();
|
|
145
|
-
} else if (data instanceof Uint8Array) {
|
|
146
|
-
inline.always(serializeTypedArray<Uint8Array>(data));
|
|
147
|
-
return bs.out<string>();
|
|
148
|
-
} else if (data instanceof Uint8ClampedArray) {
|
|
149
|
-
inline.always(serializeTypedArray<Uint8ClampedArray>(data));
|
|
150
|
-
return bs.out<string>();
|
|
151
|
-
} else if (data instanceof Int16Array) {
|
|
152
|
-
inline.always(serializeTypedArray<Int16Array>(data));
|
|
153
|
-
return bs.out<string>();
|
|
154
|
-
} else if (data instanceof Uint16Array) {
|
|
155
|
-
inline.always(serializeTypedArray<Uint16Array>(data));
|
|
156
|
-
return bs.out<string>();
|
|
157
|
-
} else if (data instanceof Int32Array) {
|
|
158
|
-
inline.always(serializeTypedArray<Int32Array>(data));
|
|
159
|
-
return bs.out<string>();
|
|
160
|
-
} else if (data instanceof Uint32Array) {
|
|
161
|
-
inline.always(serializeTypedArray<Uint32Array>(data));
|
|
162
|
-
return bs.out<string>();
|
|
163
|
-
} else if (data instanceof Int64Array) {
|
|
164
|
-
inline.always(serializeTypedArray<Int64Array>(data));
|
|
165
|
-
return bs.out<string>();
|
|
166
|
-
} else if (data instanceof Uint64Array) {
|
|
167
|
-
inline.always(serializeTypedArray<Uint64Array>(data));
|
|
168
|
-
return bs.out<string>();
|
|
169
|
-
} else if (data instanceof Float32Array) {
|
|
170
|
-
inline.always(serializeTypedArray<Float32Array>(data));
|
|
171
|
-
return bs.out<string>();
|
|
172
|
-
} else if (data instanceof Float64Array) {
|
|
173
|
-
inline.always(serializeTypedArray<Float64Array>(data));
|
|
174
|
-
return bs.out<string>();
|
|
175
|
-
} else if (data instanceof ArrayBuffer) {
|
|
176
|
-
const dataStart = changetype<usize>(data);
|
|
177
|
-
serializeArrayBufferUnsafe(dataStart, changetype<OBJECT>(dataStart - TOTAL_OVERHEAD).rtSize);
|
|
178
|
-
return bs.out<string>();
|
|
179
|
-
} else if (data instanceof Set) {
|
|
180
|
-
// @ts-expect-error
|
|
181
|
-
inline.always(serializeSet(changetype<nonnull<T>>(data)));
|
|
182
|
-
return bs.out<string>();
|
|
183
|
-
} else if (data instanceof Map) {
|
|
184
|
-
// @ts-expect-error
|
|
185
|
-
inline.always(serializeMap(changetype<nonnull<T>>(data)));
|
|
186
|
-
return bs.out<string>();
|
|
187
|
-
} else if (data instanceof JSON.Raw) {
|
|
188
|
-
serializeRaw(data);
|
|
189
|
-
return bs.out<string>();
|
|
190
|
-
} else if (data instanceof JSON.Value) {
|
|
191
|
-
inline.always(serializeArbitrary(data));
|
|
192
|
-
return bs.out<string>();
|
|
193
|
-
} else if (data instanceof JSON.Obj) {
|
|
194
|
-
inline.always(serializeObject(data));
|
|
195
|
-
return bs.out<string>();
|
|
196
|
-
} else if (data instanceof JSON.Box) {
|
|
197
|
-
return JSON.stringify(data.value);
|
|
198
180
|
} else {
|
|
199
|
-
|
|
181
|
+
serializeReference<T>(data);
|
|
182
|
+
return bs.out<string>();
|
|
200
183
|
}
|
|
201
184
|
}
|
|
202
185
|
|
|
@@ -210,15 +193,29 @@ export namespace JSON {
|
|
|
210
193
|
*/
|
|
211
194
|
// @ts-expect-error: inline
|
|
212
195
|
@inline export function parse<T>(data: string): T {
|
|
213
|
-
|
|
214
|
-
const
|
|
196
|
+
let dataPtr = changetype<usize>(data);
|
|
197
|
+
const dataEnd = dataPtr + bytes(data);
|
|
198
|
+
// Entry point skips leading whitespace: every deserialize handler may then
|
|
199
|
+
// assume srcStart points at the first non-whitespace char. Handlers must
|
|
200
|
+
// NOT re-skip leading whitespace themselves. (Trailing whitespace is left
|
|
201
|
+
// intact — scalars stop at the value end, composites self-trim, and
|
|
202
|
+
// JSON.Raw intentionally preserves trailing bytes.)
|
|
203
|
+
while (dataPtr < dataEnd && JSON.Util.isSpace(load<u16>(dataPtr)))
|
|
204
|
+
dataPtr += 2;
|
|
205
|
+
const dataSize = dataEnd - dataPtr;
|
|
215
206
|
if (isBoolean<T>()) {
|
|
216
207
|
return deserializeBoolean(dataPtr, dataPtr + dataSize) as T;
|
|
217
208
|
} else if (isInteger<T>()) {
|
|
218
|
-
return isSigned<T>()
|
|
209
|
+
return isSigned<T>()
|
|
210
|
+
? deserializeInteger<T>(dataPtr, dataPtr + dataSize)
|
|
211
|
+
: deserializeUnsigned<T>(dataPtr, dataPtr + dataSize);
|
|
219
212
|
} else if (isFloat<T>()) {
|
|
220
213
|
return deserializeFloat<T>(dataPtr, dataPtr + dataSize);
|
|
221
|
-
} else if (
|
|
214
|
+
} else if (
|
|
215
|
+
isNullable<T>() &&
|
|
216
|
+
dataSize == 8 &&
|
|
217
|
+
load<u64>(dataPtr) == NULL_WORD_U64
|
|
218
|
+
) {
|
|
222
219
|
return null;
|
|
223
220
|
} else if (isString<T>()) {
|
|
224
221
|
return deserializeString(dataPtr, dataPtr + dataSize) as T;
|
|
@@ -230,13 +227,30 @@ export namespace JSON {
|
|
|
230
227
|
// @ts-expect-error
|
|
231
228
|
return out.__DESERIALIZE_CUSTOM(data);
|
|
232
229
|
// @ts-expect-error: Defined by transform
|
|
233
|
-
} else if (
|
|
234
|
-
|
|
230
|
+
} else if (
|
|
231
|
+
isDefined(type.__DESERIALIZE_SLOW) ||
|
|
232
|
+
isDefined(type.__DESERIALIZE_FAST)
|
|
233
|
+
) {
|
|
234
|
+
const out = changetype<nonnull<T>>(
|
|
235
|
+
__new(offsetof<nonnull<T>>(), idof<nonnull<T>>()),
|
|
236
|
+
);
|
|
235
237
|
// @ts-expect-error: Defined by transform
|
|
236
238
|
if (isDefined(type.__DESERIALIZE_FAST)) {
|
|
237
239
|
// @ts-expect-error: Defined by transform
|
|
238
|
-
|
|
239
|
-
|
|
240
|
+
const fastEnd = out.__DESERIALIZE_FAST(
|
|
241
|
+
dataPtr,
|
|
242
|
+
dataPtr + dataSize,
|
|
243
|
+
out,
|
|
244
|
+
);
|
|
245
|
+
// A non-zero return means the fast path matched; accept it when only
|
|
246
|
+
// trailing whitespace remains (pretty-printed input ends with a
|
|
247
|
+
// newline, so the cursor stops just past `}` rather than at srcEnd).
|
|
248
|
+
if (
|
|
249
|
+
fastEnd != 0 &&
|
|
250
|
+
JSON.Util.skipWhitespace(fastEnd, dataPtr + dataSize) ==
|
|
251
|
+
dataPtr + dataSize
|
|
252
|
+
)
|
|
253
|
+
return out;
|
|
240
254
|
}
|
|
241
255
|
if (isDefined(type.__INITIALIZE)) out.__INITIALIZE();
|
|
242
256
|
// @ts-expect-error: Defined by transform
|
|
@@ -249,40 +263,48 @@ export namespace JSON {
|
|
|
249
263
|
}
|
|
250
264
|
if (type instanceof StaticArray) {
|
|
251
265
|
// @ts-expect-error
|
|
252
|
-
return inline.always(
|
|
266
|
+
return inline.always(
|
|
267
|
+
deserializeStaticArray<nonnull<T>>(dataPtr, dataPtr + dataSize, 0),
|
|
268
|
+
);
|
|
253
269
|
} else if (type instanceof Array) {
|
|
254
270
|
// @ts-expect-error
|
|
255
|
-
return inline.always(
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
} else if (
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
return deserializeTypedArray<nonnull<T>>(
|
|
276
|
-
|
|
277
|
-
|
|
271
|
+
return inline.always(
|
|
272
|
+
deserializeArray<nonnull<T>>(
|
|
273
|
+
dataPtr,
|
|
274
|
+
dataPtr + dataSize,
|
|
275
|
+
changetype<usize>(instantiate<T>()),
|
|
276
|
+
),
|
|
277
|
+
);
|
|
278
|
+
} else if (
|
|
279
|
+
type instanceof Int8Array ||
|
|
280
|
+
type instanceof Uint8Array ||
|
|
281
|
+
type instanceof Uint8ClampedArray ||
|
|
282
|
+
type instanceof Int16Array ||
|
|
283
|
+
type instanceof Uint16Array ||
|
|
284
|
+
type instanceof Int32Array ||
|
|
285
|
+
type instanceof Uint32Array ||
|
|
286
|
+
type instanceof Int64Array ||
|
|
287
|
+
type instanceof Uint64Array ||
|
|
288
|
+
type instanceof Float32Array ||
|
|
289
|
+
type instanceof Float64Array
|
|
290
|
+
) {
|
|
291
|
+
return deserializeTypedArray<nonnull<T>>(
|
|
292
|
+
dataPtr,
|
|
293
|
+
dataPtr + dataSize,
|
|
294
|
+
0,
|
|
295
|
+
) as T;
|
|
278
296
|
} else if (type instanceof ArrayBuffer) {
|
|
279
297
|
return deserializeArrayBuffer(dataPtr, dataPtr + dataSize, 0) as T;
|
|
280
298
|
} else if (type instanceof Set) {
|
|
281
299
|
// @ts-expect-error
|
|
282
|
-
return inline.always(
|
|
300
|
+
return inline.always(
|
|
301
|
+
deserializeSet<nonnull<T>>(dataPtr, dataPtr + dataSize, 0),
|
|
302
|
+
);
|
|
283
303
|
} else if (type instanceof Map) {
|
|
284
304
|
// @ts-expect-error
|
|
285
|
-
return inline.always(
|
|
305
|
+
return inline.always(
|
|
306
|
+
deserializeMap<nonnull<T>>(dataPtr, dataPtr + dataSize, 0),
|
|
307
|
+
);
|
|
286
308
|
} else if (type instanceof Date) {
|
|
287
309
|
// @ts-expect-error
|
|
288
310
|
return deserializeDate(dataPtr, dataPtr + dataSize);
|
|
@@ -291,7 +313,9 @@ export namespace JSON {
|
|
|
291
313
|
return deserializeRaw(dataPtr, dataPtr + dataSize);
|
|
292
314
|
} else if (type instanceof JSON.Value) {
|
|
293
315
|
// @ts-expect-error
|
|
294
|
-
return inline.always(
|
|
316
|
+
return inline.always(
|
|
317
|
+
deserializeArbitrary(dataPtr, dataPtr + dataSize, 0),
|
|
318
|
+
);
|
|
295
319
|
} else if (type instanceof JSON.Obj) {
|
|
296
320
|
// @ts-expect-error
|
|
297
321
|
return inline.always(deserializeObject(dataPtr, dataPtr + dataSize, 0));
|
|
@@ -299,7 +323,11 @@ export namespace JSON {
|
|
|
299
323
|
// @ts-expect-error
|
|
300
324
|
return new JSON.Box(parseBox(data, changetype<nonnull<T>>(0).value));
|
|
301
325
|
} else {
|
|
302
|
-
throw new Error(
|
|
326
|
+
throw new Error(
|
|
327
|
+
`Could not deserialize JSON to type '${nameof<T>()}'. ` +
|
|
328
|
+
`If this is a custom class, ensure it has the @json decorator: @json class ${nameof<T>()} { ... }. ` +
|
|
329
|
+
`Input: "${data.length > 50 ? data.slice(0, 50) + "..." : data}"`,
|
|
330
|
+
);
|
|
303
331
|
}
|
|
304
332
|
}
|
|
305
333
|
}
|
|
@@ -450,7 +478,9 @@ export namespace JSON {
|
|
|
450
478
|
* @returns An instance of JSON.Value.
|
|
451
479
|
*/
|
|
452
480
|
@inline static empty(): JSON.Value {
|
|
453
|
-
return changetype<JSON.Value>(
|
|
481
|
+
return changetype<JSON.Value>(
|
|
482
|
+
__new(offsetof<JSON.Value>(), idof<JSON.Value>()),
|
|
483
|
+
);
|
|
454
484
|
}
|
|
455
485
|
|
|
456
486
|
/**
|
|
@@ -460,7 +490,9 @@ export namespace JSON {
|
|
|
460
490
|
*/
|
|
461
491
|
@inline static from<T>(value: T): JSON.Value {
|
|
462
492
|
if (value instanceof JSON.Value) return value;
|
|
463
|
-
const out = changetype<JSON.Value>(
|
|
493
|
+
const out = changetype<JSON.Value>(
|
|
494
|
+
__new(offsetof<JSON.Value>(), idof<JSON.Value>()),
|
|
495
|
+
);
|
|
464
496
|
out.set<T>(value);
|
|
465
497
|
return out;
|
|
466
498
|
}
|
|
@@ -471,12 +503,20 @@ export namespace JSON {
|
|
|
471
503
|
* @returns JSON.Types
|
|
472
504
|
*/
|
|
473
505
|
@inline getType<T>(value: T): JSON.Types {
|
|
474
|
-
if (isNullable<T>() && changetype<usize>(value) === 0)
|
|
506
|
+
if (isNullable<T>() && changetype<usize>(value) === 0)
|
|
507
|
+
return JSON.Types.Null;
|
|
475
508
|
if (isBoolean<T>()) return JSON.Types.Bool;
|
|
476
|
-
if (
|
|
509
|
+
if (
|
|
510
|
+
isInteger<T>() &&
|
|
511
|
+
!isSigned<T>() &&
|
|
512
|
+
changetype<usize>(value) == 0 &&
|
|
513
|
+
nameof<T>() == "usize"
|
|
514
|
+
)
|
|
515
|
+
return JSON.Types.Null;
|
|
477
516
|
if (isString<T>()) return JSON.Types.String;
|
|
478
517
|
// @ts-expect-error: can assume that T is ArrayLike based on previous condition
|
|
479
|
-
if (isArray<T>() && idof<valueof<T>>() == idof<JSON.Value>())
|
|
518
|
+
if (isArray<T>() && idof<valueof<T>>() == idof<JSON.Value>())
|
|
519
|
+
return JSON.Types.Array;
|
|
480
520
|
if (value instanceof JSON.Box) return this.getType(value.value);
|
|
481
521
|
if (value instanceof i8) return JSON.Types.I8;
|
|
482
522
|
if (value instanceof i16) return JSON.Types.I16;
|
|
@@ -489,18 +529,22 @@ export namespace JSON {
|
|
|
489
529
|
if (value instanceof f32) return JSON.Types.F32;
|
|
490
530
|
if (value instanceof f64) return JSON.Types.F64;
|
|
491
531
|
// @ts-expect-error: supplied by transform
|
|
492
|
-
if (isDefined(value.__SERIALIZE) && isManaged<T>(value))
|
|
493
|
-
|
|
494
|
-
if (
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
532
|
+
if (isDefined(value.__SERIALIZE) && isManaged<T>(value))
|
|
533
|
+
return u16(idof<T>()) + JSON.Types.Struct;
|
|
534
|
+
if (
|
|
535
|
+
value instanceof Int8Array ||
|
|
536
|
+
value instanceof Uint8Array ||
|
|
537
|
+
value instanceof Uint8ClampedArray ||
|
|
538
|
+
value instanceof Int16Array ||
|
|
539
|
+
value instanceof Uint16Array ||
|
|
540
|
+
value instanceof Int32Array ||
|
|
541
|
+
value instanceof Uint32Array ||
|
|
542
|
+
value instanceof Int64Array ||
|
|
543
|
+
value instanceof Uint64Array ||
|
|
544
|
+
value instanceof Float32Array ||
|
|
545
|
+
value instanceof Float64Array
|
|
546
|
+
)
|
|
547
|
+
return JSON.Types.TypedArray;
|
|
504
548
|
if (value instanceof ArrayBuffer) return JSON.Types.ArrayBuffer;
|
|
505
549
|
if (value instanceof Map) return JSON.Types.Map;
|
|
506
550
|
if (value instanceof JSON.Raw) return JSON.Types.Raw;
|
|
@@ -515,29 +559,47 @@ export namespace JSON {
|
|
|
515
559
|
this.type = this.getType<T>(value);
|
|
516
560
|
|
|
517
561
|
if (value instanceof JSON.Box) this.set(value.value);
|
|
518
|
-
else if (isBoolean<T>())
|
|
519
|
-
|
|
520
|
-
else if (
|
|
521
|
-
|
|
562
|
+
else if (isBoolean<T>())
|
|
563
|
+
store<T>(changetype<usize>(this), value, STORAGE);
|
|
564
|
+
else if (
|
|
565
|
+
isInteger<T>() &&
|
|
566
|
+
!isSigned<T>() &&
|
|
567
|
+
changetype<usize>(value) == 0 &&
|
|
568
|
+
nameof<T>() == "usize"
|
|
569
|
+
)
|
|
570
|
+
store<usize>(changetype<usize>(this), 0, STORAGE);
|
|
571
|
+
else if (isInteger<T>() || isFloat<T>())
|
|
572
|
+
store<T>(changetype<usize>(this), value, STORAGE);
|
|
573
|
+
else if (isNullable<T>() && changetype<usize>(value) === 0)
|
|
574
|
+
store<usize>(changetype<usize>(this), 0, STORAGE);
|
|
522
575
|
else if (isString<T>()) store<T>(changetype<usize>(this), value, STORAGE);
|
|
523
|
-
else if (value instanceof JSON.Raw)
|
|
576
|
+
else if (value instanceof JSON.Raw)
|
|
577
|
+
store<T>(changetype<usize>(this), value, STORAGE);
|
|
524
578
|
// @ts-expect-error: supplied by transform
|
|
525
579
|
else if (isDefined(value.__SERIALIZE) && isManaged<T>(value)) {
|
|
526
580
|
// @ts-expect-error
|
|
527
|
-
if (!JSON.Value.METHODS.has(idof<T>()))
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
else if (
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
581
|
+
if (!JSON.Value.METHODS.has(idof<T>()))
|
|
582
|
+
JSON.Value.METHODS.set(idof<T>(), value.__SERIALIZE.index);
|
|
583
|
+
store<usize>(
|
|
584
|
+
changetype<usize>(this),
|
|
585
|
+
changetype<usize>(value),
|
|
586
|
+
STORAGE,
|
|
587
|
+
);
|
|
588
|
+
} else if (
|
|
589
|
+
value instanceof Int8Array ||
|
|
590
|
+
value instanceof Uint8Array ||
|
|
591
|
+
value instanceof Uint8ClampedArray ||
|
|
592
|
+
value instanceof Int16Array ||
|
|
593
|
+
value instanceof Uint16Array ||
|
|
594
|
+
value instanceof Int32Array ||
|
|
595
|
+
value instanceof Uint32Array ||
|
|
596
|
+
value instanceof Int64Array ||
|
|
597
|
+
value instanceof Uint64Array ||
|
|
598
|
+
value instanceof Float32Array ||
|
|
599
|
+
value instanceof Float64Array ||
|
|
600
|
+
value instanceof ArrayBuffer
|
|
601
|
+
)
|
|
602
|
+
store<T>(changetype<usize>(this), value, STORAGE);
|
|
541
603
|
else if (value instanceof Map) {
|
|
542
604
|
if (idof<T>() !== idof<Map<string, JSON.Value>>()) {
|
|
543
605
|
abort("Maps must be of type Map<string, JSON.Value>!");
|
|
@@ -769,7 +831,9 @@ export namespace JSON {
|
|
|
769
831
|
|
|
770
832
|
const parsed = JSON.parse<JSON.Value>(JSON.stringify(value));
|
|
771
833
|
if (parsed.type != JSON.Types.Object) {
|
|
772
|
-
throw new Error(
|
|
834
|
+
throw new Error(
|
|
835
|
+
"JSON.Obj.from expects a value that serializes to a JSON object",
|
|
836
|
+
);
|
|
773
837
|
}
|
|
774
838
|
return parsed.get<JSON.Obj>();
|
|
775
839
|
}
|
|
@@ -779,7 +843,8 @@ export namespace JSON {
|
|
|
779
843
|
*/
|
|
780
844
|
export class Box<T> {
|
|
781
845
|
constructor(public value: T) {
|
|
782
|
-
if (!isInteger<T>() && !isFloat<T>() && !isBoolean<T>())
|
|
846
|
+
if (!isInteger<T>() && !isFloat<T>() && !isBoolean<T>())
|
|
847
|
+
ERROR("JSON.Box should only hold primitive types!");
|
|
783
848
|
}
|
|
784
849
|
/**
|
|
785
850
|
* Set the internal value of Box to new value
|
|
@@ -802,9 +867,11 @@ export namespace JSON {
|
|
|
802
867
|
* @returns Box<T> | null
|
|
803
868
|
*/
|
|
804
869
|
@inline static fromValue<T>(value: JSON.Value): Box<T> | null {
|
|
805
|
-
if (!(value instanceof JSON.Value))
|
|
870
|
+
if (!(value instanceof JSON.Value))
|
|
871
|
+
throw new Error("value must be of type JSON.Value");
|
|
806
872
|
if (value.type === JSON.Types.Null) return null;
|
|
807
|
-
const v =
|
|
873
|
+
const v =
|
|
874
|
+
value.type === JSON.Types.F64 ? value.get<f64>() : value.get<T>();
|
|
808
875
|
// @ts-expect-error
|
|
809
876
|
return new Box(isInteger<T>() || isFloat<T>() ? <T>v : v);
|
|
810
877
|
}
|
|
@@ -835,7 +902,7 @@ export namespace JSON {
|
|
|
835
902
|
* @param data - T
|
|
836
903
|
* @returns void
|
|
837
904
|
*/
|
|
838
|
-
|
|
905
|
+
function __serialize<T>(data: T): void {
|
|
839
906
|
if (isBoolean<T>()) {
|
|
840
907
|
serializeBool(data as bool);
|
|
841
908
|
} else if (isInteger<T>() && nameof<T>() == "usize" && data == 0) {
|
|
@@ -867,53 +934,8 @@ export namespace JSON {
|
|
|
867
934
|
} else if (data instanceof Date) {
|
|
868
935
|
// @ts-expect-error
|
|
869
936
|
inline.always(serializeDate(changetype<nonnull<T>>(data)));
|
|
870
|
-
} else if (data instanceof Array) {
|
|
871
|
-
// @ts-expect-error
|
|
872
|
-
serializeArray(changetype<nonnull<T>>(data));
|
|
873
|
-
} else if (data instanceof StaticArray) {
|
|
874
|
-
// @ts-expect-error
|
|
875
|
-
serializeStaticArray(changetype<nonnull<T>>(data));
|
|
876
|
-
} else if (data instanceof Int8Array) {
|
|
877
|
-
serializeTypedArray<Int8Array>(data);
|
|
878
|
-
} else if (data instanceof Uint8Array) {
|
|
879
|
-
serializeTypedArray<Uint8Array>(data);
|
|
880
|
-
} else if (data instanceof Uint8ClampedArray) {
|
|
881
|
-
serializeTypedArray<Uint8ClampedArray>(data);
|
|
882
|
-
} else if (data instanceof Int16Array) {
|
|
883
|
-
serializeTypedArray<Int16Array>(data);
|
|
884
|
-
} else if (data instanceof Uint16Array) {
|
|
885
|
-
serializeTypedArray<Uint16Array>(data);
|
|
886
|
-
} else if (data instanceof Int32Array) {
|
|
887
|
-
serializeTypedArray<Int32Array>(data);
|
|
888
|
-
} else if (data instanceof Uint32Array) {
|
|
889
|
-
serializeTypedArray<Uint32Array>(data);
|
|
890
|
-
} else if (data instanceof Int64Array) {
|
|
891
|
-
serializeTypedArray<Int64Array>(data);
|
|
892
|
-
} else if (data instanceof Uint64Array) {
|
|
893
|
-
serializeTypedArray<Uint64Array>(data);
|
|
894
|
-
} else if (data instanceof Float32Array) {
|
|
895
|
-
serializeTypedArray<Float32Array>(data);
|
|
896
|
-
} else if (data instanceof Float64Array) {
|
|
897
|
-
serializeTypedArray<Float64Array>(data);
|
|
898
|
-
} else if (data instanceof ArrayBuffer) {
|
|
899
|
-
const dataStart = changetype<usize>(data);
|
|
900
|
-
serializeArrayBufferUnsafe(dataStart, changetype<OBJECT>(dataStart - TOTAL_OVERHEAD).rtSize);
|
|
901
|
-
} else if (data instanceof Set) {
|
|
902
|
-
// @ts-expect-error
|
|
903
|
-
serializeSet(changetype<nonnull<T>>(data));
|
|
904
|
-
} else if (data instanceof Map) {
|
|
905
|
-
// @ts-expect-error
|
|
906
|
-
serializeMap(changetype<nonnull<T>>(data));
|
|
907
|
-
} else if (data instanceof JSON.Raw) {
|
|
908
|
-
serializeRaw(data);
|
|
909
|
-
} else if (data instanceof JSON.Value) {
|
|
910
|
-
serializeArbitrary(data);
|
|
911
|
-
} else if (data instanceof JSON.Obj) {
|
|
912
|
-
serializeObject(data);
|
|
913
|
-
} else if (data instanceof JSON.Box) {
|
|
914
|
-
__serialize(data.value);
|
|
915
937
|
} else {
|
|
916
|
-
|
|
938
|
+
serializeReference<T>(data);
|
|
917
939
|
}
|
|
918
940
|
}
|
|
919
941
|
|
|
@@ -925,19 +947,33 @@ export namespace JSON {
|
|
|
925
947
|
* @param dst - usize
|
|
926
948
|
* @returns void
|
|
927
949
|
*/
|
|
928
|
-
|
|
950
|
+
function __deserialize<T>(srcStart: usize, srcEnd: usize, dst: usize = 0): T {
|
|
951
|
+
// Skip leading whitespace once here so every handler below may assume
|
|
952
|
+
// srcStart is at the first non-whitespace char. (Trailing whitespace is
|
|
953
|
+
// left intact — composites self-trim and JSON.Raw preserves it.)
|
|
954
|
+
while (srcStart < srcEnd && JSON.Util.isSpace(load<u16>(srcStart)))
|
|
955
|
+
srcStart += 2;
|
|
929
956
|
if (isBoolean<T>()) {
|
|
930
957
|
// @ts-expect-error: type
|
|
931
958
|
return deserializeBoolean(srcStart, srcEnd);
|
|
932
959
|
} else if (isInteger<T>()) {
|
|
933
|
-
return isSigned<T>()
|
|
960
|
+
return isSigned<T>()
|
|
961
|
+
? deserializeInteger<T>(srcStart, srcEnd)
|
|
962
|
+
: deserializeUnsigned<T>(srcStart, srcEnd);
|
|
934
963
|
} else if (isFloat<T>()) {
|
|
935
964
|
return deserializeFloat<T>(srcStart, srcEnd);
|
|
936
965
|
} else if (isString<T>()) {
|
|
937
|
-
if (srcEnd - srcStart < 4)
|
|
966
|
+
if (srcEnd - srcStart < 4)
|
|
967
|
+
throw new Error(
|
|
968
|
+
"Cannot parse data as string because it was formatted incorrectly!",
|
|
969
|
+
);
|
|
938
970
|
|
|
939
971
|
return deserializeString(srcStart, srcEnd) as T;
|
|
940
|
-
} else if (
|
|
972
|
+
} else if (
|
|
973
|
+
isNullable<T>() &&
|
|
974
|
+
srcEnd - srcStart == 8 &&
|
|
975
|
+
load<u64>(srcStart) == NULL_WORD_U64
|
|
976
|
+
) {
|
|
941
977
|
return null;
|
|
942
978
|
} else {
|
|
943
979
|
let type: nonnull<T> = changetype<nonnull<T>>(0);
|
|
@@ -947,12 +983,23 @@ export namespace JSON {
|
|
|
947
983
|
// @ts-expect-error: Defined by transform
|
|
948
984
|
return out.__DESERIALIZE_CUSTOM(ptrToStr(srcStart, srcEnd));
|
|
949
985
|
// @ts-expect-error: Defined by transform
|
|
950
|
-
} else if (
|
|
951
|
-
|
|
986
|
+
} else if (
|
|
987
|
+
isDefined(type.__DESERIALIZE_SLOW) ||
|
|
988
|
+
isDefined(type.__DESERIALIZE_FAST)
|
|
989
|
+
) {
|
|
990
|
+
const out = changetype<nonnull<T>>(
|
|
991
|
+
dst || __new(offsetof<nonnull<T>>(), idof<nonnull<T>>()),
|
|
992
|
+
);
|
|
952
993
|
// @ts-expect-error: Defined by transform
|
|
953
994
|
if (isDefined(type.__DESERIALIZE_FAST)) {
|
|
954
995
|
// @ts-expect-error: Defined by transform
|
|
955
|
-
|
|
996
|
+
const fastEnd = out.__DESERIALIZE_FAST(srcStart, srcEnd, out);
|
|
997
|
+
// Accept the fast path when only trailing whitespace remains.
|
|
998
|
+
if (
|
|
999
|
+
fastEnd != 0 &&
|
|
1000
|
+
JSON.Util.skipWhitespace(fastEnd, srcEnd) == srcEnd
|
|
1001
|
+
)
|
|
1002
|
+
return out;
|
|
956
1003
|
}
|
|
957
1004
|
// @ts-expect-error: Defined by transform
|
|
958
1005
|
if (isDefined(type.__INITIALIZE)) out.__INITIALIZE();
|
|
@@ -970,27 +1017,19 @@ export namespace JSON {
|
|
|
970
1017
|
} else if (type instanceof Array) {
|
|
971
1018
|
// @ts-expect-error: type
|
|
972
1019
|
return deserializeArray<T>(srcStart, srcEnd, dst);
|
|
973
|
-
} else if (
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
return deserializeTypedArray<nonnull<T>>(srcStart, srcEnd, dst) as T;
|
|
987
|
-
} else if (type instanceof Int64Array) {
|
|
988
|
-
return deserializeTypedArray<nonnull<T>>(srcStart, srcEnd, dst) as T;
|
|
989
|
-
} else if (type instanceof Uint64Array) {
|
|
990
|
-
return deserializeTypedArray<nonnull<T>>(srcStart, srcEnd, dst) as T;
|
|
991
|
-
} else if (type instanceof Float32Array) {
|
|
992
|
-
return deserializeTypedArray<nonnull<T>>(srcStart, srcEnd, dst) as T;
|
|
993
|
-
} else if (type instanceof Float64Array) {
|
|
1020
|
+
} else if (
|
|
1021
|
+
type instanceof Int8Array ||
|
|
1022
|
+
type instanceof Uint8Array ||
|
|
1023
|
+
type instanceof Uint8ClampedArray ||
|
|
1024
|
+
type instanceof Int16Array ||
|
|
1025
|
+
type instanceof Uint16Array ||
|
|
1026
|
+
type instanceof Int32Array ||
|
|
1027
|
+
type instanceof Uint32Array ||
|
|
1028
|
+
type instanceof Int64Array ||
|
|
1029
|
+
type instanceof Uint64Array ||
|
|
1030
|
+
type instanceof Float32Array ||
|
|
1031
|
+
type instanceof Float64Array
|
|
1032
|
+
) {
|
|
994
1033
|
return deserializeTypedArray<nonnull<T>>(srcStart, srcEnd, dst) as T;
|
|
995
1034
|
} else if (type instanceof ArrayBuffer) {
|
|
996
1035
|
return deserializeArrayBuffer(srcStart, srcEnd, dst) as T;
|
|
@@ -1014,19 +1053,42 @@ export namespace JSON {
|
|
|
1014
1053
|
return deserializeObject(srcStart, srcEnd, 0);
|
|
1015
1054
|
} else if (type instanceof JSON.Box) {
|
|
1016
1055
|
// @ts-expect-error: type
|
|
1017
|
-
return new JSON.Box(
|
|
1056
|
+
return new JSON.Box(
|
|
1057
|
+
deserializeBox(
|
|
1058
|
+
srcStart,
|
|
1059
|
+
srcEnd,
|
|
1060
|
+
dst,
|
|
1061
|
+
changetype<nonnull<T>>(0).value,
|
|
1062
|
+
),
|
|
1063
|
+
);
|
|
1018
1064
|
}
|
|
1019
1065
|
}
|
|
1020
1066
|
const snippet = ptrToStr(srcStart, srcEnd);
|
|
1021
|
-
throw new Error(
|
|
1067
|
+
throw new Error(
|
|
1068
|
+
`Could not deserialize JSON to type '${nameof<T>()}'. ` +
|
|
1069
|
+
`If this is a custom class, ensure it has the @json decorator: @json class ${nameof<T>()} { ... }. ` +
|
|
1070
|
+
`Input: "${snippet.length > 50 ? snippet.slice(0, 50) + "..." : snippet}"`,
|
|
1071
|
+
);
|
|
1022
1072
|
}
|
|
1023
1073
|
export namespace Util {
|
|
1024
1074
|
// @ts-expect-error: decorator
|
|
1025
1075
|
@inline export function isSpace(code: u16): boolean {
|
|
1026
1076
|
return code == 0x20 || code - 9 <= 4;
|
|
1027
1077
|
}
|
|
1078
|
+
/** Advance past JSON whitespace (space, tab, LF, VT, FF, CR). */
|
|
1079
|
+
// @ts-expect-error: decorator
|
|
1080
|
+
@inline export function skipWhitespace(
|
|
1081
|
+
srcStart: usize,
|
|
1082
|
+
srcEnd: usize,
|
|
1083
|
+
): usize {
|
|
1084
|
+
while (srcStart < srcEnd && isSpace(load<u16>(srcStart))) srcStart += 2;
|
|
1085
|
+
return srcStart;
|
|
1086
|
+
}
|
|
1028
1087
|
// @ts-expect-error: decorator
|
|
1029
|
-
@inline export function scanValueEnd(
|
|
1088
|
+
@inline export function scanValueEnd(
|
|
1089
|
+
srcStart: usize,
|
|
1090
|
+
srcEnd: usize,
|
|
1091
|
+
): usize {
|
|
1030
1092
|
if (srcStart >= srcEnd) return 0;
|
|
1031
1093
|
let ptr = srcStart;
|
|
1032
1094
|
while (ptr < srcEnd && isSpace(load<u16>(ptr))) ptr += 2;
|
|
@@ -1061,7 +1123,13 @@ export namespace JSON {
|
|
|
1061
1123
|
|
|
1062
1124
|
while (ptr < srcEnd) {
|
|
1063
1125
|
const code = load<u16>(ptr);
|
|
1064
|
-
if (
|
|
1126
|
+
if (
|
|
1127
|
+
code == COMMA ||
|
|
1128
|
+
code == BRACKET_RIGHT ||
|
|
1129
|
+
code == BRACE_RIGHT ||
|
|
1130
|
+
isSpace(code)
|
|
1131
|
+
)
|
|
1132
|
+
return ptr;
|
|
1065
1133
|
ptr += 2;
|
|
1066
1134
|
}
|
|
1067
1135
|
|
|
@@ -1079,7 +1147,7 @@ export namespace JSON {
|
|
|
1079
1147
|
* Methods for use when using JSON methods inside another JSON method or custom serializer/deserializer
|
|
1080
1148
|
* Transform will automatically convert JSON.x calls to JSON.internal.x when in a custom (de)serializer
|
|
1081
1149
|
*/
|
|
1082
|
-
|
|
1150
|
+
namespace internal {
|
|
1083
1151
|
/**
|
|
1084
1152
|
* Serializes JSON data. Don't use this directly, use `JSON.stringify` instead.
|
|
1085
1153
|
* @param data - T
|
|
@@ -1087,7 +1155,10 @@ export namespace JSON {
|
|
|
1087
1155
|
* @returns - string
|
|
1088
1156
|
*/
|
|
1089
1157
|
// @ts-expect-error: inline
|
|
1090
|
-
@inline export function stringify<T>(
|
|
1158
|
+
@inline export function stringify<T>(
|
|
1159
|
+
data: T,
|
|
1160
|
+
out: string | null = null,
|
|
1161
|
+
): string {
|
|
1091
1162
|
bs.saveState();
|
|
1092
1163
|
JSON.__serialize<T>(data);
|
|
1093
1164
|
const result = bs.cpyOut<string>();
|
|
@@ -1116,6 +1187,71 @@ export namespace JSON {
|
|
|
1116
1187
|
}
|
|
1117
1188
|
}
|
|
1118
1189
|
|
|
1190
|
+
/**
|
|
1191
|
+
* Shared reference-type serialization chain used by both {@link JSON.stringify}
|
|
1192
|
+
* and {@link JSON.__serialize}. Writes directly to the active buffer. Primitive
|
|
1193
|
+
* and `Date` fast paths are handled by the callers (which have buffer-reuse
|
|
1194
|
+
* optimizations); everything else routes here so the dispatch chain lives once.
|
|
1195
|
+
*/
|
|
1196
|
+
// @ts-expect-error: @inline is a valid decorator
|
|
1197
|
+
@inline function serializeReference<T>(data: T): void {
|
|
1198
|
+
if (data instanceof Array) {
|
|
1199
|
+
// @ts-expect-error
|
|
1200
|
+
serializeArray(changetype<nonnull<T>>(data));
|
|
1201
|
+
} else if (data instanceof StaticArray) {
|
|
1202
|
+
// @ts-expect-error
|
|
1203
|
+
serializeStaticArray(changetype<nonnull<T>>(data));
|
|
1204
|
+
} else if (data instanceof Int8Array) {
|
|
1205
|
+
serializeTypedArray<Int8Array>(data);
|
|
1206
|
+
} else if (data instanceof Uint8Array) {
|
|
1207
|
+
serializeTypedArray<Uint8Array>(data);
|
|
1208
|
+
} else if (data instanceof Uint8ClampedArray) {
|
|
1209
|
+
serializeTypedArray<Uint8ClampedArray>(data);
|
|
1210
|
+
} else if (data instanceof Int16Array) {
|
|
1211
|
+
serializeTypedArray<Int16Array>(data);
|
|
1212
|
+
} else if (data instanceof Uint16Array) {
|
|
1213
|
+
serializeTypedArray<Uint16Array>(data);
|
|
1214
|
+
} else if (data instanceof Int32Array) {
|
|
1215
|
+
serializeTypedArray<Int32Array>(data);
|
|
1216
|
+
} else if (data instanceof Uint32Array) {
|
|
1217
|
+
serializeTypedArray<Uint32Array>(data);
|
|
1218
|
+
} else if (data instanceof Int64Array) {
|
|
1219
|
+
serializeTypedArray<Int64Array>(data);
|
|
1220
|
+
} else if (data instanceof Uint64Array) {
|
|
1221
|
+
serializeTypedArray<Uint64Array>(data);
|
|
1222
|
+
} else if (data instanceof Float32Array) {
|
|
1223
|
+
serializeTypedArray<Float32Array>(data);
|
|
1224
|
+
} else if (data instanceof Float64Array) {
|
|
1225
|
+
serializeTypedArray<Float64Array>(data);
|
|
1226
|
+
} else if (data instanceof ArrayBuffer) {
|
|
1227
|
+
const dataStart = changetype<usize>(data);
|
|
1228
|
+
serializeArrayBufferUnsafe(
|
|
1229
|
+
dataStart,
|
|
1230
|
+
changetype<OBJECT>(dataStart - TOTAL_OVERHEAD).rtSize,
|
|
1231
|
+
);
|
|
1232
|
+
} else if (data instanceof Set) {
|
|
1233
|
+
// @ts-expect-error
|
|
1234
|
+
serializeSet(changetype<nonnull<T>>(data));
|
|
1235
|
+
} else if (data instanceof Map) {
|
|
1236
|
+
// @ts-expect-error
|
|
1237
|
+
serializeMap(changetype<nonnull<T>>(data));
|
|
1238
|
+
} else if (data instanceof JSON.Raw) {
|
|
1239
|
+
serializeRaw(data);
|
|
1240
|
+
} else if (data instanceof JSON.Value) {
|
|
1241
|
+
serializeArbitrary(data);
|
|
1242
|
+
} else if (data instanceof JSON.Obj) {
|
|
1243
|
+
serializeObject(data);
|
|
1244
|
+
} else if (data instanceof JSON.Box) {
|
|
1245
|
+
JSON.__serialize(data.value);
|
|
1246
|
+
} else {
|
|
1247
|
+
throw new Error(
|
|
1248
|
+
`Could not serialize data of type '${nameof<T>()}'. ` +
|
|
1249
|
+
`If this is a custom class, add the @json decorator: @json class ${nameof<T>()} { ... }. ` +
|
|
1250
|
+
`Supported types: primitives, string, Array, StaticArray, TypedArray, ArrayBuffer, Map, Date, and @json decorated classes.`,
|
|
1251
|
+
);
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1119
1255
|
export enum JSONMode {
|
|
1120
1256
|
SWAR = 0,
|
|
1121
1257
|
SIMD = 1,
|
|
@@ -1127,7 +1263,12 @@ export enum JSONMode {
|
|
|
1127
1263
|
return JSON.parse<T>(data);
|
|
1128
1264
|
}
|
|
1129
1265
|
// @ts-expect-error: inline
|
|
1130
|
-
@inline function deserializeBox<T>(
|
|
1266
|
+
@inline function deserializeBox<T>(
|
|
1267
|
+
srcStart: usize,
|
|
1268
|
+
srcEnd: usize,
|
|
1269
|
+
dst: usize,
|
|
1270
|
+
ty: T,
|
|
1271
|
+
): T {
|
|
1131
1272
|
return JSON.__deserialize<T>(srcStart, srcEnd, dst);
|
|
1132
1273
|
}
|
|
1133
1274
|
|