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.
@@ -1,21 +1,36 @@
1
1
  import { bs } from "../../../lib/as-bs";
2
- import { BACK_SLASH } from "../../custom/chars";
3
- import { DESERIALIZE_ESCAPE_TABLE, ESCAPE_HEX_TABLE } from "../../globals/tables";
4
-
5
- // @ts-ignore: decorator allowed
6
- @lazy const LANE_MASK_HIGH = 0xFF00_FF00_FF00_FF00;
7
- // @ts-ignore: decorator allowed
8
- @lazy const LANE_MASK_LOW = 0x00FF_00FF_00FF_00FF;
9
- // @ts-ignore: decorator allowed
10
- @lazy const UINT64_H8 = 0x8080808080808080;
11
- // @ts-ignore: decorator allowed
12
- @lazy const QUOTE_MASK = 0x0022_0022_0022_0022;
13
- // @ts-ignore: decorator allowed
14
- @lazy const BACKSLASH_MASK = 0x005C_005C_005C_005C;
15
- // @ts-ignore: decorator allowed
16
- @lazy const CONTROL_MASK = 0x0020_0020_0020_0020;
17
- // @ts-ignore: decorator allowed
18
- @lazy const U00_MARKER = 13511005048209500;
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
- // todo: optimize and stuff. it works, its not pretty. ideally, i'd like this to be (nearly) branchless
27
- export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): void {
41
+ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
42
+ // Strip quotes
28
43
  srcStart += 2;
29
44
  srcEnd -= 2;
30
- bs.proposeSize(u32(srcEnd - srcStart));
31
-
32
- // const src_end_15 = srcEnd - 15;
33
- // while (srcStart < src_end_15) {
34
- // const block = load<u64>(srcStart);
35
- // store<u64>(dst_ptr, block);
36
-
37
- // let mask = v64x4_eq(block, BACKSLASH_MASK);
38
-
39
- // while (mask != 0) {
40
- // const lane_index = usize(ctz(mask) >> 3);
41
- // const dst_offset = dst_ptr + lane_index;
42
- // const src_offset = srcStart + lane_index;
43
- // const code = load<u16>(src_offset, 2);
44
-
45
- // mask &= mask - 1;
46
- // if (code == 117 && load<u32>(src_offset, 4) == 3145776) {
47
- // const block = load<u32>(src_offset, 8);
48
- // const codeA = block & 0xffff;
49
- // const codeB = (block >> 16) & 0xffff;
50
- // const escapedA = load<u8>(ESCAPE_HEX_TABLE + codeA);
51
- // const escapedB = load<u8>(ESCAPE_HEX_TABLE + codeB);
52
- // const escaped = (escapedA << 4) + escapedB;
53
- // // console.log("Escaped:");
54
- // // console.log(" a: " + escapedA.toString())
55
- // // console.log(" b: " + escapedB.toString());
56
- // // console.log(" c: " + escaped.toString());
57
- // // console.log(" o: " + (dst_ptr - dst).toString());
58
- // // console.log(" d: " + (dst_offset - dst).toString())
59
- // // console.log(" l: " + (lane_index).toString())
60
- // store<u16>(dst_offset, escaped);
61
- // memory.copy(dst_offset + 2, src_offset + 4, (4 - lane_index) << 1);
62
- // // v128.store(dst_offset, v128.load(src_offset, 4), 2);
63
- // if (lane_index >= 6) {
64
- // const bytes_left = lane_index - 4;
65
- // srcStart += bytes_left;
66
- // dst_ptr += bytes_left;
67
- // // console.log(" e: " + (bytes_left).toString())
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
- } else {
110
- store<u16>(bs.offset, code);
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
- // @ts-ignore: decorators allowed
118
- @inline function v64x4_eq(x: u64, y: u64): u64 {
119
- const xored = (x ^ LANE_MASK_HIGH) ^ y;
120
- const mask = (((xored >> 1) | UINT64_H8) - xored) & UINT64_H8;
121
- return (mask << 1) - (mask >> 7);
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
- // @ts-ignore: decorators allowed
125
- @inline function v64x4_ltu(a: u64, b: u64): u64 {
126
- // Vigna's algorithm - fastest SWAR unsigned less-than
127
- return (((a | UINT64_H8) - (b & ~UINT64_H8)) | (a ^ b)) ^ (a | ~b);
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, 117, 0, 0, // 112-119
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 (dataSize < 4) throw new Error("Cannot parse data as string because it was formatted incorrectly!");
177
- // if (ASC_FEATURE_SIMD) {
178
- // // @ts-ignore
179
- // return changetype<string>(deserializeString_SIMD(dataPtr, dataPtr + dataSize, __new(dataSize - 4, idof<string>())));
180
- // } else {
181
-
182
- // @ts-ignore
183
- return deserializeString(dataPtr, dataPtr + dataSize, 0);
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 enum Types {
226
- StructNull = -12,
227
- ArrayNull = -11,
228
- ObjectNull = -10,
229
- StringNull = -9,
230
- BoolNull = -8,
231
- F64Null = -7,
232
- F32Null = -6,
233
- U64Null = -5,
234
- U32Null = -4,
235
- U16Null = -3,
236
- U8Null = -2,
237
- RawNull = -1, // unused
238
- Null = 0,
239
- Raw = 1,
240
- U8 = 2,
241
- U16 = 3,
242
- U32 = 4,
243
- U64 = 5,
244
- F32 = 6,
245
- F64 = 7,
246
- Bool = 8,
247
- String = 9,
248
- Object = 10,
249
- Array = 11,
250
- Struct = 12,
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: i32;
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
- @inline private setPrimitive<T>(value: T): void {
306
- if (isBoolean(value)) {
307
- this.type = JSON.Types.BoolNull;
308
- store<T>(changetype<usize>(this), value, STORAGE);
309
- } else if (value instanceof u8 || value instanceof i8) {
310
- this.type = JSON.Types.U8Null;
311
- store<T>(changetype<usize>(this), value, STORAGE);
312
- } else if (value instanceof u16 || value instanceof i16) {
313
- this.type = JSON.Types.U16;
314
- store<T>(changetype<usize>(this), value, STORAGE);
315
- } else if (value instanceof u32 || value instanceof i32) {
316
- this.type = JSON.Types.U32Null;
317
- store<T>(changetype<usize>(this), value, STORAGE);
318
- } else if (value instanceof u64 || value instanceof i64) {
319
- this.type = JSON.Types.U64Null;
320
- store<T>(changetype<usize>(this), value, STORAGE);
321
- } else if (value instanceof f32) {
322
- this.type = JSON.Types.F32Null;
323
- store<T>(changetype<usize>(this), value, STORAGE);
324
- } else if (value instanceof f64) {
325
- this.type = JSON.Types.F64Null;
326
- store<T>(changetype<usize>(this), value, STORAGE);
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
- if (isNullable<T>()) {
335
- this.isNull = changetype<usize>(value) === 0;
336
- if (value instanceof JSON.Box) {
337
- return this.setPrimitive(value.value);
338
- } else if (isBoolean<T>()) {
339
- this.type = JSON.Types.BoolNull;
340
- store<T>(changetype<usize>(this), value, STORAGE);
341
- } else if (isString<T>()) {
342
- this.type = JSON.Types.StringNull;
343
- store<T>(changetype<usize>(this), value, STORAGE);
344
- } else if (value instanceof JSON.Raw) {
345
- this.type = JSON.Types.RawNull;
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.isNull) return null;
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.isNull) return null;
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, dst);
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;