json-as 1.1.20 → 1.1.21
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 +5 -0
- package/README.md +4 -32
- package/assembly/__tests__/arbitrary.spec.ts +16 -0
- package/assembly/__tests__/enum.spec.ts +35 -0
- package/assembly/deserialize/simd/string.ts +18 -19
- package/assembly/deserialize/simple/object.ts +15 -8
- package/assembly/index.ts +14 -8
- package/assembly/serialize/simd/string.ts +2 -3
- package/assembly/serialize/simple/arbitrary.ts +1 -0
- package/assembly/serialize/simple/array.ts +1 -1
- package/assembly/serialize/simple/bool.ts +1 -1
- package/assembly/serialize/simple/float.ts +3 -1
- package/assembly/serialize/simple/integer.ts +1 -1
- package/assembly/serialize/simple/map.ts +2 -2
- package/assembly/serialize/simple/object.ts +28 -26
- package/assembly/test.tmp.ts +16 -614
- package/assembly/test.ts +2 -0
- package/lib/as-bs.ts +13 -12
- package/package.json +6 -7
- package/run-bench.as.sh +3 -3
- package/run-bench.js.sh +1 -1
- package/run-tests.sh +1 -1
- package/transform/lib/index.js +4 -1
- package/transform/lib/index.js.map +1 -1
- package/transform/lib/types.js +21 -0
- package/transform/lib/types.js.map +1 -1
- package/transform/src/index.ts +5 -1
- package/transform/src/types.ts +35 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 2025-08-14 - 1.1.21
|
|
4
|
+
|
|
5
|
+
- fix: JSON.parse on classes with enums [#155](https://github.com/JairusSW/json-as/issues/155)
|
|
6
|
+
- fix: Resolve memory OOB issue within `serializeFloat` function [#153](https://github.com/JairusSW/json-as/issues/153)
|
|
7
|
+
|
|
3
8
|
## 2025-07-14 - 1.1.20
|
|
4
9
|
|
|
5
10
|
- feat: enable SIMD string serialization
|
package/README.md
CHANGED
|
@@ -1,34 +1,6 @@
|
|
|
1
|
-
<
|
|
2
|
-
|
|
3
|
-
|
|
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
|
|
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 {
|
|
@@ -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
|
-
|
|
13
|
+
srcStart += 2;
|
|
14
|
+
srcEnd -= 2;
|
|
14
15
|
let dst_ptr = changetype<usize>(dst);
|
|
16
|
+
const src_end_15 = srcEnd - 15;
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
61
|
+
srcStart += 2;
|
|
63
62
|
} else {
|
|
64
63
|
dst_ptr -= 2;
|
|
65
64
|
}
|
|
66
65
|
}
|
|
67
66
|
}
|
|
68
67
|
|
|
69
|
-
|
|
68
|
+
srcStart += 16;
|
|
70
69
|
dst_ptr += 16;
|
|
71
70
|
|
|
72
|
-
// console.log("src: " + (
|
|
71
|
+
// console.log("src: " + (srcStart - changetype<usize>(src)).toString());
|
|
73
72
|
// console.log("dst: " + (dst_ptr - dst).toString());
|
|
74
73
|
}
|
|
75
|
-
while (
|
|
76
|
-
let code = load<u16>(
|
|
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>(
|
|
79
|
-
if (code == 117 && load<u32>(
|
|
80
|
-
const block = load<u32>(
|
|
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
|
-
|
|
87
|
+
srcStart += 12;
|
|
89
88
|
} else {
|
|
90
89
|
store<u16>(dst_ptr, code);
|
|
91
90
|
dst_ptr += 2;
|
|
92
|
-
|
|
91
|
+
srcStart += 4;
|
|
93
92
|
}
|
|
94
93
|
} else {
|
|
95
94
|
store<u16>(dst_ptr, code);
|
|
96
95
|
dst_ptr += 2;
|
|
97
|
-
|
|
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)
|
|
52
|
-
out.set(ptrToStr(keyStart, keyEnd),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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
|
-
|
|
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 =
|
|
484
|
+
const out = new JSON.Obj();
|
|
479
485
|
|
|
480
486
|
if (value instanceof Map) {
|
|
481
487
|
}
|
|
@@ -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 +
|
|
23
|
+
bs.proposeSize(srcSize + 4);
|
|
25
24
|
|
|
26
25
|
store<u8>(changetype<usize>(bs.offset), 34); /* " */
|
|
27
26
|
bs.offset += 2;
|
|
@@ -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
|
-
|
|
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(
|
|
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,
|
|
4
|
-
import {
|
|
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(
|
|
7
|
-
|
|
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
|
-
|
|
15
|
-
const
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
}
|