json-as 1.1.20 → 1.1.22

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 CHANGED
@@ -1,5 +1,14 @@
1
1
  # Change Log
2
2
 
3
+ ## 2025-09-01 - 1.1.22
4
+
5
+ - fix: Type aliases should work across files [#154](https://github.com/JairusSW/json-as/issues/154)
6
+
7
+ ## 2025-08-14 - 1.1.21
8
+
9
+ - fix: JSON.parse on classes with enums [#155](https://github.com/JairusSW/json-as/issues/155)
10
+ - fix: Resolve memory OOB issue within `serializeFloat` function [#153](https://github.com/JairusSW/json-as/issues/153)
11
+
3
12
  ## 2025-07-14 - 1.1.20
4
13
 
5
14
  - feat: enable SIMD string serialization
package/README.md CHANGED
@@ -1,34 +1,6 @@
1
- <h6 align="center">
2
- <pre>
3
- <span style="font-size: 0.8em;"> ██ ███████ ██████ ███ ██ █████ ███████
4
- ██ ██ ██ ██ ████ ██ ██ ██ ██
5
- ██ ███████ ██ ██ ██ ██ ██ █████ ███████ ███████
6
- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
7
- █████ ███████ ██████ ██ ████ ██ ██ ███████
8
- </span>
9
- AssemblyScript - v1.1.20
10
- </pre>
11
- </h6>
12
-
13
- ## 📝 About
14
-
15
- JSON is the de-facto serialization format of modern web applications, but its serialization and deserialization remain a significant performance bottleneck, especially at scale. Traditional parsing approaches are computationally expensive, adding unnecessary overhead to both clients and servers. This library is designed to mitigate this by leveraging SIMD acceleration and highly optimized transformations.
16
-
17
- ## 📚 Contents
18
-
19
- - [Installation](#-installation)
20
- - [Usage](#-usage)
21
- - [Examples](#-examples)
22
- - [Omitting Fields](#️-omitting-fields)
23
- - [Nullable Primitives](#️-using-nullable-primitives)
24
- - [Unknown or Dynamic Data](#-working-with-unknown-or-dynamic-data)
25
- - [Using Raw JSON Strings](#️-using-raw-json-strings)
26
- - [Using Enums](#️-working-with-enums)
27
- - [Custom Serializers](#️-using-custom-serializers-or-deserializers)
28
- - [Performance](#-performance)
29
- - [Debugging](#-debugging)
30
- - [License](#-license)
31
- - [Contact](#-contact)
1
+ <h1 align="center"><pre> ╦╔═╗╔═╗╔╗╔ ╔═╗╔═╗
2
+ ║╚═╗║ ║║║║══╠═╣╚═╗
3
+ ╚╝╚═╝╚═╝╝╚╝ ╩ ╩╚═╝</pre></h1>
32
4
 
33
5
  ## 💾 Installation
34
6
 
@@ -297,7 +269,7 @@ console.log(JSON.stringify(map));
297
269
 
298
270
  ### 📝 Working with enums
299
271
 
300
- By default, enums arn't supported by `json-as`. However, you can use a workaround:
272
+ By default, enums with values other than `i32` arn't supported by AssemblyScript. However, you can use a workaround:
301
273
 
302
274
  ```typescript
303
275
  namespace Foo {
@@ -406,19 +378,6 @@ These benchmarks compare this library to JavaScript's native `JSON.stringify` an
406
378
  | Medium Object | 494 bytes | 2,395,210 ops/s | 1,381,693 ops/s | 1,183 MB/s | 682.5 MB/s |
407
379
  | Large Object | 3374 bytes | 222,222 ops/s | 117,233 ops/s | 749.7 MB/s | 395.5 MB/s |
408
380
 
409
- **📌 Insights**
410
-
411
- - JSON-AS consistently outperforms JavaScript's native implementation.
412
-
413
- - **Serialization Speed:**
414
-
415
- - JSON-AS achieves speeds up to `2,133 MB/s`, significantly faster than JavaScript's peak of `1,416 MB/s`.
416
- - Large objects see the biggest improvement, with JSON-AS at `2,074 MB/s` vs. JavaScript’s `749.7 MB/s`.
417
-
418
- - **Deserialization Speed:**
419
- - JSON-AS reaches `1,986 MB/s`, while JavaScript caps at `1,592 MB/s`.
420
- - Small and medium objects see the most significant performance boost overall.
421
-
422
381
  ### 📈 Comparison to v0.9.x version
423
382
 
424
383
  **Table 1** - _v1.0.0_
@@ -441,12 +400,45 @@ These benchmarks compare this library to JavaScript's native `JSON.stringify` an
441
400
  | Medium Object | 494 bytes | 522,193 ops/s | 508,582 ops/s | 258.0 MB/s | 251.2 MB/s |
442
401
  | Large Object | 3374 bytes | 51,229 ops/s | 65,585 ops/s | 172.8 MB/s | 221.3 MB/s |
443
402
 
444
- **📌 Insights:**
403
+ ### Running benchmarks locally
404
+
405
+ Benchmarks are run directly on top of v8 for more tailored control
406
+
407
+ 1. Download JSVU off of npm
408
+
409
+ ```bash
410
+ npm install jsvu -g
411
+ ```
412
+
413
+ 2. Modify your dotfiles to add `~/.jsvu/bin` to `PATH`
414
+
415
+ ```bash
416
+ export PATH="${HOME}/.jsvu/bin:${PATH}"
417
+ ```
418
+
419
+ 3. Clone the repository
445
420
 
446
- - Massive performance improvements in JSON-AS `v1.0.0`:
447
- - Serialization is **2-12x faster** (e.g., Large Object: `2,074 MB/s` vs. `172.8 MB/s`).
448
- - Deserialization is **2-3x faster** (e.g., Large Object: `1,348 MB/s` vs. `221.3 MB/s`).
449
- - Vector3 Object serialization improved from `416 MB/s` to `1,357 MB/s`--a **3x benefit** through new code generation techniques.
421
+ ```bash
422
+ git clone https://github.com/JairusSW/json-as
423
+ ```
424
+
425
+ 4. Install dependencies
426
+
427
+ ```bash
428
+ npm i
429
+ ```
430
+
431
+ 5. Run benchmarks for either AssemblyScript or JavaScript
432
+
433
+ ```bash
434
+ ./run-bench.as.sh
435
+ ```
436
+
437
+ or
438
+
439
+ ```bash
440
+ ./run-bench.js.sh
441
+ ```
450
442
 
451
443
  ## 🔭 What's Next
452
444
 
@@ -8,6 +8,22 @@ describe("Should serialize arbitrary types", () => {
8
8
  expect(JSON.stringify(JSON.Value.from(true))).toBe("true");
9
9
  expect(JSON.stringify(JSON.Value.from(new Vec3()))).toBe('{"x":1.0,"y":2.0,"z":3.0}');
10
10
  expect(JSON.stringify([JSON.Value.from("string"), JSON.Value.from(true), JSON.Value.from(3.14), JSON.Value.from(new Vec3())])).toBe('["string",true,3.14,{"x":1.0,"y":2.0,"z":3.0}]');
11
+
12
+ const o = new JSON.Obj();
13
+ o.set("schema", "http://json-schema.org/draft-07/schema#");
14
+ o.set("additionalProperties", false);
15
+ o.set("properties", new JSON.Obj());
16
+ o.get("properties")!.as<JSON.Obj>().set("duration", new JSON.Obj());
17
+ o.get("properties")!.as<JSON.Obj>().get("duration")!.as<JSON.Obj>().set("default", 10.0);
18
+ o.get("properties")!.as<JSON.Obj>().get("duration")!.as<JSON.Obj>().set("description", "Duration of the operation in seconds");
19
+ o.get("properties")!.as<JSON.Obj>().get("duration")!.as<JSON.Obj>().set("type", "number");
20
+ o.get("properties")!.as<JSON.Obj>().set("steps", new JSON.Obj());
21
+ o.get("properties")!.as<JSON.Obj>().get("steps")!.as<JSON.Obj>().set("default", 5.0);
22
+ o.get("properties")!.as<JSON.Obj>().get("steps")!.as<JSON.Obj>().set("description", "Number of steps in the operation");
23
+ o.get("properties")!.as<JSON.Obj>().get("steps")!.as<JSON.Obj>().set("type", "number");
24
+ o.set("type", "object");
25
+
26
+ expect(o.toString()).toBe('{"schema":"http://json-schema.org/draft-07/schema#","additionalProperties":false,"properties":{"duration":{"default":10.0,"description":"Duration of the operation in seconds","type":"number"},"steps":{"default":5.0,"description":"Number of steps in the operation","type":"number"}},"type":"object"}');
11
27
  });
12
28
 
13
29
  describe("Should deserialize arbitrary types", () => {
@@ -0,0 +1,35 @@
1
+ import { JSON } from "..";
2
+ import { describe, expect } from "./lib";
3
+
4
+ enum Enum1 {
5
+ Zero = 0,
6
+ One = 1,
7
+ Two = 2,
8
+ Three = 3,
9
+ }
10
+
11
+
12
+ @json
13
+ class DataWithEnum {
14
+ v: Enum1 = Enum1.One;
15
+ constructor(v: Enum1) {
16
+ this.v = v;
17
+ }
18
+ }
19
+
20
+ describe("Should serialize enums", () => {
21
+ expect(JSON.stringify<Enum1>(Enum1.One)).toBe("1");
22
+ expect(JSON.stringify<Enum1>(Enum1.Zero)).toBe("0");
23
+ expect(JSON.stringify<DataWithEnum>(new DataWithEnum(Enum1.Two))).toBe('{"v":2}');
24
+ });
25
+
26
+ describe("Should deserialize enums", () => {
27
+ const date1 = JSON.parse<Enum1>("2");
28
+ expect(date1).toBe(Enum1.Two);
29
+
30
+ const date2 = JSON.parse<Enum1>("0");
31
+ expect(date2).toBe(Enum1.Zero);
32
+
33
+ const date3 = JSON.parse<DataWithEnum>('{"v":3}');
34
+ expect(date3.v).toBe(Enum1.Three);
35
+ });
@@ -10,14 +10,13 @@ import { DESERIALIZE_ESCAPE_TABLE, ESCAPE_HEX_TABLE } from "../../globals/tables
10
10
  // todo: optimize and stuff. it works, its not pretty. ideally, i'd like this to be (nearly) branchless
11
11
  export function deserializeString_SIMD(srcStart: usize, srcEnd: usize, dst: usize): usize {
12
12
  const SPLAT_92 = i16x8.splat(92); /* \ */
13
- let src_ptr = srcStart + 2;
13
+ srcStart += 2;
14
+ srcEnd -= 2;
14
15
  let dst_ptr = changetype<usize>(dst);
16
+ const src_end_15 = srcEnd - 15;
15
17
 
16
- const src_end = srcEnd - 2;
17
- const src_end_15 = src_end - 15;
18
-
19
- while (src_ptr < src_end_15) {
20
- const block = v128.load(src_ptr);
18
+ while (srcStart < src_end_15) {
19
+ const block = v128.load(srcStart);
21
20
  v128.store(dst_ptr, block);
22
21
 
23
22
  const backslash_indices = i16x8.eq(block, SPLAT_92);
@@ -26,7 +25,7 @@ export function deserializeString_SIMD(srcStart: usize, srcEnd: usize, dst: usiz
26
25
  while (mask != 0) {
27
26
  const lane_index = ctz(mask) << 1;
28
27
  const dst_offset = dst_ptr + lane_index;
29
- const src_offset = src_ptr + lane_index;
28
+ const src_offset = srcStart + lane_index;
30
29
  const code = load<u16>(src_offset, 2);
31
30
 
32
31
  mask &= mask - 1;
@@ -48,7 +47,7 @@ export function deserializeString_SIMD(srcStart: usize, srcEnd: usize, dst: usiz
48
47
  v128.store(dst_offset, v128.load(src_offset, 4), 2);
49
48
  if (lane_index >= 6) {
50
49
  const bytes_left = lane_index - 4;
51
- src_ptr += bytes_left;
50
+ srcStart += bytes_left;
52
51
  dst_ptr += bytes_left;
53
52
  // console.log(" e: " + (bytes_left).toString())
54
53
  }
@@ -59,25 +58,25 @@ export function deserializeString_SIMD(srcStart: usize, srcEnd: usize, dst: usiz
59
58
  v128.store(dst_offset, v128.load(src_offset, 4), 2);
60
59
  // console.log("Escaped:");
61
60
  if (lane_index == 14) {
62
- src_ptr += 2;
61
+ srcStart += 2;
63
62
  } else {
64
63
  dst_ptr -= 2;
65
64
  }
66
65
  }
67
66
  }
68
67
 
69
- src_ptr += 16;
68
+ srcStart += 16;
70
69
  dst_ptr += 16;
71
70
 
72
- // console.log("src: " + (src_ptr - changetype<usize>(src)).toString());
71
+ // console.log("src: " + (srcStart - changetype<usize>(src)).toString());
73
72
  // console.log("dst: " + (dst_ptr - dst).toString());
74
73
  }
75
- while (src_ptr < src_end) {
76
- let code = load<u16>(src_ptr);
74
+ while (srcStart < srcEnd) {
75
+ let code = load<u16>(srcStart);
77
76
  if (code == BACK_SLASH) {
78
- code = load<u16>(DESERIALIZE_ESCAPE_TABLE + load<u8>(src_ptr, 2));
79
- if (code == 117 && load<u32>(src_ptr, 4) == 3145776) {
80
- const block = load<u32>(src_ptr, 8);
77
+ code = load<u16>(DESERIALIZE_ESCAPE_TABLE + load<u8>(srcStart, 2));
78
+ if (code == 117 && load<u32>(srcStart, 4) == 3145776) {
79
+ const block = load<u32>(srcStart, 8);
81
80
  const codeA = block & 0xffff;
82
81
  const codeB = (block >> 16) & 0xffff;
83
82
  const escapedA = load<u8>(ESCAPE_HEX_TABLE + codeA);
@@ -85,16 +84,16 @@ export function deserializeString_SIMD(srcStart: usize, srcEnd: usize, dst: usiz
85
84
  const escaped = (escapedA << 4) + escapedB;
86
85
  store<u16>(dst_ptr, escaped);
87
86
  dst_ptr += 2;
88
- src_ptr += 12;
87
+ srcStart += 12;
89
88
  } else {
90
89
  store<u16>(dst_ptr, code);
91
90
  dst_ptr += 2;
92
- src_ptr += 4;
91
+ srcStart += 4;
93
92
  }
94
93
  } else {
95
94
  store<u16>(dst_ptr, code);
96
95
  dst_ptr += 2;
97
- src_ptr += 2;
96
+ srcStart += 2;
98
97
  }
99
98
  }
100
99
 
@@ -3,6 +3,10 @@ import { BACK_SLASH, COMMA, CHAR_F, BRACE_LEFT, BRACKET_LEFT, CHAR_N, QUOTE, BRA
3
3
  import { isSpace } from "../../util";
4
4
  import { ptrToStr } from "../../util/ptrToStr";
5
5
  import { deserializeArbitrary } from "./arbitrary";
6
+ import { deserializeArray } from "./array";
7
+ import { deserializeBoolean } from "./bool";
8
+ import { deserializeFloat } from "./float";
9
+ import { deserializeString } from "./string";
6
10
 
7
11
  export function deserializeObject(srcStart: usize, srcEnd: usize, dst: usize): JSON.Obj {
8
12
  const out = changetype<JSON.Obj>(dst || changetype<usize>(new JSON.Obj()));
@@ -48,8 +52,8 @@ export function deserializeObject(srcStart: usize, srcEnd: usize, dst: usize): J
48
52
  while (srcStart < srcEnd) {
49
53
  const code = load<u16>(srcStart);
50
54
  if (code == QUOTE && load<u16>(srcStart - 2) !== BACK_SLASH) {
51
- // console.log("Value (string): " + ptrToStr(lastIndex, srcStart + 2));
52
- out.set(ptrToStr(keyStart, keyEnd), deserializeArbitrary(lastIndex, srcStart + 2, dst));
55
+ // console.log("Value (string):-" + deserializeString(lastIndex, srcStart + 2, 0) + "-");
56
+ out.set(ptrToStr(keyStart, keyEnd), deserializeString(lastIndex, srcStart + 2, 0));
53
57
  // while (isSpace(load<u16>(srcStart))) srcStart += 2;
54
58
  srcStart += 4;
55
59
  // console.log("Next: " + String.fromCharCode(load<u16>(srcStart)));
@@ -65,7 +69,7 @@ export function deserializeObject(srcStart: usize, srcEnd: usize, dst: usize): J
65
69
  const code = load<u16>(srcStart);
66
70
  if (code == COMMA || code == BRACE_RIGHT || isSpace(code)) {
67
71
  // console.log("Value (number): " + ptrToStr(lastIndex, srcStart));
68
- out.set(ptrToStr(keyStart, keyEnd), deserializeArbitrary(lastIndex, srcStart, dst));
72
+ out.set(ptrToStr(keyStart, keyEnd), deserializeFloat<f64>(lastIndex, srcStart));
69
73
  // while (isSpace(load<u16>((srcStart += 2)))) {
70
74
  // /* empty */
71
75
  // }
@@ -88,7 +92,7 @@ export function deserializeObject(srcStart: usize, srcEnd: usize, dst: usize): J
88
92
  } else if (code == BRACE_RIGHT) {
89
93
  if (--depth == 0) {
90
94
  // console.log("Value (object): " + ptrToStr(lastIndex, srcStart + 2));
91
- out.set(ptrToStr(keyStart, keyEnd), deserializeArbitrary(lastIndex, (srcStart += 2), dst));
95
+ out.set(ptrToStr(keyStart, keyEnd), deserializeObject(lastIndex, (srcStart += 2), 0));
92
96
  // console.log("Next: " + String.fromCharCode(load<u16>(srcStart)));
93
97
  keyStart = 0;
94
98
  // while (isSpace(load<u16>(srcStart))) {
@@ -108,7 +112,7 @@ export function deserializeObject(srcStart: usize, srcEnd: usize, dst: usize): J
108
112
  if (code == BRACKET_RIGHT) {
109
113
  if (--depth == 0) {
110
114
  // console.log("Value (array): " + ptrToStr(lastIndex, srcStart + 2));
111
- out.set(ptrToStr(keyStart, keyEnd), deserializeArbitrary(lastIndex, (srcStart += 2), dst));
115
+ out.set(ptrToStr(keyStart, keyEnd), deserializeArray<JSON.Value[]>(lastIndex, (srcStart += 2), 0));
112
116
  // console.log("Next: " + String.fromCharCode(load<u16>(srcStart)));
113
117
  keyStart = 0;
114
118
  // while (isSpace(load<u16>((srcStart += 2)))) {
@@ -122,7 +126,8 @@ export function deserializeObject(srcStart: usize, srcEnd: usize, dst: usize): J
122
126
  } else if (code == CHAR_T) {
123
127
  if (load<u64>(srcStart) == 28429475166421108) {
124
128
  // console.log("Value (bool): " + ptrToStr(srcStart, srcStart + 8));
125
- out.set(ptrToStr(keyStart, keyEnd), deserializeArbitrary(srcStart, (srcStart += 8), dst));
129
+ out.set(ptrToStr(keyStart, keyEnd), true);
130
+ srcStart += 8;
126
131
  // while (isSpace(load<u16>((srcStart += 2)))) {
127
132
  // /* empty */
128
133
  // }
@@ -133,7 +138,8 @@ export function deserializeObject(srcStart: usize, srcEnd: usize, dst: usize): J
133
138
  } else if (code == CHAR_F) {
134
139
  if (load<u64>(srcStart, 2) == 28429466576093281) {
135
140
  // console.log("Value (bool): " + ptrToStr(srcStart, srcStart + 10));
136
- out.set(ptrToStr(keyStart, keyEnd), deserializeArbitrary(srcStart, (srcStart += 10), dst));
141
+ out.set(ptrToStr(keyStart, keyEnd), false);
142
+ srcStart += 10;
137
143
  // while (isSpace(load<u16>((srcStart += 2)))) {
138
144
  // /* empty */
139
145
  // }
@@ -144,7 +150,8 @@ export function deserializeObject(srcStart: usize, srcEnd: usize, dst: usize): J
144
150
  } else if (code == CHAR_N) {
145
151
  if (load<u64>(srcStart) == 30399761348886638) {
146
152
  // console.log("Value (null): " + ptrToStr(srcStart, srcStart + 8));
147
- out.set(ptrToStr(keyStart, keyEnd), deserializeArbitrary(srcStart, (srcStart += 8), dst));
153
+ out.set(ptrToStr(keyStart, keyEnd), JSON.Value.from<usize>(0));
154
+ srcStart += 8;
148
155
  // while (isSpace(load<u16>((srcStart += 2)))) {
149
156
  /* empty */
150
157
  // }
package/assembly/index.ts CHANGED
@@ -260,6 +260,8 @@ export namespace JSON {
260
260
  }
261
261
  }
262
262
 
263
+
264
+ @final
263
265
  export class Value {
264
266
  static METHODS: Map<u32, u32> = new Map<u32, u32>();
265
267
  public type: i32;
@@ -334,7 +336,7 @@ export namespace JSON {
334
336
  this.type = JSON.Types.Struct;
335
337
  store<T>(changetype<usize>(this), value, STORAGE);
336
338
  // @ts-ignore: supplied by transform
337
- } else if (isDefined(value.__SERIALIZE)) {
339
+ } else if (isDefined(value.__SERIALIZE) && isManaged<T>(value)) {
338
340
  this.type = idof<T>() + JSON.Types.Struct;
339
341
  // @ts-ignore
340
342
  if (!JSON.Value.METHODS.has(idof<T>())) JSON.Value.METHODS.set(idof<T>(), value.__SERIALIZE.index);
@@ -419,16 +421,20 @@ export namespace JSON {
419
421
  }
420
422
  }
421
423
  }
424
+
425
+
426
+ @unsafe private __visit(cookie: u32): void {
427
+ if (this.type >= JSON.Types.String) {
428
+ __visit(load<usize>(changetype<usize>(this), STORAGE), cookie);
429
+ }
430
+ }
422
431
  }
423
432
 
424
433
  export class Obj {
425
- // When accessing stackSize, subtract 2
426
- // @ts-ignore: type
427
- private stackSize: u32 = 6;
428
434
  // @ts-ignore: type
429
- private storage: Map<string, JSON.Value> = new Map<string, JSON.Value>();
435
+ storage: Map<string, JSON.Value> = new Map<string, JSON.Value>();
430
436
 
431
- constructor() { }
437
+ constructor() {}
432
438
 
433
439
  // @ts-ignore: decorator
434
440
  @inline get size(): i32 {
@@ -437,7 +443,7 @@ export namespace JSON {
437
443
 
438
444
  // @ts-ignore: decorator
439
445
  @inline set<T>(key: string, value: T): void {
440
- if (!this.storage.has(key)) this.stackSize += bytes(key) + 8;
446
+ // if (!this.storage.has(key)) this.stackSize += bytes(key) + 8;
441
447
  this.storage.set(key, JSON.Value.from<T>(value));
442
448
  }
443
449
 
@@ -475,7 +481,7 @@ export namespace JSON {
475
481
  // @ts-ignore: decorator
476
482
  @inline static from<T>(value: T): JSON.Obj {
477
483
  if (value instanceof JSON.Obj) return value;
478
- const out = changetype<JSON.Obj>(__new(offsetof<JSON.Obj>(), idof<JSON.Obj>()));
484
+ const out = new JSON.Obj();
479
485
 
480
486
  if (value instanceof Map) {
481
487
  }
@@ -611,7 +617,7 @@ export namespace JSON {
611
617
  if (isDefined(type.__DESERIALIZE)) {
612
618
  const out = changetype<nonnull<T>>(dst || __new(offsetof<nonnull<T>>(), idof<nonnull<T>>()));
613
619
  // @ts-ignore: Defined by transform
614
- if (isNullable<T>() && isDefined(type.__INITIALIZE)) out.__INITIALIZE();
620
+ if (isDefined(type.__INITIALIZE)) out.__INITIALIZE();
615
621
  // @ts-ignore: Defined by transform
616
622
  return out.__DESERIALIZE(srcStart, srcEnd, out);
617
623
  } else if (type instanceof Map) {
@@ -3,14 +3,13 @@ import { BACK_SLASH } from "../../custom/chars";
3
3
  import { SERIALIZE_ESCAPE_TABLE } from "../../globals/tables";
4
4
  import { bytes } from "../../util";
5
5
 
6
- const U00_MARKER = 13511005048209500;
7
-
8
6
  /**
9
7
  * Serializes strings into their JSON counterparts using SIMD operations
10
8
  * @param srcStart pointer to begin serializing at
11
9
  * @param srcEnd pointer to end serialization at
12
10
  */
13
11
  export function serializeString_SIMD(src: string): void {
12
+ const U00_MARKER = 13511005048209500;
14
13
  const SPLAT_34 = i16x8.splat(34); /* " */
15
14
  const SPLAT_92 = i16x8.splat(92); /* \ */
16
15
 
@@ -21,7 +20,7 @@ export function serializeString_SIMD(src: string): void {
21
20
  const srcEnd = srcStart + srcSize;
22
21
  const srcEnd16 = srcEnd - 16;
23
22
 
24
- bs.proposeSize(srcSize + 40);
23
+ bs.proposeSize(srcSize + 4);
25
24
 
26
25
  store<u8>(changetype<usize>(bs.offset), 34); /* " */
27
26
  bs.offset += 2;
@@ -44,6 +44,7 @@ export function serializeArbitrary(src: JSON.Value): void {
44
44
  const fn = JSON.Value.METHODS.get(src.type - JSON.Types.Struct);
45
45
  const ptr = src.get<usize>();
46
46
  call_indirect<void>(fn, 0, ptr);
47
+ break;
47
48
  }
48
49
  }
49
50
  }
@@ -27,7 +27,7 @@ export function serializeArray<T extends any[]>(src: T): void {
27
27
 
28
28
  const lastBlock = unchecked(src[end]);
29
29
  JSON.__serialize<valueof<T>>(lastBlock);
30
- bs.growSize(2);
30
+ // bs.growSize(2);
31
31
  store<u16>(bs.offset, BRACKET_RIGHT);
32
32
  bs.offset += 2;
33
33
  }
@@ -5,7 +5,7 @@ import { bs } from "../../../lib/as-bs";
5
5
  * @returns void
6
6
  */
7
7
  export function serializeBool(data: bool): void {
8
- if (data == true) {
8
+ if (data === true) {
9
9
  bs.proposeSize(8);
10
10
  store<u64>(bs.offset, 28429475166421108);
11
11
  bs.offset += 8;
@@ -4,5 +4,7 @@ import { dtoa_buffered } from "util/number";
4
4
  // @ts-ignore: inline
5
5
  @inline export function serializeFloat<T extends number>(data: T): void {
6
6
  bs.ensureSize(64);
7
- bs.offset += dtoa_buffered(bs.offset, data) << 1;
7
+ const size = dtoa_buffered(bs.offset, data) << 1;
8
+ bs.stackSize += size;
9
+ bs.offset += size;
8
10
  }
@@ -5,8 +5,8 @@ import { itoa_buffered } from "util/number";
5
5
  @inline export function serializeInteger<T extends number>(data: T): void {
6
6
  bs.ensureSize(sizeof<T>() << 3);
7
7
  const bytesWritten = itoa_buffered(bs.offset, data) << 1;
8
- bs.offset += bytesWritten;
9
8
  bs.growSize(bytesWritten);
9
+ bs.offset += bytesWritten;
10
10
  }
11
11
 
12
12
  // 32 {"x":,"y":,"z"}
@@ -16,7 +16,7 @@ export function serializeMap<T extends Map<any, any>>(src: T): void {
16
16
  let keys = src.keys();
17
17
  let values = src.values();
18
18
 
19
- bs.proposeSize(srcSize << 3); // This needs to be predicted better
19
+ bs.proposeSize(4);
20
20
 
21
21
  store<u16>(bs.offset, BRACE_LEFT);
22
22
  bs.offset += 2;
@@ -37,7 +37,7 @@ export function serializeMap<T extends Map<any, any>>(src: T): void {
37
37
  store<u16>(bs.offset, COLON);
38
38
  bs.offset += 2;
39
39
  JSON.__serialize(unchecked(values[srcEnd]));
40
- bs.growSize(2);
40
+ // bs.growSize(2);
41
41
  store<u16>(bs.offset, BRACE_RIGHT);
42
42
  bs.offset += 2;
43
43
  }
@@ -1,44 +1,46 @@
1
1
  import { bs } from "../../../lib/as-bs";
2
2
  import { JSON } from "../..";
3
- import { BRACE_LEFT, BRACE_RIGHT, QUOTE } from "../../custom/chars";
4
- import { bytes } from "../../util";
3
+ import { BRACE_LEFT, BRACE_RIGHT, COLON, COMMA } from "../../custom/chars";
4
+ import { serializeArbitrary } from "./arbitrary";
5
+ import { serializeString } from "./string";
5
6
 
6
- export function serializeObject(data: JSON.Obj): void {
7
- if (!data.size) {
7
+ export function serializeObject(src: JSON.Obj): void {
8
+ const srcSize = src.size;
9
+ const srcEnd = srcSize - 1;
10
+
11
+ if (srcSize == 0) {
8
12
  bs.proposeSize(4);
9
13
  store<u32>(bs.offset, 8192123);
10
14
  bs.offset += 4;
11
15
  return;
12
16
  }
13
17
 
14
- bs.proposeSize(load<u32>(changetype<usize>(data), offsetof<JSON.Obj>("stackSize")) - 2);
15
- const keys = data.keys();
16
- const values = data.values();
17
-
18
- // console.log(" Keys " + keys.join(" "));
19
- // console.log(" Values " + values.map<string>(v => v.toString()).join(" "))
18
+ const keys = src.keys();
19
+ const values = src.values();
20
20
 
21
+ bs.growSize(2);
21
22
  store<u16>(bs.offset, BRACE_LEFT);
22
23
  bs.offset += 2;
23
24
 
24
- const firstKey = unchecked(keys[0]);
25
- const keySize = bytes(firstKey);
26
- store<u16>(bs.offset, QUOTE);
27
- memory.copy(bs.offset + 2, changetype<usize>(firstKey), keySize);
28
- store<u32>((bs.offset += keySize + 2), 3801122); // ":
29
- bs.offset += 4;
30
- JSON.__serialize(unchecked(values[0]));
31
-
32
- for (let i = 1; i < keys.length; i++) {
33
- const key = unchecked(keys[i]);
34
- const keySize = bytes(key);
35
- store<u32>(bs.offset, 2228268); // ,"
36
- memory.copy(bs.offset + 4, changetype<usize>(key), keySize);
37
- store<u32>((bs.offset += keySize + 4), 3801122); // ":
38
- bs.offset += 4;
39
- JSON.__serialize(unchecked(values[i]));
25
+ for (let i = 0; i < srcEnd; i++) {
26
+ serializeString(unchecked(keys[i]));
27
+ bs.growSize(2);
28
+ store<u16>(bs.offset, COLON);
29
+ bs.offset += 2;
30
+
31
+ serializeArbitrary(unchecked(values[i]));
32
+ bs.growSize(2);
33
+ store<u16>(bs.offset, COMMA);
34
+ bs.offset += 2;
40
35
  }
41
36
 
37
+ serializeString(unchecked(keys[srcEnd]));
38
+ bs.growSize(2);
39
+ store<u16>(bs.offset, COLON);
40
+ bs.offset += 2;
41
+ serializeArbitrary(unchecked(values[srcEnd]));
42
+
43
+ bs.growSize(2);
42
44
  store<u16>(bs.offset, BRACE_RIGHT);
43
45
  bs.offset += 2;
44
46
  }