json-as 1.0.0-alpha.3 → 1.0.0-alpha.4
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 +14 -0
- package/README.md +31 -19
- package/assembly/__tests__/box.spec.ts +37 -0
- package/assembly/__tests__/date.spec.ts +38 -0
- package/assembly/deserialize/simple/bool.ts +4 -7
- package/assembly/deserialize/simple/date.ts +2 -2
- package/assembly/deserialize/simple/object.ts +3 -1
- package/assembly/index.ts +31 -8
- package/assembly/serialize/simd/string.ts +11 -11
- package/assembly/serialize/simple/array.ts +4 -3
- package/assembly/serialize/simple/float.ts +1 -1
- package/assembly/serialize/simple/integer.ts +7 -2
- package/assembly/test.ts +58 -4
- package/assembly/util/snp.ts +2 -2
- package/modules/as-bs/assembly/index.ts +61 -30
- package/package.json +5 -5
- package/transform/lib/builder.js +1340 -1262
- package/transform/lib/index.js +582 -512
- package/transform/lib/index.js.map +1 -1
- package/transform/lib/linker.js +12 -10
- package/transform/lib/types.js +19 -19
- package/transform/lib/util.js +34 -34
- package/transform/lib/visitor.js +529 -526
- package/transform/src/index.ts +22 -16
package/CHANGELOG
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 2025-02-13 - 1.0.0-alpha.4
|
|
4
|
+
|
|
5
|
+
- feat: reintroduce support for `Box<T>`-wrapped primitive types
|
|
6
|
+
- tests: add extensive tests to all supported types
|
|
7
|
+
- fix: 6-byte keys being recognized on deserialize
|
|
8
|
+
- perf: take advantage of aligned memory to use a single 64-bit load on 6-byte keys
|
|
9
|
+
- fix: `bs.proposeSize()` should increment `stackSize` by `size` instead of setting it
|
|
10
|
+
- fix: allow runtime to manage `bs.buffer`
|
|
11
|
+
- fix: memory leaks in `bs` module
|
|
12
|
+
- fix: add (possibly temporary) `JSON.Memory.shrink()` to shrink memory in `bs`
|
|
13
|
+
- perf: prefer growing memory by `nextPowerOf2(size + 64)` for less reallocations
|
|
14
|
+
- tests: add boolean tests to `Box<T>`
|
|
15
|
+
- fix: serialization of non-growable data types should grow `bs.stackSize`
|
|
16
|
+
|
|
3
17
|
## 2025-01-31 - 1.0.0-alpha.3
|
|
4
18
|
|
|
5
19
|
- fix: write to proper offset when deserializing string with \u0000-type escapes
|
package/README.md
CHANGED
|
@@ -6,10 +6,21 @@
|
|
|
6
6
|
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
7
7
|
█████ ███████ ██████ ██ ████ ██ ██ ███████
|
|
8
8
|
</span>
|
|
9
|
-
AssemblyScript - v1.0.0-alpha.
|
|
9
|
+
AssemblyScript - v1.0.0-alpha.4
|
|
10
10
|
</pre>
|
|
11
11
|
</h5>
|
|
12
12
|
|
|
13
|
+
## Contents
|
|
14
|
+
- [About](#about)
|
|
15
|
+
- [Installation](#installation)
|
|
16
|
+
- [Usage](#usage)
|
|
17
|
+
- [Examples](#examples)
|
|
18
|
+
- [Performance](#performance)
|
|
19
|
+
- [License](#license)
|
|
20
|
+
- [Contact](#contact)
|
|
21
|
+
|
|
22
|
+
## About
|
|
23
|
+
|
|
13
24
|
## Installation
|
|
14
25
|
|
|
15
26
|
```bash
|
|
@@ -40,7 +51,6 @@ If you'd like to see the code that the transform generates, run with `JSON_DEBUG
|
|
|
40
51
|
```js
|
|
41
52
|
import { JSON } from "json-as";
|
|
42
53
|
|
|
43
|
-
// @json or @serializable work here
|
|
44
54
|
@json
|
|
45
55
|
class Vec3 {
|
|
46
56
|
x: f32 = 0.0;
|
|
@@ -55,8 +65,7 @@ class Player {
|
|
|
55
65
|
lastName!: string;
|
|
56
66
|
lastActive!: i32[];
|
|
57
67
|
// Drop in a code block, function, or expression that evaluates to a boolean
|
|
58
|
-
@omitif((
|
|
59
|
-
@omitif('this.age <= 0')
|
|
68
|
+
@omitif((self: Player) => self.age < 18)
|
|
60
69
|
age!: i32;
|
|
61
70
|
@omitnull()
|
|
62
71
|
pos!: Vec3 | null;
|
|
@@ -64,10 +73,10 @@ class Player {
|
|
|
64
73
|
}
|
|
65
74
|
|
|
66
75
|
const player: Player = {
|
|
67
|
-
firstName: "
|
|
68
|
-
lastName: "
|
|
69
|
-
lastActive: [
|
|
70
|
-
age:
|
|
76
|
+
firstName: "Jairus",
|
|
77
|
+
lastName: "Tanaka",
|
|
78
|
+
lastActive: [2, 7, 2025],
|
|
79
|
+
age: 18,
|
|
71
80
|
pos: {
|
|
72
81
|
x: 3.4,
|
|
73
82
|
y: 1.2,
|
|
@@ -76,11 +85,15 @@ const player: Player = {
|
|
|
76
85
|
isVerified: true
|
|
77
86
|
};
|
|
78
87
|
|
|
79
|
-
const
|
|
88
|
+
const serialized = JSON.stringify<Player>(player);
|
|
89
|
+
const parsed = JSON.parse<Player>(serialized);
|
|
80
90
|
|
|
81
|
-
|
|
91
|
+
console.log("Serialized: " + serialized);
|
|
92
|
+
console.log("Parsed: " + JSON.stringify(parsed));
|
|
82
93
|
```
|
|
83
94
|
|
|
95
|
+
## Examples
|
|
96
|
+
|
|
84
97
|
Classes can even have inheritance. Here's a nasty example
|
|
85
98
|
|
|
86
99
|
```js
|
|
@@ -124,16 +137,15 @@ You can also add it to your `asconfig.json`
|
|
|
124
137
|
|
|
125
138
|
If you use this project in your codebase, consider dropping a [star](https://github.com/JairusSW/as-json). I would really appreciate it!
|
|
126
139
|
|
|
127
|
-
##
|
|
128
|
-
|
|
129
|
-
If you want a feature, drop an issue (and again, maybe a star). I'll likely add it in less than 7 days.
|
|
140
|
+
## 📃 License
|
|
130
141
|
|
|
131
|
-
|
|
142
|
+
This project is distributed under an open source license. You can view the full license using the following link: [License](./LICENSE)
|
|
132
143
|
|
|
133
|
-
|
|
134
|
-
- [GitHub](https://github.com/JairusSW)
|
|
135
|
-
- [Discord](discord.com/users/600700584038760448)
|
|
144
|
+
## 📫 Contact
|
|
136
145
|
|
|
137
|
-
|
|
146
|
+
Please send all issues to [GitHub Issues](https://github.com/JairusSW/as-json/issues) and to converse, please send me an email at [me@jairus.dev](mailto:me@jairus.dev)
|
|
138
147
|
|
|
139
|
-
|
|
148
|
+
- **Email:** Send me inquiries, questions, or requests at [me@jairus.dev](mailto:me@jairus.dev)
|
|
149
|
+
- **GitHub:** Visit the official GitHub repository [Here](https://github.com/JairusSW/as-json)
|
|
150
|
+
- **Website:** Visit my official website at [jairus.dev](https://jairus.dev/)
|
|
151
|
+
- **Discord:** Converse with me on [My Discord](discord.com/users/600700584038760448) or on the [AssemblyScript Discord Server](https://discord.gg/assemblyscript/)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { JSON } from "..";
|
|
2
|
+
import { describe, expect } from "../../modules/test/assembly";
|
|
3
|
+
|
|
4
|
+
describe("Should serialize JSON.Box<T>", () => {
|
|
5
|
+
expect(JSON.stringify<JSON.Box<i32> | null>(null))
|
|
6
|
+
.toBe("null");
|
|
7
|
+
|
|
8
|
+
expect(JSON.stringify<JSON.Box<i32> | null>(new JSON.Box<i32>(0)))
|
|
9
|
+
.toBe("0");
|
|
10
|
+
|
|
11
|
+
expect(JSON.stringify<JSON.Box<i32> | null>(new JSON.Box<i32>(1)))
|
|
12
|
+
.toBe("1");
|
|
13
|
+
|
|
14
|
+
expect(JSON.stringify<JSON.Box<boolean> | null>(new JSON.Box<boolean>(false)))
|
|
15
|
+
.toBe("false");
|
|
16
|
+
|
|
17
|
+
expect(JSON.stringify<JSON.Box<boolean> | null>(new JSON.Box<boolean>(true)))
|
|
18
|
+
.toBe("true");
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// This is somewhat clumsy to use. Perhaps I can redesign it or use some transform to make it more transparent.
|
|
22
|
+
describe("Should deserialize JSON.Box<T>", () => {
|
|
23
|
+
expect((JSON.parse<JSON.Box<i32> | null>("null") == null).toString())
|
|
24
|
+
.toBe("true");
|
|
25
|
+
|
|
26
|
+
expect(JSON.parse<JSON.Box<i32> | null>("0")!.value.toString())
|
|
27
|
+
.toBe("0");
|
|
28
|
+
|
|
29
|
+
expect(JSON.parse<JSON.Box<i32> | null>("1")!.value.toString())
|
|
30
|
+
.toBe("1");
|
|
31
|
+
|
|
32
|
+
expect(JSON.parse<JSON.Box<boolean> | null>("false")!.value.toString())
|
|
33
|
+
.toBe("false");
|
|
34
|
+
|
|
35
|
+
expect(JSON.parse<JSON.Box<boolean> | null>("true")!.value.toString())
|
|
36
|
+
.toBe("true");
|
|
37
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { JSON } from "..";
|
|
2
|
+
import { describe, expect } from "../../modules/test/assembly";
|
|
3
|
+
|
|
4
|
+
describe("Should serialize Date", () => {
|
|
5
|
+
expect(JSON.stringify<Date>(new Date(0)))
|
|
6
|
+
.toBe('"1970-01-01T00:00:00.000Z"');
|
|
7
|
+
expect(JSON.stringify<Date>(new Date(1738618120525)))
|
|
8
|
+
.toBe('"2025-02-03T21:28:40.525Z"');
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
describe("Should deserialize booleans", () => {
|
|
12
|
+
// const date = JSON.parse<Date>('"2025-02-03T21:28:40.525Z"');
|
|
13
|
+
// console.log("Year: " + date.getUTCFullYear().toString());
|
|
14
|
+
// console.log("Month: " + date.getUTCMonth().toString());
|
|
15
|
+
// console.log("Day: " + date.getUTCDay().toString());
|
|
16
|
+
// console.log("Hours: " + date.getUTCHours().toString());
|
|
17
|
+
// console.log("Minutes: " + date.getUTCMinutes().toString());
|
|
18
|
+
// console.log("Seconds: " + date.getUTCSeconds().toString());
|
|
19
|
+
// console.log("Milliseconds: " + date.getUTCMilliseconds().toString());
|
|
20
|
+
|
|
21
|
+
const date1 = JSON.parse<Date>('"1970-01-01T00:00:00.000Z"');
|
|
22
|
+
expect(date1.getUTCFullYear().toString()).toBe("1970");
|
|
23
|
+
expect(date1.getUTCMonth().toString()).toBe("0");
|
|
24
|
+
expect(date1.getUTCDay().toString()).toBe("4");
|
|
25
|
+
expect(date1.getUTCHours().toString()).toBe("0");
|
|
26
|
+
expect(date1.getUTCMinutes().toString()).toBe("0");
|
|
27
|
+
expect(date1.getUTCSeconds().toString()).toBe("0");
|
|
28
|
+
expect(date1.getUTCMilliseconds().toString()).toBe("0");
|
|
29
|
+
|
|
30
|
+
const date2 = JSON.parse<Date>('"2025-02-03T21:28:40.525Z"');
|
|
31
|
+
expect(date2.getUTCFullYear().toString()).toBe("2025");
|
|
32
|
+
expect(date2.getUTCMonth().toString()).toBe("1");
|
|
33
|
+
expect(date2.getUTCDay().toString()).toBe("1");
|
|
34
|
+
expect(date2.getUTCHours().toString()).toBe("21");
|
|
35
|
+
expect(date2.getUTCMinutes().toString()).toBe("28");
|
|
36
|
+
expect(date2.getUTCSeconds().toString()).toBe("40");
|
|
37
|
+
expect(date2.getUTCMilliseconds().toString()).toBe("525");
|
|
38
|
+
});
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import { CHAR_F, CHAR_T } from "../../custom/chars";
|
|
2
|
-
|
|
3
1
|
export function deserializeBoolean(srcStart: usize, srcEnd: usize): boolean {
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
if (
|
|
7
|
-
else if (firstChar == CHAR_F && load<u64>(srcSize, 2) == 28429466576093281) return false;
|
|
2
|
+
const block = load<u64>(srcStart);
|
|
3
|
+
if (block == 28429475166421108) return true;
|
|
4
|
+
else if (block == 32370086184550502 && load<u16>(srcStart, 8) == 101) return false;
|
|
8
5
|
return false; //throw new Error(`Expected to find boolean, but found "${data.slice(0, 100)}" instead!`);
|
|
9
|
-
}
|
|
6
|
+
}
|
|
@@ -2,10 +2,10 @@ import { ptrToStr } from "../../util/ptrToStr";
|
|
|
2
2
|
|
|
3
3
|
export function deserializeDate(srcStart: usize, srcEnd: usize): Date {
|
|
4
4
|
// Use AssemblyScript's date parser
|
|
5
|
-
const d = Date.fromString(ptrToStr(srcStart, srcEnd));
|
|
5
|
+
const d = Date.fromString(ptrToStr(srcStart + 2, srcEnd - 2));
|
|
6
6
|
|
|
7
7
|
// Return a new object instead of the one that the parser returned.
|
|
8
|
-
// This may seem redundant, but
|
|
8
|
+
// This may seem redundant, but it addresses the issue when Date
|
|
9
9
|
// is globally aliased to wasi_Date (or some other superclass).
|
|
10
10
|
return new Date(d.getTime());
|
|
11
11
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { JSON } from "../..";
|
|
1
2
|
import { BACK_SLASH, COMMA, CHAR_F, BRACE_LEFT, BRACKET_LEFT, CHAR_N, QUOTE, BRACE_RIGHT, BRACKET_RIGHT, CHAR_T } from "../../custom/chars";
|
|
2
3
|
import { isSpace } from "../../util";
|
|
4
|
+
import { ptrToStr } from "../../util/ptrToStr";
|
|
3
5
|
|
|
4
6
|
export function deserializeObject<T>(srcStart: usize, srcEnd: usize, dst: usize): T {
|
|
5
7
|
const out = changetype<nonnull<T>>(dst || __new(offsetof<T>(), idof<T>()));
|
|
@@ -60,9 +62,9 @@ export function deserializeObject<T>(srcStart: usize, srcEnd: usize, dst: usize)
|
|
|
60
62
|
while (srcStart < srcEnd) {
|
|
61
63
|
const code = load<u16>(srcStart);
|
|
62
64
|
if (code == COMMA || code == BRACE_RIGHT || isSpace(code)) {
|
|
65
|
+
// console.log("Value (number): " + ptrToStr(lastIndex, srcStart));
|
|
63
66
|
// @ts-ignore: exists
|
|
64
67
|
out.__DESERIALIZE(keyStart, keyEnd, lastIndex, srcStart, dst);
|
|
65
|
-
// console.log("Value (number): " + ptrToStr(lastIndex, srcStart));
|
|
66
68
|
// while (isSpace(load<u16>((srcStart += 2)))) {
|
|
67
69
|
// /* empty */
|
|
68
70
|
// }
|
package/assembly/index.ts
CHANGED
|
@@ -36,6 +36,11 @@ export type Raw = string;
|
|
|
36
36
|
* JSON Encoder/Decoder for AssemblyScript
|
|
37
37
|
*/
|
|
38
38
|
export namespace JSON {
|
|
39
|
+
export namespace Memory {
|
|
40
|
+
export function shrink(): void {
|
|
41
|
+
bs.resize(64);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
39
44
|
/**
|
|
40
45
|
* Serializes valid JSON data
|
|
41
46
|
* ```js
|
|
@@ -107,9 +112,7 @@ export namespace JSON {
|
|
|
107
112
|
serializeString(changetype<string>(data));
|
|
108
113
|
return bs.out<string>();
|
|
109
114
|
// @ts-ignore: Supplied by transform
|
|
110
|
-
} else if (isDefined(data.__SERIALIZE)
|
|
111
|
-
// @ts-ignore
|
|
112
|
-
// data.__ALLOCATE();
|
|
115
|
+
} else if (isDefined(data.__SERIALIZE)) {
|
|
113
116
|
// @ts-ignore
|
|
114
117
|
data.__SERIALIZE(changetype<usize>(data));
|
|
115
118
|
return bs.out<string>();
|
|
@@ -119,8 +122,8 @@ export namespace JSON {
|
|
|
119
122
|
|
|
120
123
|
store<u16>(changetype<usize>(out), QUOTE);
|
|
121
124
|
memory.copy(changetype<usize>(out) + 2, changetype<usize>(data.toISOString()), 48);
|
|
122
|
-
store<u16>(changetype<usize>(out), 50);
|
|
123
|
-
return out;
|
|
125
|
+
store<u16>(changetype<usize>(out), QUOTE, 50);
|
|
126
|
+
return changetype<string>(out);
|
|
124
127
|
} else if (data instanceof Array) {
|
|
125
128
|
// @ts-ignore
|
|
126
129
|
serializeArray(changetype<nonnull<T>>(data));
|
|
@@ -156,7 +159,7 @@ export namespace JSON {
|
|
|
156
159
|
return deserializeInteger<T>(dataPtr, dataPtr + dataSize);
|
|
157
160
|
} else if (isFloat<T>()) {
|
|
158
161
|
return deserializeFloat<T>(dataPtr, dataPtr + dataSize);
|
|
159
|
-
} else if (isNullable<T>() &&
|
|
162
|
+
} else if (isNullable<T>() && dataSize == 8 && load<u64>(dataPtr) == 30399761348886638) {
|
|
160
163
|
// @ts-ignore
|
|
161
164
|
return null;
|
|
162
165
|
} else if (isString<T>()) {
|
|
@@ -182,7 +185,7 @@ export namespace JSON {
|
|
|
182
185
|
return deserializeDate(dataPtr, dataPtr + dataSize);
|
|
183
186
|
} else if (type instanceof JSON.Box) {
|
|
184
187
|
// @ts-ignore
|
|
185
|
-
return new JSON.Box(
|
|
188
|
+
return new JSON.Box(parseBox(data, changetype<nonnull<T>>(0).value));
|
|
186
189
|
} else {
|
|
187
190
|
throw new Error(`Could not deserialize data ${data} to type ${nameof<T>()}. Make sure to add the correct decorators to classes.`);
|
|
188
191
|
}
|
|
@@ -339,7 +342,9 @@ export namespace JSON {
|
|
|
339
342
|
* Box for primitive types
|
|
340
343
|
*/
|
|
341
344
|
export class Box<T> {
|
|
342
|
-
constructor(public value: T) {
|
|
345
|
+
constructor(public value: T) {
|
|
346
|
+
if (!isInteger<T>() && !isFloat<T>()) ERROR("JSON.Box should only hold primitive types!");
|
|
347
|
+
}
|
|
343
348
|
/**
|
|
344
349
|
* Creates a reference to a primitive type
|
|
345
350
|
* This means that it can create a nullable primitive
|
|
@@ -353,6 +358,12 @@ export namespace JSON {
|
|
|
353
358
|
@inline static from<T>(value: T): Box<T> {
|
|
354
359
|
return new Box(value);
|
|
355
360
|
}
|
|
361
|
+
toString(): string {
|
|
362
|
+
if (isNullable<this>() && changetype<usize>(this) == null) return "null";
|
|
363
|
+
// @ts-ignore: type
|
|
364
|
+
if (isDefined(this.value.toString)) return this.value.toString();
|
|
365
|
+
return "null";
|
|
366
|
+
}
|
|
356
367
|
}
|
|
357
368
|
|
|
358
369
|
export function __serialize<T>(src: T): void {
|
|
@@ -421,8 +432,20 @@ export namespace JSON {
|
|
|
421
432
|
} else if (type instanceof Date) {
|
|
422
433
|
// @ts-ignore: type
|
|
423
434
|
return deserializeDate(srcStart, srcEnd);
|
|
435
|
+
} else if (type instanceof JSON.Box) {
|
|
436
|
+
// @ts-ignore: type
|
|
437
|
+
return new JSON.Box(deserializeBox(srcStart, srcEnd, dst, changetype<nonnull<T>>(0).value));
|
|
424
438
|
}
|
|
425
439
|
}
|
|
426
440
|
throw new Error(`Could not deserialize data '${ptrToStr(srcStart, srcEnd).slice(0, 100)}' to type. Make sure to add the correct decorators to classes.`);
|
|
427
441
|
}
|
|
428
442
|
}
|
|
443
|
+
|
|
444
|
+
// @ts-ignore: decorator
|
|
445
|
+
@inline function parseBox<T>(data: string, ty: T): T {
|
|
446
|
+
return JSON.parse<T>(data);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function deserializeBox<T>(srcStart: usize, srcEnd: usize, dst: usize, ty: T): T {
|
|
450
|
+
return JSON.__deserialize<T>(srcStart, srcEnd, dst);
|
|
451
|
+
}
|
|
@@ -18,7 +18,7 @@ export function serializeString_SIMD(src: string): void {
|
|
|
18
18
|
const srcSize = changetype<OBJECT>(changetype<usize>(src) - TOTAL_OVERHEAD).rtSize;
|
|
19
19
|
let srcStart = changetype<usize>(src);
|
|
20
20
|
const srcEnd = srcStart + srcSize;
|
|
21
|
-
bs.
|
|
21
|
+
bs.proposeSize(srcSize + 4);
|
|
22
22
|
const srcEnd16 = srcEnd - 15;
|
|
23
23
|
|
|
24
24
|
store<u8>(changetype<usize>(bs.offset), 34); /* " */
|
|
@@ -45,13 +45,13 @@ export function serializeString_SIMD(src: string): void {
|
|
|
45
45
|
mask &= mask - 1;
|
|
46
46
|
|
|
47
47
|
if ((escaped & 0xffff) != BACK_SLASH) {
|
|
48
|
-
bs.
|
|
48
|
+
bs.growSize(10);
|
|
49
49
|
store<u64>(dst_offset, 13511005048209500);
|
|
50
50
|
store<u32>(dst_offset, escaped, 8);
|
|
51
51
|
v128.store(dst_offset, v128.load(src_offset, 2), 12);
|
|
52
52
|
bs.offset += 10;
|
|
53
53
|
} else {
|
|
54
|
-
bs.
|
|
54
|
+
bs.growSize(2);
|
|
55
55
|
store<u32>(dst_offset, escaped);
|
|
56
56
|
v128.store(dst_offset, v128.load(src_offset, 2), 4);
|
|
57
57
|
bs.offset += 2;
|
|
@@ -84,7 +84,7 @@ export function serializeString_SIMD(src: string): void {
|
|
|
84
84
|
mask &= mask - 1;
|
|
85
85
|
|
|
86
86
|
if ((escaped & 0xffff) != BACK_SLASH) {
|
|
87
|
-
bs.
|
|
87
|
+
bs.growSize(10);
|
|
88
88
|
store<u64>(dst_offset, 13511005048209500);
|
|
89
89
|
store<u32>(dst_offset, escaped, 8);
|
|
90
90
|
while (lane_index < 6) {
|
|
@@ -93,7 +93,7 @@ export function serializeString_SIMD(src: string): void {
|
|
|
93
93
|
}
|
|
94
94
|
bs.offset += 10;
|
|
95
95
|
} else {
|
|
96
|
-
bs.
|
|
96
|
+
bs.growSize(2);
|
|
97
97
|
store<u32>(dst_offset, escaped);
|
|
98
98
|
|
|
99
99
|
while (lane_index < 6) {
|
|
@@ -116,12 +116,12 @@ export function serializeString_SIMD(src: string): void {
|
|
|
116
116
|
const escaped = load<u32>(SERIALIZE_ESCAPE_TABLE + (codeA << 2));
|
|
117
117
|
|
|
118
118
|
if ((escaped & 0xffff) != BACK_SLASH) {
|
|
119
|
-
bs.
|
|
119
|
+
bs.growSize(10);
|
|
120
120
|
store<u64>(bs.offset, 13511005048209500);
|
|
121
121
|
store<u32>(bs.offset, escaped, 8);
|
|
122
122
|
bs.offset += 12;
|
|
123
123
|
} else {
|
|
124
|
-
bs.
|
|
124
|
+
bs.growSize(2);
|
|
125
125
|
store<u32>(bs.offset, escaped);
|
|
126
126
|
bs.offset += 4;
|
|
127
127
|
}
|
|
@@ -134,12 +134,12 @@ export function serializeString_SIMD(src: string): void {
|
|
|
134
134
|
const escaped = load<u32>(SERIALIZE_ESCAPE_TABLE + (codeB << 2));
|
|
135
135
|
|
|
136
136
|
if ((escaped & 0xffff) != BACK_SLASH) {
|
|
137
|
-
bs.
|
|
137
|
+
bs.growSize(10);
|
|
138
138
|
store<u64>(bs.offset, 13511005048209500);
|
|
139
139
|
store<u32>(bs.offset, escaped, 8);
|
|
140
140
|
bs.offset += 12;
|
|
141
141
|
} else {
|
|
142
|
-
bs.
|
|
142
|
+
bs.growSize(2);
|
|
143
143
|
store<u32>(bs.offset, escaped);
|
|
144
144
|
bs.offset += 4;
|
|
145
145
|
}
|
|
@@ -156,12 +156,12 @@ export function serializeString_SIMD(src: string): void {
|
|
|
156
156
|
const escaped = load<u32>(SERIALIZE_ESCAPE_TABLE + (code << 2));
|
|
157
157
|
|
|
158
158
|
if ((escaped & 0xffff) != BACK_SLASH) {
|
|
159
|
-
bs.
|
|
159
|
+
bs.growSize(10);
|
|
160
160
|
store<u64>(bs.offset, 13511005048209500);
|
|
161
161
|
store<u32>(bs.offset, escaped, 8);
|
|
162
162
|
bs.offset += 12;
|
|
163
163
|
} else {
|
|
164
|
-
bs.
|
|
164
|
+
bs.growSize(2);
|
|
165
165
|
store<u32>(bs.offset, escaped);
|
|
166
166
|
bs.offset += 4;
|
|
167
167
|
}
|
|
@@ -3,15 +3,16 @@ import { COMMA, BRACKET_RIGHT, BRACKET_LEFT } from "../../custom/chars";
|
|
|
3
3
|
import { JSON } from "../..";
|
|
4
4
|
|
|
5
5
|
export function serializeArray<T extends any[]>(src: T): void {
|
|
6
|
+
bs.proposeSize(4);
|
|
6
7
|
const end = src.length - 1;
|
|
7
8
|
let i = 0;
|
|
8
9
|
if (end == -1) {
|
|
9
|
-
bs.proposeSize(4);
|
|
10
10
|
store<u32>(bs.offset, 6094939);
|
|
11
11
|
bs.offset += 4;
|
|
12
12
|
return;
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
// {} = 4
|
|
15
|
+
// xi, = n << 1
|
|
15
16
|
|
|
16
17
|
store<u16>(bs.offset, BRACKET_LEFT);
|
|
17
18
|
bs.offset += 2;
|
|
@@ -26,7 +27,7 @@ export function serializeArray<T extends any[]>(src: T): void {
|
|
|
26
27
|
|
|
27
28
|
const lastBlock = unchecked(src[end]);
|
|
28
29
|
JSON.__serialize<valueof<T>>(lastBlock);
|
|
29
|
-
bs.
|
|
30
|
+
bs.growSize(2);
|
|
30
31
|
store<u16>(bs.offset, BRACKET_RIGHT);
|
|
31
32
|
bs.offset += 2;
|
|
32
33
|
}
|
|
@@ -2,6 +2,11 @@ import { itoa_buffered } from "util/number";
|
|
|
2
2
|
import { bs } from "../../../modules/as-bs";
|
|
3
3
|
|
|
4
4
|
export function serializeInteger<T extends number>(data: T): void {
|
|
5
|
-
bs.
|
|
6
|
-
|
|
5
|
+
bs.ensureSize(sizeof<T>() << 3);
|
|
6
|
+
const bytesWritten = itoa_buffered(bs.offset, data) << 1;
|
|
7
|
+
bs.offset += bytesWritten;
|
|
8
|
+
bs.growSize(bytesWritten);
|
|
7
9
|
}
|
|
10
|
+
|
|
11
|
+
// 32 {"x":,"y":,"z"}
|
|
12
|
+
// 18 3.41.28.3
|
package/assembly/test.ts
CHANGED
|
@@ -1,5 +1,59 @@
|
|
|
1
|
-
import { JSON } from "
|
|
2
|
-
import {
|
|
1
|
+
import { JSON } from ".";
|
|
2
|
+
import { bytes } from "./util";
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
@json
|
|
5
|
+
class Obj {
|
|
6
|
+
public a: string = "hello";
|
|
7
|
+
public b: string = "world";
|
|
8
|
+
public c: string = "\"\t\f\u0000\u0001";
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@json
|
|
12
|
+
class Vec3 {
|
|
13
|
+
x: f32 = 0.0;
|
|
14
|
+
y: f32 = 0.0;
|
|
15
|
+
z: f32 = 0.0;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@json
|
|
19
|
+
class Player {
|
|
20
|
+
@alias("first name")
|
|
21
|
+
firstName!: string;
|
|
22
|
+
lastName!: string;
|
|
23
|
+
lastActive!: i32[];
|
|
24
|
+
// Drop in a code block, function, or expression that evaluates to a boolean
|
|
25
|
+
@omitif((age) => age < 18)
|
|
26
|
+
@omitif('this.age <= 0')
|
|
27
|
+
age!: i32;
|
|
28
|
+
@omitnull()
|
|
29
|
+
pos!: Vec3 | null;
|
|
30
|
+
isVerified!: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const player: Player = {
|
|
34
|
+
firstName: "Jairus",
|
|
35
|
+
lastName: "Tanaka",
|
|
36
|
+
lastActive: [2, 7, 2025],
|
|
37
|
+
age: 18,
|
|
38
|
+
pos: {
|
|
39
|
+
x: 3.4,
|
|
40
|
+
y: 1.2,
|
|
41
|
+
z: 8.3
|
|
42
|
+
},
|
|
43
|
+
isVerified: true
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const a1 = JSON.stringify("\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000a\u000b\u000c\u000d\u000e\u000f\u000f\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f");
|
|
47
|
+
// console.log("Bytes " + bytes(a1).toString());
|
|
48
|
+
console.log("a1: " + a1);
|
|
49
|
+
|
|
50
|
+
const obj = new Obj();
|
|
51
|
+
const a2 = JSON.stringify(obj);
|
|
52
|
+
// console.log("Bytes " + bytes(a2).toString());
|
|
53
|
+
console.log("a2: " + a2);
|
|
54
|
+
|
|
55
|
+
const a3 = JSON.stringify(player);
|
|
56
|
+
// console.log("Bytes " + bytes(a3).toString());
|
|
57
|
+
console.log("a3: " + a3);
|
|
58
|
+
|
|
59
|
+
JSON.Memory.shrink();
|
package/assembly/util/snp.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { POW_TEN_TABLE_32, POW_TEN_TABLE_64 } from "../globals/tables";
|
|
|
7
7
|
import { atoi } from "./atoi";
|
|
8
8
|
|
|
9
9
|
// @ts-ignore: Decorator valid here
|
|
10
|
-
@inline function snp<T extends number>(srcStart: usize, srcEnd: usize): T {
|
|
10
|
+
@inline export function snp<T extends number>(srcStart: usize, srcEnd: usize): T {
|
|
11
11
|
// @ts-ignore: type
|
|
12
12
|
let val: T = 0;
|
|
13
13
|
let char = load<u16>(srcStart) - 48;
|
|
@@ -46,7 +46,7 @@ import { atoi } from "./atoi";
|
|
|
46
46
|
char = load<u16>(srcStart);
|
|
47
47
|
if (char == 45) {
|
|
48
48
|
// @ts-ignore: type
|
|
49
|
-
return val / pow10(atoi(srcStart + 2, srcEnd));
|
|
49
|
+
return val / pow10(atoi<u8>(srcStart + 2, srcEnd));
|
|
50
50
|
} else {
|
|
51
51
|
// @ts-ignore: type
|
|
52
52
|
return val * pow10(atoi(srcStart, srcEnd));
|