json-as 1.2.2 → 1.2.3
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/README.md +2 -0
- package/assembly/deserialize/simd/string.ts +174 -78
- package/assembly/deserialize/simple/arbitrary.ts +1 -2
- package/assembly/deserialize/simple/object.ts +1 -1
- package/assembly/deserialize/simple/string.ts +31 -40
- package/assembly/deserialize/swar/string.ts +146 -109
- package/assembly/globals/tables.ts +1 -1
- package/assembly/index.ts +112 -163
- package/assembly/serialize/simd/string.ts +136 -39
- package/assembly/serialize/simple/arbitrary.ts +18 -10
- package/assembly/serialize/simple/string.ts +54 -4
- package/assembly/serialize/swar/string.ts +112 -69
- package/assembly/test.mask.ts +87 -0
- package/assembly/test.ts +38 -34
- package/assembly/util/masks.ts +47 -0
- package/assembly/util/swar.ts +14 -0
- package/package.json +1 -1
|
@@ -1,21 +1,36 @@
|
|
|
1
1
|
import { bs } from "../../../lib/as-bs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
//
|
|
8
|
-
|
|
9
|
-
//
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
//
|
|
14
|
-
|
|
15
|
-
//
|
|
16
|
-
|
|
17
|
-
//
|
|
18
|
-
|
|
2
|
+
import { DESERIALIZE_ESCAPE_TABLE } from "../../globals/tables";
|
|
3
|
+
import { hex4_to_u16_swar } from "../../util/swar";
|
|
4
|
+
|
|
5
|
+
// Overflow Pattern for Unicode Escapes (READ)
|
|
6
|
+
// \u0001 0 \u00|01__ + 4
|
|
7
|
+
// -\u0001 2 -\u0|001_ + 6
|
|
8
|
+
// --\u0001 4 --\u|0001 + 8
|
|
9
|
+
// ---\u0001 6 ---\|u0001 + 10
|
|
10
|
+
// Formula: overflow = lane + 4
|
|
11
|
+
|
|
12
|
+
// Overflow Pattern for Unicode Escapes (WRITE)
|
|
13
|
+
// * = escape, _ = empty
|
|
14
|
+
// \u0001 0 *___| - 6
|
|
15
|
+
// -\u0001 2 -*__| - 4
|
|
16
|
+
// --\u0001 4 --*_| - 2
|
|
17
|
+
// ---\u0001 6 ---*| - 0
|
|
18
|
+
// Formula: 6 - lane
|
|
19
|
+
|
|
20
|
+
// Overflow pattern for Short Escapes (READ)
|
|
21
|
+
// \n-- 0 \n--| + 0
|
|
22
|
+
// -\n 2 -\n-| + 0
|
|
23
|
+
// --\n 4 --\n| + 0
|
|
24
|
+
// ---\n 6 ---\|n + 2
|
|
25
|
+
// Formula: overflow = |lane - 4|
|
|
26
|
+
|
|
27
|
+
// Overflow pattern for Short Escapes (WRITE)
|
|
28
|
+
// * = escape, _ = empty
|
|
29
|
+
// \n-- 0 *--_ - 2
|
|
30
|
+
// -\n- 2 -*-_ - 2
|
|
31
|
+
// --\n 4 --*_ - 2
|
|
32
|
+
// ---\n 6 ---* - 0
|
|
33
|
+
// Formula: overflow =
|
|
19
34
|
|
|
20
35
|
/**
|
|
21
36
|
* Deserializes strings back into into their original form using SIMD operations
|
|
@@ -23,106 +38,128 @@ import { DESERIALIZE_ESCAPE_TABLE, ESCAPE_HEX_TABLE } from "../../globals/tables
|
|
|
23
38
|
* @param dst buffer to write to
|
|
24
39
|
* @returns number of bytes written
|
|
25
40
|
*/
|
|
26
|
-
|
|
27
|
-
|
|
41
|
+
export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
|
|
42
|
+
// Strip quotes
|
|
28
43
|
srcStart += 2;
|
|
29
44
|
srcEnd -= 2;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
//
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
// }
|
|
69
|
-
// dst_ptr -= 10;
|
|
70
|
-
// } else {
|
|
71
|
-
// const escaped = load<u8>(DESERIALIZE_ESCAPE_TABLE + code);
|
|
72
|
-
// store<u16>(dst_offset, escaped);
|
|
73
|
-
// memory.copy(dst_offset + 2, src_offset + 4, (4 - lane_index) << 1);
|
|
74
|
-
// // v128.store(dst_offset, v128.load(src_offset, 4), 2);
|
|
75
|
-
// // console.log("Escaped:");
|
|
76
|
-
// if (lane_index == 14) {
|
|
77
|
-
// srcStart += 2;
|
|
78
|
-
// } else {
|
|
79
|
-
// dst_ptr -= 2;
|
|
80
|
-
// }
|
|
81
|
-
// }
|
|
82
|
-
// }
|
|
83
|
-
|
|
84
|
-
// srcStart += 16;
|
|
85
|
-
// dst_ptr += 16;
|
|
86
|
-
|
|
87
|
-
// // console.log("src: " + (srcStart - changetype<usize>(src)).toString());
|
|
88
|
-
// // console.log("dst: " + (dst_ptr - dst).toString());
|
|
89
|
-
// }
|
|
90
|
-
while (srcStart < srcEnd) {
|
|
91
|
-
let code = load<u16>(srcStart);
|
|
92
|
-
if (code == BACK_SLASH) {
|
|
93
|
-
code = load<u16>(DESERIALIZE_ESCAPE_TABLE + load<u8>(srcStart, 2));
|
|
94
|
-
if (code == 117 && load<u32>(srcStart, 4) == 3145776) {
|
|
95
|
-
const block = load<u32>(srcStart, 8);
|
|
96
|
-
const codeA = block & 0xffff;
|
|
97
|
-
const codeB = (block >> 16) & 0xffff;
|
|
98
|
-
const escapedA = load<u8>(ESCAPE_HEX_TABLE + codeA);
|
|
99
|
-
const escapedB = load<u8>(ESCAPE_HEX_TABLE + codeB);
|
|
100
|
-
const escaped = (escapedA << 4) + escapedB;
|
|
101
|
-
store<u16>(bs.offset, escaped);
|
|
102
|
-
bs.offset += 2;
|
|
103
|
-
srcStart += 12;
|
|
104
|
-
} else {
|
|
105
|
-
store<u16>(bs.offset, code);
|
|
106
|
-
bs.offset += 2;
|
|
107
|
-
srcStart += 4;
|
|
45
|
+
const srcEnd8 = srcEnd - 8;
|
|
46
|
+
bs.ensureSize(u32(srcEnd - srcStart));
|
|
47
|
+
|
|
48
|
+
while (srcStart < srcEnd8) {
|
|
49
|
+
const block = load<u64>(srcStart);
|
|
50
|
+
store<u64>(bs.offset, block);
|
|
51
|
+
let mask = backslash_mask_unsafe(block);
|
|
52
|
+
|
|
53
|
+
// Early exit
|
|
54
|
+
if (mask === 0) {
|
|
55
|
+
srcStart += 8;
|
|
56
|
+
bs.offset += 8;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
do {
|
|
61
|
+
const laneIdx = usize(ctz(mask) >> 3); // 0 2 4 6
|
|
62
|
+
mask &= mask - 1;
|
|
63
|
+
const srcIdx = srcStart + laneIdx;
|
|
64
|
+
const dstIdx = bs.offset + laneIdx;
|
|
65
|
+
const header = load<u32>(srcIdx);
|
|
66
|
+
const code = <u16>(header >> 16);
|
|
67
|
+
|
|
68
|
+
// Detect false positive (code unit where low byte is 0x5C)
|
|
69
|
+
if ((header & 0xFFFF) !== 0x5C) continue;
|
|
70
|
+
|
|
71
|
+
// Hot path (negative bias)
|
|
72
|
+
if (code !== 0x75) {
|
|
73
|
+
// Short escapes (\n \t \" \\)
|
|
74
|
+
const escaped = load<u16>(DESERIALIZE_ESCAPE_TABLE + code);
|
|
75
|
+
mask &= mask - usize(escaped === 0x5C);
|
|
76
|
+
store<u16>(dstIdx, escaped);
|
|
77
|
+
store<u32>(dstIdx, load<u32>(srcIdx, 4), 2);
|
|
78
|
+
|
|
79
|
+
const l6 = usize(laneIdx === 6);
|
|
80
|
+
bs.offset -= (1 - l6) << 1;
|
|
81
|
+
srcStart += l6 << 1;
|
|
82
|
+
continue;
|
|
108
83
|
}
|
|
109
|
-
|
|
110
|
-
|
|
84
|
+
|
|
85
|
+
// Unicode escape (\uXXXX)
|
|
86
|
+
const block = load<u64>(srcIdx, 4); // XXXX
|
|
87
|
+
const escaped = hex4_to_u16_swar(block);
|
|
88
|
+
store<u16>(dstIdx, escaped);
|
|
89
|
+
// store<u64>(dstIdx, load<u32>(srcIdx, 12), 2);
|
|
90
|
+
srcStart += 4 + laneIdx;
|
|
91
|
+
bs.offset -= 6 - laneIdx;
|
|
92
|
+
|
|
93
|
+
} while (mask !== 0);
|
|
94
|
+
|
|
95
|
+
bs.offset += 8;
|
|
96
|
+
srcStart += 8;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
while (srcStart < srcEnd) {
|
|
100
|
+
const block = load<u16>(srcStart);
|
|
101
|
+
store<u16>(bs.offset, block);
|
|
102
|
+
srcStart += 2;
|
|
103
|
+
|
|
104
|
+
// Early exit
|
|
105
|
+
if (block !== 0x5C) {
|
|
111
106
|
bs.offset += 2;
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const code = load<u16>(srcStart);
|
|
111
|
+
if (code !== 0x75) {
|
|
112
|
+
// Short escapes (\n \t \" \\)
|
|
113
|
+
const block = load<u16>(srcStart);
|
|
114
|
+
const escape = load<u16>(DESERIALIZE_ESCAPE_TABLE + block);
|
|
115
|
+
store<u16>(bs.offset, escape);
|
|
112
116
|
srcStart += 2;
|
|
117
|
+
} else {
|
|
118
|
+
// Unicode escape (\uXXXX)
|
|
119
|
+
const block = load<u64>(srcStart, 2); // XXXX
|
|
120
|
+
const escaped = hex4_to_u16_swar(block);
|
|
121
|
+
store<u16>(bs.offset, escaped);
|
|
122
|
+
srcStart += 10;
|
|
113
123
|
}
|
|
124
|
+
|
|
125
|
+
bs.offset += 2;
|
|
114
126
|
}
|
|
127
|
+
return bs.out<string>();
|
|
115
128
|
}
|
|
116
129
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
130
|
+
/**
|
|
131
|
+
* Computes a per-lane mask identifying UTF-16 code units whose **low byte**
|
|
132
|
+
* is the ASCII backslash (`'\\'`, 0x5C).
|
|
133
|
+
*
|
|
134
|
+
* The mask is produced in two stages:
|
|
135
|
+
* 1. Detects bytes equal to 0x5C using a SWAR equality test.
|
|
136
|
+
* 2. Clears matches where 0x5C appears in the **high byte** of a UTF-16 code unit,
|
|
137
|
+
* ensuring only valid low-byte backslashes are reported.
|
|
138
|
+
*
|
|
139
|
+
* Each matching lane sets itself to 0x80.
|
|
140
|
+
*/
|
|
141
|
+
// @ts-ignore: decorator
|
|
142
|
+
@inline function backslash_mask(block: u64): u64 {
|
|
143
|
+
const b = block ^ 0x005C_005C_005C_005C;
|
|
144
|
+
const backslash_mask = (b - 0x0001_0001_0001_0001) & ~b & 0x0080_0080_0080_0080;
|
|
145
|
+
const high_byte_mask =
|
|
146
|
+
~(((block - 0x0100_0100_0100_0100) & ~block & 0x8000_8000_8000_8000)
|
|
147
|
+
^ 0x8000_8000_8000_8000) >> 8;
|
|
148
|
+
return backslash_mask & high_byte_mask;
|
|
122
149
|
}
|
|
123
150
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
151
|
+
/**
|
|
152
|
+
* Computes a per-lane mask identifying UTF-16 code units whose **low byte**
|
|
153
|
+
* is the ASCII backslash (`'\\'`, 0x5C).
|
|
154
|
+
*
|
|
155
|
+
* Each matching lane sets itself to 0x80.
|
|
156
|
+
*
|
|
157
|
+
* WARNING: The low byte of a code unit *may* be a backslash, thus triggering false positives!
|
|
158
|
+
* This is useful for a hot path where it is possible to detect the false positive scalarly.
|
|
159
|
+
*/
|
|
160
|
+
// @ts-ignore: decorator
|
|
161
|
+
@inline function backslash_mask_unsafe(block: u64): u64 {
|
|
162
|
+
const b = block ^ 0x005C_005C_005C_005C;
|
|
163
|
+
const backslash_mask = (b - 0x0001_0001_0001_0001) & ~b & 0x0080_0080_0080_0080;
|
|
164
|
+
return backslash_mask;
|
|
165
|
+
}
|
|
@@ -51,7 +51,7 @@ export const SERIALIZE_ESCAPE_TABLE = memory.data<u16>([
|
|
|
51
51
|
0, 0, 0, 0, 92, 0, 0, 0, // 88-95
|
|
52
52
|
0, 0, 8, 0, 0, 0, 12, 0, // 96-103
|
|
53
53
|
0, 0, 0, 0, 0, 0, 10, 0, // 104-111
|
|
54
|
-
0, 0, 13, 0, 9,
|
|
54
|
+
0, 0, 13, 0, 9, 0, 0, 0, // 112-119
|
|
55
55
|
0, 0, 0, 0, 0, 0, 0, 0, // 120-127
|
|
56
56
|
0, 0, 0, 0, 0, 0, 0, 0, // 128-135
|
|
57
57
|
0, 0, 0, 0, 0, 0, 0, 0, // 136-143
|
package/assembly/index.ts
CHANGED
|
@@ -11,7 +11,6 @@ import { deserializeFloat } from "./deserialize/simple/float";
|
|
|
11
11
|
import { deserializeMap } from "./deserialize/simple/map";
|
|
12
12
|
import { deserializeDate } from "./deserialize/simple/date";
|
|
13
13
|
import { deserializeInteger } from "./deserialize/simple/integer";
|
|
14
|
-
// import { deserializeString } from "./deserialize/simple/string";
|
|
15
14
|
import { serializeArbitrary } from "./serialize/simple/arbitrary";
|
|
16
15
|
|
|
17
16
|
import { NULL_WORD, QUOTE } from "./custom/chars";
|
|
@@ -32,6 +31,7 @@ import { serializeString_SWAR } from "./serialize/swar/string";
|
|
|
32
31
|
import { deserializeString_SWAR } from "./deserialize/swar/string";
|
|
33
32
|
import { deserializeString } from "./deserialize/simple/string";
|
|
34
33
|
import { serializeString } from "./serialize/simple/string";
|
|
34
|
+
import { deserializeString_SIMD } from "./deserialize/simd/string";
|
|
35
35
|
// import { deserializeString_SIMD } from "./deserialize/simd/string";
|
|
36
36
|
/**
|
|
37
37
|
* Offset of the 'storage' property in the JSON.Value class.
|
|
@@ -173,14 +173,16 @@ export namespace JSON {
|
|
|
173
173
|
// @ts-ignore
|
|
174
174
|
return null;
|
|
175
175
|
} else if (isString<T>()) {
|
|
176
|
-
if (
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
176
|
+
if (JSON_MODE === JSONMode.NAIVE) {
|
|
177
|
+
// @ts-ignore: type
|
|
178
|
+
return deserializeString(dataPtr, dataPtr + dataSize);
|
|
179
|
+
} else if (JSON_MODE === JSONMode.SWAR) {
|
|
180
|
+
// @ts-ignore: type
|
|
181
|
+
return deserializeString_SWAR(dataPtr, dataPtr + dataSize);
|
|
182
|
+
} else (JSON_MODE === JSONMode.SIMD) {
|
|
183
|
+
// @ts-ignore: type
|
|
184
|
+
return deserializeString_SIMD(dataPtr, dataPtr + dataSize);
|
|
185
|
+
}
|
|
184
186
|
// }
|
|
185
187
|
} else if (isArray<T>()) {
|
|
186
188
|
// @ts-ignore
|
|
@@ -219,35 +221,49 @@ export namespace JSON {
|
|
|
219
221
|
}
|
|
220
222
|
}
|
|
221
223
|
|
|
224
|
+
export type Types = u16;
|
|
222
225
|
/**
|
|
223
226
|
* Enum representing the different types supported by JSON.
|
|
224
227
|
*/
|
|
225
|
-
export
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
228
|
+
export namespace Types {
|
|
229
|
+
// Primitives
|
|
230
|
+
// @ts-ignore
|
|
231
|
+
@inline export const Null: u16 = 0;
|
|
232
|
+
// @ts-ignore
|
|
233
|
+
@inline export const Raw: u16 = 1;
|
|
234
|
+
// @ts-ignore
|
|
235
|
+
@inline export const U8: u16 = 2;
|
|
236
|
+
// @ts-ignore
|
|
237
|
+
@inline export const U16: u16 = 3;
|
|
238
|
+
// @ts-ignore
|
|
239
|
+
@inline export const U32: u16 = 4;
|
|
240
|
+
// @ts-ignore
|
|
241
|
+
@inline export const U64: u16 = 5;
|
|
242
|
+
// @ts-ignore
|
|
243
|
+
@inline export const I8: u16 = 6;
|
|
244
|
+
// @ts-ignore
|
|
245
|
+
@inline export const I16: u16 = 7;
|
|
246
|
+
// @ts-ignore
|
|
247
|
+
@inline export const I32: u16 = 8;
|
|
248
|
+
// @ts-ignore
|
|
249
|
+
@inline export const I64: u16 = 9;
|
|
250
|
+
// @ts-ignore
|
|
251
|
+
@inline export const F32: u16 = 10;
|
|
252
|
+
// @ts-ignore
|
|
253
|
+
@inline export const F64: u16 = 11;
|
|
254
|
+
// @ts-ignore
|
|
255
|
+
@inline export const Bool: u16 = 12;
|
|
256
|
+
// Managed
|
|
257
|
+
// @ts-ignore
|
|
258
|
+
@inline export const String: u16 = 13;
|
|
259
|
+
// @ts-ignore
|
|
260
|
+
@inline export const Object: u16 = 14;
|
|
261
|
+
// @ts-ignore
|
|
262
|
+
@inline export const Array: u16 = 15;
|
|
263
|
+
// @ts-ignore
|
|
264
|
+
@inline export const Map: u16 = 16;
|
|
265
|
+
// @ts-ignore
|
|
266
|
+
@inline export const Struct: u16 = 17;
|
|
251
267
|
}
|
|
252
268
|
|
|
253
269
|
export class Raw {
|
|
@@ -272,9 +288,7 @@ export namespace JSON {
|
|
|
272
288
|
@final
|
|
273
289
|
export class Value {
|
|
274
290
|
static METHODS: Map<u32, u32> = new Map<u32, u32>();
|
|
275
|
-
public type:
|
|
276
|
-
|
|
277
|
-
public isNull: bool;
|
|
291
|
+
public type: u16;
|
|
278
292
|
private storage: u64;
|
|
279
293
|
|
|
280
294
|
private constructor() {
|
|
@@ -295,132 +309,73 @@ export namespace JSON {
|
|
|
295
309
|
* @returns An instance of JSON.Value.
|
|
296
310
|
*/
|
|
297
311
|
@inline static from<T>(value: T): JSON.Value {
|
|
298
|
-
if (value instanceof JSON.Value)
|
|
299
|
-
return value;
|
|
300
|
-
}
|
|
312
|
+
if (value instanceof JSON.Value) return value;
|
|
301
313
|
const out = changetype<JSON.Value>(__new(offsetof<JSON.Value>(), idof<JSON.Value>()));
|
|
302
314
|
out.set<T>(value);
|
|
303
315
|
return out;
|
|
304
316
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Gets the type of a given value as a JSON.Types enum.
|
|
320
|
+
* @param value - any
|
|
321
|
+
* @returns JSON.Types
|
|
322
|
+
*/
|
|
323
|
+
@inline getType<T>(value: T): JSON.Types {
|
|
324
|
+
if (isNullable<T>() && changetype<usize>(value) === 0) return JSON.Types.Null;
|
|
325
|
+
if (isBoolean<T>()) return JSON.Types.Bool;
|
|
326
|
+
if (isInteger<T>() && !isSigned<T>() && changetype<usize>(value) == 0 && nameof<T>() == "usize") return JSON.Types.Null;
|
|
327
|
+
if (isString<T>()) return JSON.Types.String;
|
|
328
|
+
if (isArray<T>() && idof<valueof<T>>() == idof<JSON.Value>()) return JSON.Types.Array;
|
|
329
|
+
if (value instanceof JSON.Box) return this.getType(value.value);
|
|
330
|
+
if (value instanceof u8 || value instanceof i8) return JSON.Types.U8;
|
|
331
|
+
if (value instanceof u16 || value instanceof i16) return JSON.Types.U16;
|
|
332
|
+
if (value instanceof u32 || value instanceof i32) return JSON.Types.U32;
|
|
333
|
+
if (value instanceof u64 || value instanceof i64) return JSON.Types.U64;
|
|
334
|
+
if (value instanceof i8) return JSON.Types.I8;
|
|
335
|
+
if (value instanceof i16) return JSON.Types.I16;
|
|
336
|
+
if (value instanceof i32) return JSON.Types.I32;
|
|
337
|
+
if (value instanceof i64) return JSON.Types.I64;
|
|
338
|
+
if (value instanceof f32) return JSON.Types.F32;
|
|
339
|
+
if (value instanceof f64) return JSON.Types.F64;
|
|
340
|
+
if (value instanceof Map) return JSON.Types.Map;
|
|
341
|
+
if (value instanceof JSON.Raw) return JSON.Types.Raw;
|
|
342
|
+
if (value instanceof JSON.Obj) return JSON.Types.Object;
|
|
343
|
+
|
|
344
|
+
// @ts-ignore: supplied by transform
|
|
345
|
+
if (isDefined(value.__SERIALIZE) && isManaged<T>(value)) return u16(idof<T>()) + JSON.Types.Struct;
|
|
346
|
+
return JSON.Types.Null;
|
|
328
347
|
}
|
|
329
348
|
/**
|
|
330
349
|
* Sets the value of the JSON.Value instance.
|
|
331
350
|
* @param value - The value to be set.
|
|
332
351
|
*/
|
|
333
352
|
@inline set<T>(value: T): void {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
store<T>(changetype<usize>(this), value, STORAGE);
|
|
347
|
-
} else if (value instanceof Map) {
|
|
348
|
-
if (idof<T>() !== idof<Map<string, JSON.Value>>()) {
|
|
349
|
-
abort("Maps must be of type Map<string, JSON.Value>!");
|
|
350
|
-
}
|
|
351
|
-
this.type = JSON.Types.StructNull;
|
|
352
|
-
store<T>(changetype<usize>(this), value, STORAGE);
|
|
353
|
-
// @ts-ignore: supplied by transform
|
|
354
|
-
} else if (isDefined(value.__SERIALIZE) && isManaged<T>(value)) {
|
|
355
|
-
this.type = idof<T>() + JSON.Types.StructNull;
|
|
356
|
-
// @ts-ignore
|
|
357
|
-
if (!JSON.Value.METHODS.has(idof<T>())) JSON.Value.METHODS.set(idof<T>(), value.__SERIALIZE.index);
|
|
358
|
-
// @ts-ignore
|
|
359
|
-
store<usize>(changetype<usize>(this), changetype<usize>(value), STORAGE);
|
|
360
|
-
} else if (value instanceof JSON.Obj) {
|
|
361
|
-
this.type = JSON.Types.ObjectNull;
|
|
362
|
-
store<T>(changetype<usize>(this), value, STORAGE);
|
|
363
|
-
// @ts-ignore
|
|
364
|
-
} else if (isArray<T>() && idof<valueof<T>>() == idof<JSON.Value>()) {
|
|
365
|
-
// @ts-ignore: T satisfies constraints of any[]
|
|
366
|
-
this.type = JSON.Types.ArrayNull;
|
|
367
|
-
store<T>(changetype<usize>(this), value, STORAGE);
|
|
368
|
-
}
|
|
369
|
-
} else {
|
|
370
|
-
if (value instanceof JSON.Box) {
|
|
371
|
-
return this.set(value.value);
|
|
372
|
-
} else if (isBoolean<T>()) {
|
|
373
|
-
this.type = JSON.Types.Bool;
|
|
374
|
-
store<T>(changetype<usize>(this), value, STORAGE);
|
|
375
|
-
} else if (isInteger<T>() && !isSigned<T>() && changetype<usize>(value) == 0 && nameof<T>() == "usize") {
|
|
376
|
-
this.type = JSON.Types.Null;
|
|
377
|
-
store<usize>(changetype<usize>(this), 0, STORAGE);
|
|
378
|
-
} else if (value instanceof u8 || value instanceof i8) {
|
|
379
|
-
this.type = JSON.Types.U8;
|
|
380
|
-
store<T>(changetype<usize>(this), value, STORAGE);
|
|
381
|
-
} else if (value instanceof u16 || value instanceof i16) {
|
|
382
|
-
this.type = JSON.Types.U16;
|
|
383
|
-
store<T>(changetype<usize>(this), value, STORAGE);
|
|
384
|
-
} else if (value instanceof u32 || value instanceof i32) {
|
|
385
|
-
this.type = JSON.Types.U32;
|
|
386
|
-
store<T>(changetype<usize>(this), value, STORAGE);
|
|
387
|
-
} else if (value instanceof u64 || value instanceof i64) {
|
|
388
|
-
this.type = JSON.Types.U64;
|
|
389
|
-
store<T>(changetype<usize>(this), value, STORAGE);
|
|
390
|
-
} else if (value instanceof f32) {
|
|
391
|
-
this.type = JSON.Types.F32;
|
|
392
|
-
store<T>(changetype<usize>(this), value, STORAGE);
|
|
393
|
-
} else if (value instanceof f64) {
|
|
394
|
-
this.type = JSON.Types.F64;
|
|
395
|
-
store<T>(changetype<usize>(this), value, STORAGE);
|
|
396
|
-
} else if (isString<T>()) {
|
|
397
|
-
this.type = JSON.Types.String;
|
|
398
|
-
store<T>(changetype<usize>(this), value, STORAGE);
|
|
399
|
-
} else if (value instanceof JSON.Raw) {
|
|
400
|
-
this.type = JSON.Types.Raw;
|
|
401
|
-
store<T>(changetype<usize>(this), value, STORAGE);
|
|
402
|
-
} else if (value instanceof Map) {
|
|
403
|
-
if (idof<T>() !== idof<Map<string, JSON.Value>>()) {
|
|
404
|
-
abort("Maps must be of type Map<string, JSON.Value>!");
|
|
405
|
-
}
|
|
406
|
-
this.type = JSON.Types.Struct;
|
|
407
|
-
store<T>(changetype<usize>(this), value, STORAGE);
|
|
408
|
-
// @ts-ignore: supplied by transform
|
|
409
|
-
} else if (isDefined(value.__SERIALIZE) && isManaged<T>(value)) {
|
|
410
|
-
this.type = idof<T>() + JSON.Types.Struct;
|
|
411
|
-
// @ts-ignore
|
|
412
|
-
if (!JSON.Value.METHODS.has(idof<T>())) JSON.Value.METHODS.set(idof<T>(), value.__SERIALIZE.index);
|
|
413
|
-
// @ts-ignore
|
|
414
|
-
store<usize>(changetype<usize>(this), changetype<usize>(value), STORAGE);
|
|
415
|
-
} else if (value instanceof JSON.Obj) {
|
|
416
|
-
this.type = JSON.Types.Object;
|
|
417
|
-
store<T>(changetype<usize>(this), value, STORAGE);
|
|
418
|
-
// @ts-ignore
|
|
419
|
-
} else if (isArray<T>() && idof<valueof<T>>() == idof<JSON.Value>()) {
|
|
420
|
-
// @ts-ignore: T satisfies constraints of any[]
|
|
421
|
-
this.type = JSON.Types.Array;
|
|
422
|
-
store<T>(changetype<usize>(this), value, STORAGE);
|
|
353
|
+
this.type = this.getType<T>(value);
|
|
354
|
+
|
|
355
|
+
if (value instanceof JSON.Box) this.set(value.value);
|
|
356
|
+
else if (isBoolean<T>()) store<T>(changetype<usize>(this), value, STORAGE);
|
|
357
|
+
else if (isInteger<T>() && !isSigned<T>() && changetype<usize>(value) == 0 && nameof<T>() == "usize") store<usize>(changetype<usize>(this), 0, STORAGE);
|
|
358
|
+
else if (isInteger<T>() || isFloat<T>()) store<T>(changetype<usize>(this), value, STORAGE);
|
|
359
|
+
else if (isNullable<T>() && changetype<usize>(value) === 0) store<usize>(changetype<usize>(this), 0, STORAGE);
|
|
360
|
+
else if (isString<T>()) store<T>(changetype<usize>(this), value, STORAGE);
|
|
361
|
+
else if (value instanceof JSON.Raw) store<T>(changetype<usize>(this), value, STORAGE);
|
|
362
|
+
else if (value instanceof Map) {
|
|
363
|
+
if (idof<T>() !== idof<Map<string, JSON.Value>>()) {
|
|
364
|
+
abort("Maps must be of type Map<string, JSON.Value>!");
|
|
423
365
|
}
|
|
366
|
+
store<T>(changetype<usize>(this), value, STORAGE);
|
|
367
|
+
// @ts-ignore: supplied by transform
|
|
368
|
+
} else if (isDefined(value.__SERIALIZE) && isManaged<T>(value)) {
|
|
369
|
+
// @ts-ignore
|
|
370
|
+
if (!JSON.Value.METHODS.has(idof<T>())) JSON.Value.METHODS.set(idof<T>(), value.__SERIALIZE.index);
|
|
371
|
+
// @ts-ignore
|
|
372
|
+
store<usize>(changetype<usize>(this), changetype<usize>(value), STORAGE);
|
|
373
|
+
} else if (value instanceof JSON.Obj) {
|
|
374
|
+
store<T>(changetype<usize>(this), value, STORAGE);
|
|
375
|
+
// @ts-ignore
|
|
376
|
+
} else if (isArray<T>() && idof<valueof<T>>() == idof<JSON.Value>()) {
|
|
377
|
+
// @ts-ignore: T satisfies constraints of any[]
|
|
378
|
+
store<T>(changetype<usize>(this), value, STORAGE);
|
|
424
379
|
}
|
|
425
380
|
}
|
|
426
381
|
|
|
@@ -447,7 +402,7 @@ export namespace JSON {
|
|
|
447
402
|
* @returns The encapsulated value.
|
|
448
403
|
*/
|
|
449
404
|
@inline asBox<T>(): Box<T> | null {
|
|
450
|
-
if (this.
|
|
405
|
+
if (this.type === JSON.Types.Null) return null;
|
|
451
406
|
return changetype<Box<T>>(JSON.Box.fromValue<T>(this));
|
|
452
407
|
}
|
|
453
408
|
|
|
@@ -456,11 +411,6 @@ export namespace JSON {
|
|
|
456
411
|
* @returns The string representation of the JSON.Value.
|
|
457
412
|
*/
|
|
458
413
|
toString(): string {
|
|
459
|
-
if (this.type < JSON.Types.Null) {
|
|
460
|
-
if (this.isNull) return "null";
|
|
461
|
-
else this.type = ~this.type + 1;
|
|
462
|
-
}
|
|
463
|
-
|
|
464
414
|
switch (this.type) {
|
|
465
415
|
case JSON.Types.Null:
|
|
466
416
|
return "null";
|
|
@@ -510,7 +460,6 @@ export namespace JSON {
|
|
|
510
460
|
}
|
|
511
461
|
}
|
|
512
462
|
|
|
513
|
-
|
|
514
463
|
@unsafe private __visit(cookie: u32): void {
|
|
515
464
|
if (this.type >= JSON.Types.String) {
|
|
516
465
|
__visit(load<usize>(changetype<usize>(this), STORAGE), cookie);
|
|
@@ -605,8 +554,8 @@ export namespace JSON {
|
|
|
605
554
|
*/
|
|
606
555
|
@inline static fromValue<T>(value: JSON.Value): Box<T> | null {
|
|
607
556
|
if (!(value instanceof JSON.Value)) throw new Error("value must be of type JSON.Value");
|
|
608
|
-
if (value.
|
|
609
|
-
const v = value.type === JSON.Types.F64 ?value.get<f64>() : value.get<T>();
|
|
557
|
+
if (value.type === JSON.Types.Null) return null;
|
|
558
|
+
const v = value.type === JSON.Types.F64 ? value.get<f64>() : value.get<T>();
|
|
610
559
|
// @ts-ignore
|
|
611
560
|
return new Box(isInteger<T>() || isFloat<T>() ? <T>(v) : v);
|
|
612
561
|
}
|
|
@@ -713,7 +662,7 @@ export namespace JSON {
|
|
|
713
662
|
if (srcEnd - srcStart < 4) throw new Error("Cannot parse data as string because it was formatted incorrectly!");
|
|
714
663
|
|
|
715
664
|
// @ts-ignore: type
|
|
716
|
-
return deserializeString(srcStart, srcEnd
|
|
665
|
+
return deserializeString(srcStart, srcEnd);
|
|
717
666
|
} else if (isNullable<T>() && srcEnd - srcStart == 8 && load<u64>(srcStart) == 30399761348886638) {
|
|
718
667
|
// @ts-ignore
|
|
719
668
|
return null;
|