json-as 1.0.0-alpha.4 → 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -55
- package/assembly/__benches__/misc.bench.ts +48 -0
- package/assembly/__benches__/schemas.ts +25 -0
- package/assembly/__tests__/arbitrary.spec.ts +19 -0
- package/assembly/__tests__/types.ts +3 -3
- package/assembly/deserialize/simd/string.ts +1 -1
- package/assembly/deserialize/simple/arbitrary.ts +1 -1
- package/assembly/deserialize/simple/array/arbitrary.ts +47 -24
- package/assembly/deserialize/simple/array/{object.ts → struct.ts} +1 -1
- package/assembly/deserialize/simple/array.ts +4 -9
- package/assembly/deserialize/simple/integer.ts +2 -1
- package/assembly/deserialize/simple/map.ts +1 -1
- package/assembly/deserialize/simple/object.ts +11 -17
- package/assembly/deserialize/simple/struct.ts +158 -0
- package/assembly/index.ts +112 -16
- package/assembly/serialize/simple/arbitrary.ts +15 -2
- package/assembly/serialize/simple/object.ts +43 -6
- package/assembly/serialize/simple/struct.ts +7 -0
- package/assembly/test.ts +29 -3
- package/assembly/util/atoi.ts +1 -1
- package/bench.js +11 -2
- package/modules/as-bs/assembly/index.ts +3 -3
- package/modules/as-bs/assembly/state.ts +8 -0
- package/package.json +3 -2
- package/transform/lib/index.js +4 -9
- package/transform/lib/index.js.map +1 -1
- package/transform/src/index.ts +4 -8
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { BACK_SLASH, COMMA, CHAR_F, BRACE_LEFT, BRACKET_LEFT, CHAR_N, QUOTE, BRACE_RIGHT, BRACKET_RIGHT, CHAR_T } from "../../custom/chars";
|
|
2
|
+
import { isSpace } from "../../util";
|
|
3
|
+
|
|
4
|
+
export function deserializeStruct<T>(srcStart: usize, srcEnd: usize, dst: usize): T {
|
|
5
|
+
const out = changetype<nonnull<T>>(dst || __new(offsetof<T>(), idof<T>()));
|
|
6
|
+
|
|
7
|
+
let keyStart: usize = 0;
|
|
8
|
+
let keyEnd: usize = 0;
|
|
9
|
+
let isKey = false;
|
|
10
|
+
let depth = 0;
|
|
11
|
+
let lastIndex: usize = 0;
|
|
12
|
+
|
|
13
|
+
// while (srcStart < srcEnd && isSpace(load<u16>(srcStart))) srcStart += 2;
|
|
14
|
+
// while (srcEnd > srcStart && isSpace(load<u16>(srcEnd))) srcEnd -= 2;
|
|
15
|
+
srcStart += 2;
|
|
16
|
+
while (srcStart < srcEnd) {
|
|
17
|
+
let code = load<u16>(srcStart); // while (isSpace(code)) code = load<u16>(srcStart += 2);
|
|
18
|
+
if (keyStart == 0) {
|
|
19
|
+
if (code == QUOTE && load<u16>(srcStart - 2) !== BACK_SLASH) {
|
|
20
|
+
if (isKey) {
|
|
21
|
+
keyStart = lastIndex;
|
|
22
|
+
keyEnd = srcStart;
|
|
23
|
+
// console.log("Key: " + ptrToStr(lastIndex, srcStart));
|
|
24
|
+
// console.log("Next: " + String.fromCharCode(load<u16>(srcStart + 2)));
|
|
25
|
+
srcStart += 2;
|
|
26
|
+
// while (isSpace((code = load<u16>((srcStart += 2))))) {
|
|
27
|
+
// /* empty */
|
|
28
|
+
// }
|
|
29
|
+
// if (code !== COLON) throw new Error("Expected ':' after key at position " + (srcStart - srcPtr).toString());
|
|
30
|
+
isKey = false;
|
|
31
|
+
} else {
|
|
32
|
+
// console.log("Got key start");
|
|
33
|
+
isKey = true; // i don't like this
|
|
34
|
+
lastIndex = srcStart + 2;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// isKey = !isKey;
|
|
38
|
+
srcStart += 2;
|
|
39
|
+
} else {
|
|
40
|
+
if (code == QUOTE) {
|
|
41
|
+
lastIndex = srcStart;
|
|
42
|
+
srcStart += 2;
|
|
43
|
+
while (srcStart < srcEnd) {
|
|
44
|
+
const code = load<u16>(srcStart);
|
|
45
|
+
if (code == QUOTE && load<u16>(srcStart - 2) !== BACK_SLASH) {
|
|
46
|
+
// console.log("Value (string): " + ptrToStr(lastIndex, srcStart + 2));
|
|
47
|
+
// @ts-ignore: exists
|
|
48
|
+
out.__DESERIALIZE(keyStart, keyEnd, lastIndex, srcStart + 2, dst);
|
|
49
|
+
// while (isSpace(load<u16>(srcStart))) srcStart += 2;
|
|
50
|
+
srcStart += 4;
|
|
51
|
+
// console.log("Next: " + String.fromCharCode(load<u16>(srcStart)));
|
|
52
|
+
keyStart = 0;
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
srcStart += 2;
|
|
56
|
+
}
|
|
57
|
+
} else if (code - 48 <= 9 || code == 45) {
|
|
58
|
+
lastIndex = srcStart;
|
|
59
|
+
srcStart += 2;
|
|
60
|
+
while (srcStart < srcEnd) {
|
|
61
|
+
const code = load<u16>(srcStart);
|
|
62
|
+
if (code == COMMA || code == BRACE_RIGHT || isSpace(code)) {
|
|
63
|
+
// console.log("Value (number): " + ptrToStr(lastIndex, srcStart));
|
|
64
|
+
// @ts-ignore: exists
|
|
65
|
+
out.__DESERIALIZE(keyStart, keyEnd, lastIndex, srcStart, dst);
|
|
66
|
+
// while (isSpace(load<u16>((srcStart += 2)))) {
|
|
67
|
+
// /* empty */
|
|
68
|
+
// }
|
|
69
|
+
srcStart += 2;
|
|
70
|
+
// console.log("Next: " + String.fromCharCode(load<u16>(srcStart)));
|
|
71
|
+
keyStart = 0;
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
srcStart += 2;
|
|
75
|
+
}
|
|
76
|
+
} else if (code == BRACE_LEFT) {
|
|
77
|
+
lastIndex = srcStart;
|
|
78
|
+
depth++;
|
|
79
|
+
srcStart += 2;
|
|
80
|
+
while (srcStart < srcEnd) {
|
|
81
|
+
const code = load<u16>(srcStart);
|
|
82
|
+
if (code == BRACE_RIGHT) {
|
|
83
|
+
if (--depth == 0) {
|
|
84
|
+
// console.log("Value (object): " + ptrToStr(lastIndex, srcStart + 2));
|
|
85
|
+
// @ts-ignore: exists
|
|
86
|
+
out.__DESERIALIZE(keyStart, keyEnd, lastIndex, (srcStart += 2), dst);
|
|
87
|
+
// console.log("Next: " + String.fromCharCode(load<u16>(srcStart)));
|
|
88
|
+
keyStart = 0;
|
|
89
|
+
// while (isSpace(load<u16>(srcStart))) {
|
|
90
|
+
// /* empty */
|
|
91
|
+
// }
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
} else if (code == BRACE_LEFT) depth++;
|
|
95
|
+
srcStart += 2;
|
|
96
|
+
}
|
|
97
|
+
} else if (code == BRACKET_LEFT) {
|
|
98
|
+
lastIndex = srcStart;
|
|
99
|
+
depth++;
|
|
100
|
+
srcStart += 2;
|
|
101
|
+
while (srcStart < srcEnd) {
|
|
102
|
+
const code = load<u16>(srcStart);
|
|
103
|
+
if (code == BRACKET_RIGHT) {
|
|
104
|
+
if (--depth == 0) {
|
|
105
|
+
// console.log("Value (array): " + ptrToStr(lastIndex, srcStart + 2));
|
|
106
|
+
// @ts-ignore: exists
|
|
107
|
+
out.__DESERIALIZE(keyStart, keyEnd, lastIndex, (srcStart += 2), dst);
|
|
108
|
+
// console.log("Next: " + String.fromCharCode(load<u16>(srcStart)));
|
|
109
|
+
keyStart = 0;
|
|
110
|
+
// while (isSpace(load<u16>((srcStart += 2)))) {
|
|
111
|
+
// /* empty */
|
|
112
|
+
// }
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
} else if (code == BRACKET_LEFT) depth++;
|
|
116
|
+
srcStart += 2;
|
|
117
|
+
}
|
|
118
|
+
} else if (code == CHAR_T) {
|
|
119
|
+
if (load<u64>(srcStart) == 28429475166421108) {
|
|
120
|
+
// console.log("Value (bool): " + ptrToStr(srcStart, srcStart + 8));
|
|
121
|
+
// @ts-ignore: exists
|
|
122
|
+
out.__DESERIALIZE(keyStart, keyEnd, srcStart, (srcStart += 8), dst);
|
|
123
|
+
// while (isSpace(load<u16>((srcStart += 2)))) {
|
|
124
|
+
// /* empty */
|
|
125
|
+
// }
|
|
126
|
+
srcStart += 2;
|
|
127
|
+
// console.log("Next: " + String.fromCharCode(load<u16>(srcStart)) + " " + (srcStart < srcEnd).toString());
|
|
128
|
+
keyStart = 0;
|
|
129
|
+
}
|
|
130
|
+
} else if (code == CHAR_F) {
|
|
131
|
+
if (load<u64>(srcStart, 2) == 28429466576093281) {
|
|
132
|
+
// console.log("Value (bool): " + ptrToStr(srcStart, srcStart + 10));
|
|
133
|
+
// @ts-ignore: exists
|
|
134
|
+
out.__DESERIALIZE(keyStart, keyEnd, srcStart, (srcStart += 10), dst);
|
|
135
|
+
// while (isSpace(load<u16>((srcStart += 2)))) {
|
|
136
|
+
// /* empty */
|
|
137
|
+
// }
|
|
138
|
+
srcStart += 2;
|
|
139
|
+
// console.log("Next: " + String.fromCharCode(load<u16>(srcStart)));
|
|
140
|
+
keyStart = 0;
|
|
141
|
+
}
|
|
142
|
+
} else if (code == CHAR_N) {
|
|
143
|
+
if (load<u64>(srcStart) == 30399761348886638) {
|
|
144
|
+
// console.log("Value (null): " + ptrToStr(srcStart, srcStart + 8));
|
|
145
|
+
// @ts-ignore: exists
|
|
146
|
+
out.__DESERIALIZE(keyStart, keyEnd, srcStart, (srcStart += 8), dst);
|
|
147
|
+
// while (isSpace(load<u16>((srcStart += 2)))) {
|
|
148
|
+
/* empty */
|
|
149
|
+
// }
|
|
150
|
+
srcStart += 2;
|
|
151
|
+
// console.log("Next: " + String.fromCharCode(load<u16>(srcStart)));
|
|
152
|
+
keyStart = 0;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return out;
|
|
158
|
+
}
|
package/assembly/index.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { serializeMap } from "./serialize/simple/map";
|
|
|
7
7
|
import { deserializeBoolean } from "./deserialize/simple/bool";
|
|
8
8
|
import { deserializeArray } from "./deserialize/simple/array";
|
|
9
9
|
import { deserializeFloat } from "./deserialize/simple/float";
|
|
10
|
-
import {
|
|
10
|
+
import { deserializeStruct } from "./deserialize/simple/struct";
|
|
11
11
|
import { deserializeMap } from "./deserialize/simple/map";
|
|
12
12
|
import { deserializeDate } from "./deserialize/simple/date";
|
|
13
13
|
import { deserializeInteger } from "./deserialize/simple/integer";
|
|
@@ -20,9 +20,13 @@ import { dtoa_buffered, itoa_buffered } from "util/number";
|
|
|
20
20
|
import { serializeBool } from "./serialize/simple/bool";
|
|
21
21
|
import { serializeInteger } from "./serialize/simple/integer";
|
|
22
22
|
import { serializeFloat } from "./serialize/simple/float";
|
|
23
|
-
import {
|
|
23
|
+
import { serializeStruct } from "./serialize/simple/struct";
|
|
24
24
|
import { ptrToStr } from "./util/ptrToStr";
|
|
25
|
-
import { bytes } from "./util";
|
|
25
|
+
import { atoi, bytes } from "./util";
|
|
26
|
+
import { deserializeArbitrary } from "./deserialize/simple/arbitrary";
|
|
27
|
+
import { SERIALIZE_ESCAPE_TABLE } from "./globals/tables";
|
|
28
|
+
import { serializeObject } from "./serialize/simple/object";
|
|
29
|
+
import { deserializeObject } from "./deserialize/simple/object";
|
|
26
30
|
|
|
27
31
|
export type Raw = string;
|
|
28
32
|
|
|
@@ -49,7 +53,8 @@ export namespace JSON {
|
|
|
49
53
|
* @param data T
|
|
50
54
|
* @returns string
|
|
51
55
|
*/
|
|
52
|
-
|
|
56
|
+
// @ts-ignore: inline
|
|
57
|
+
@inline export function stringify<T>(data: T, out: string | null = null): string {
|
|
53
58
|
if (isBoolean<T>()) {
|
|
54
59
|
if (out) {
|
|
55
60
|
if (<bool>data == true) {
|
|
@@ -135,6 +140,9 @@ export namespace JSON {
|
|
|
135
140
|
} else if (data instanceof JSON.Value) {
|
|
136
141
|
serializeArbitrary(data);
|
|
137
142
|
return bs.out<string>();
|
|
143
|
+
} else if (data instanceof JSON.Obj) {
|
|
144
|
+
serializeObject(data);
|
|
145
|
+
return bs.out<string>();
|
|
138
146
|
} else if (data instanceof JSON.Box) {
|
|
139
147
|
return JSON.stringify(data.value);
|
|
140
148
|
} else {
|
|
@@ -150,7 +158,8 @@ export namespace JSON {
|
|
|
150
158
|
* @param data string
|
|
151
159
|
* @returns T
|
|
152
160
|
*/
|
|
153
|
-
|
|
161
|
+
// @ts-ignore: inline
|
|
162
|
+
@inline export function parse<T>(data: string): T {
|
|
154
163
|
const dataSize = bytes(data);
|
|
155
164
|
const dataPtr = changetype<usize>(data);
|
|
156
165
|
if (isBoolean<T>()) {
|
|
@@ -171,18 +180,24 @@ export namespace JSON {
|
|
|
171
180
|
}
|
|
172
181
|
let type: nonnull<T> = changetype<nonnull<T>>(0);
|
|
173
182
|
// @ts-ignore: Defined by transform
|
|
174
|
-
if (isDefined(type.__DESERIALIZE)
|
|
183
|
+
if (isDefined(type.__DESERIALIZE)) {
|
|
175
184
|
const out = __new(offsetof<nonnull<T>>(), idof<nonnull<T>>());
|
|
185
|
+
// @ts-ignore: Defined by transform
|
|
186
|
+
if (isDefined(type.__INITIALIZE)) changetype<nonnull<T>>(out).__INITIALIZE();
|
|
176
187
|
// @ts-ignore
|
|
177
|
-
|
|
178
|
-
// @ts-ignore
|
|
179
|
-
return deserializeObject<nonnull<T>>(dataPtr, dataPtr + dataSize, out);
|
|
188
|
+
return deserializeStruct<nonnull<T>>(dataPtr, dataPtr + dataSize, out);
|
|
180
189
|
} else if (type instanceof Map) {
|
|
181
190
|
// @ts-ignore
|
|
182
191
|
return deserializeMap<nonnull<T>>(dataPtr, dataPtr + dataSize);
|
|
183
192
|
} else if (type instanceof Date) {
|
|
184
193
|
// @ts-ignore
|
|
185
194
|
return deserializeDate(dataPtr, dataPtr + dataSize);
|
|
195
|
+
} else if (type instanceof JSON.Value) {
|
|
196
|
+
// @ts-ignore
|
|
197
|
+
return deserializeArbitrary(dataPtr, dataPtr + dataSize, 0);
|
|
198
|
+
} else if (type instanceof JSON.Obj) {
|
|
199
|
+
// @ts-ignore
|
|
200
|
+
return deserializeObject(dataPtr, dataPtr + dataSize, 0);
|
|
186
201
|
} else if (type instanceof JSON.Box) {
|
|
187
202
|
// @ts-ignore
|
|
188
203
|
return new JSON.Box(parseBox(data, changetype<nonnull<T>>(0).value));
|
|
@@ -257,7 +272,7 @@ export namespace JSON {
|
|
|
257
272
|
this.type = JSON.Types.U64;
|
|
258
273
|
store<T>(changetype<usize>(this), value, STORAGE);
|
|
259
274
|
} else if (value instanceof f32) {
|
|
260
|
-
this.type = JSON.Types.
|
|
275
|
+
this.type = JSON.Types.F32;
|
|
261
276
|
store<T>(changetype<usize>(this), value, STORAGE);
|
|
262
277
|
} else if (value instanceof f64) {
|
|
263
278
|
this.type = JSON.Types.F64;
|
|
@@ -277,6 +292,9 @@ export namespace JSON {
|
|
|
277
292
|
// @ts-ignore
|
|
278
293
|
if (!JSON.Value.METHODS.has(idof<T>())) JSON.Value.METHODS.set(idof<T>(), value.__SERIALIZE.index);
|
|
279
294
|
// @ts-ignore
|
|
295
|
+
store<usize>(changetype<usize>(this), changetype<usize>(value), STORAGE);
|
|
296
|
+
} else if (value instanceof JSON.Obj) {
|
|
297
|
+
this.type = JSON.Types.Object;
|
|
280
298
|
store<T>(changetype<usize>(this), value, STORAGE);
|
|
281
299
|
// @ts-ignore
|
|
282
300
|
} else if (isArray<T>() && idof<valueof<T>>() == idof<JSON.Value>()) {
|
|
@@ -308,6 +326,10 @@ export namespace JSON {
|
|
|
308
326
|
return this.get<u32>().toString();
|
|
309
327
|
case JSON.Types.U64:
|
|
310
328
|
return this.get<u64>().toString();
|
|
329
|
+
case JSON.Types.F32:
|
|
330
|
+
return this.get<f32>().toString();
|
|
331
|
+
case JSON.Types.F64:
|
|
332
|
+
return this.get<f64>().toString();
|
|
311
333
|
case JSON.Types.String:
|
|
312
334
|
return '"' + this.get<string>() + '"';
|
|
313
335
|
case JSON.Types.Bool:
|
|
@@ -329,15 +351,81 @@ export namespace JSON {
|
|
|
329
351
|
out.write("]");
|
|
330
352
|
return out.toString();
|
|
331
353
|
}
|
|
354
|
+
case JSON.Types.Object: {
|
|
355
|
+
return JSON.stringify(this.get<JSON.Obj>());
|
|
356
|
+
}
|
|
332
357
|
default: {
|
|
333
358
|
const fn = JSON.Value.METHODS.get(this.type - JSON.Types.Struct);
|
|
334
359
|
const value = this.get<usize>();
|
|
335
|
-
|
|
360
|
+
call_indirect<void>(fn, 0, value);
|
|
361
|
+
return bs.out<string>();
|
|
336
362
|
}
|
|
337
363
|
}
|
|
338
364
|
}
|
|
339
365
|
}
|
|
340
366
|
|
|
367
|
+
export class Obj {
|
|
368
|
+
// When accessing stackSize, subtract 2
|
|
369
|
+
// @ts-ignore: type
|
|
370
|
+
private stackSize: u32 = 6;
|
|
371
|
+
// @ts-ignore: type
|
|
372
|
+
private storage: Map<string, JSON.Value> = new Map<string, JSON.Value>();
|
|
373
|
+
|
|
374
|
+
constructor() { }
|
|
375
|
+
|
|
376
|
+
// @ts-ignore: decorator
|
|
377
|
+
@inline get size(): i32 {
|
|
378
|
+
return this.storage.size;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// @ts-ignore: decorator
|
|
382
|
+
@inline set<T>(key: string, value: T): void {
|
|
383
|
+
if (!this.storage.has(key)) this.stackSize += bytes(key) + 8;
|
|
384
|
+
this.storage.set(key, JSON.Value.from<T>(value));
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// @ts-ignore: decorator
|
|
388
|
+
@inline get(key: string): JSON.Value | null {
|
|
389
|
+
if (!this.storage.has(key)) return null;
|
|
390
|
+
return this.storage.get(key);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// @ts-ignore: decorator
|
|
394
|
+
@inline has(key: string): bool {
|
|
395
|
+
return this.storage.has(key);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// @ts-ignore: decorator
|
|
399
|
+
@inline delete(key: string): bool {
|
|
400
|
+
return this.storage.delete(key);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// @ts-ignore: decorator
|
|
404
|
+
@inline keys(): string[] {
|
|
405
|
+
return this.storage.keys();
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// @ts-ignore: decorator
|
|
409
|
+
@inline values(): JSON.Value[] {
|
|
410
|
+
return this.storage.values();
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// @ts-ignore: decorator
|
|
414
|
+
@inline toString(): string {
|
|
415
|
+
return JSON.stringify(this);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// @ts-ignore: decorator
|
|
419
|
+
@inline static from<T>(value: T): JSON.Obj {
|
|
420
|
+
if (value instanceof JSON.Obj) return value;
|
|
421
|
+
const out = changetype<JSON.Obj>(__new(offsetof<JSON.Obj>(), idof<JSON.Obj>()));
|
|
422
|
+
|
|
423
|
+
if (value instanceof Map) {
|
|
424
|
+
|
|
425
|
+
}
|
|
426
|
+
return out;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
341
429
|
/**
|
|
342
430
|
* Box for primitive types
|
|
343
431
|
*/
|
|
@@ -366,7 +454,8 @@ export namespace JSON {
|
|
|
366
454
|
}
|
|
367
455
|
}
|
|
368
456
|
|
|
369
|
-
|
|
457
|
+
// @ts-ignore: inline
|
|
458
|
+
@inline export function __serialize<T>(src: T): void {
|
|
370
459
|
if (isBoolean<T>()) {
|
|
371
460
|
serializeBool(src as bool);
|
|
372
461
|
} else if (isInteger<T>() && nameof<T>() == "usize" && src == 0) {
|
|
@@ -389,7 +478,7 @@ export namespace JSON {
|
|
|
389
478
|
// @ts-ignore: Supplied by transform
|
|
390
479
|
} else if (isDefined(src.__SERIALIZE)) {
|
|
391
480
|
// @ts-ignore
|
|
392
|
-
|
|
481
|
+
serializeStruct(changetype<nonnull<T>>(src));
|
|
393
482
|
} else if (src instanceof Date) {
|
|
394
483
|
// @ts-ignore
|
|
395
484
|
serializeDate(changetype<nonnull<T>>(src));
|
|
@@ -401,18 +490,22 @@ export namespace JSON {
|
|
|
401
490
|
serializeMap(changetype<nonnull<T>>(src));
|
|
402
491
|
} else if (src instanceof JSON.Value) {
|
|
403
492
|
serializeArbitrary(src);
|
|
493
|
+
} else if (src instanceof JSON.Obj) {
|
|
494
|
+
serializeObject(src);
|
|
404
495
|
} else if (src instanceof JSON.Box) {
|
|
405
496
|
__serialize(src.value);
|
|
406
497
|
} else {
|
|
407
498
|
throw new Error(`Could not serialize provided data. Make sure to add the correct decorators to classes.`);
|
|
408
499
|
}
|
|
409
500
|
}
|
|
410
|
-
|
|
501
|
+
|
|
502
|
+
// @ts-ignore: inline
|
|
503
|
+
@inline export function __deserialize<T>(srcStart: usize, srcEnd: usize, dst: usize = 0): T {
|
|
411
504
|
if (isBoolean<T>()) {
|
|
412
505
|
// @ts-ignore: type
|
|
413
506
|
return deserializeBoolean(srcStart, srcEnd);
|
|
414
507
|
} else if (isInteger<T>()) {
|
|
415
|
-
return
|
|
508
|
+
return atoi<T>(srcStart, srcEnd);
|
|
416
509
|
} else if (isFloat<T>()) {
|
|
417
510
|
return deserializeFloat<T>(srcStart, srcEnd);
|
|
418
511
|
} else if (isString<T>()) {
|
|
@@ -425,13 +518,16 @@ export namespace JSON {
|
|
|
425
518
|
let type: nonnull<T> = changetype<nonnull<T>>(0);
|
|
426
519
|
// @ts-ignore: declared by transform
|
|
427
520
|
if (isDefined(type.__DESERIALIZE)) {
|
|
428
|
-
return
|
|
521
|
+
return deserializeStruct<T>(srcStart, srcEnd, dst);
|
|
429
522
|
} else if (type instanceof Map) {
|
|
430
523
|
// @ts-ignore: type
|
|
431
524
|
return deserializeMap<T>(srcStart, srcEnd, dst);
|
|
432
525
|
} else if (type instanceof Date) {
|
|
433
526
|
// @ts-ignore: type
|
|
434
527
|
return deserializeDate(srcStart, srcEnd);
|
|
528
|
+
} else if (type instanceof JSON.Value) {
|
|
529
|
+
// @ts-ignore: type
|
|
530
|
+
return deserializeArbitrary(srcStart, srcEnd, 0);
|
|
435
531
|
} else if (type instanceof JSON.Box) {
|
|
436
532
|
// @ts-ignore: type
|
|
437
533
|
return new JSON.Box(deserializeBox(srcStart, srcEnd, dst, changetype<nonnull<T>>(0).value));
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { JSON } from "../..";
|
|
2
2
|
import { serializeArray } from "./array";
|
|
3
3
|
import { serializeBool } from "./bool";
|
|
4
|
+
import { serializeFloat } from "./float";
|
|
4
5
|
import { serializeInteger } from "./integer";
|
|
6
|
+
import { serializeObject } from "./object";
|
|
5
7
|
import { serializeString } from "./string";
|
|
6
8
|
|
|
7
9
|
export function serializeArbitrary(src: JSON.Value): void {
|
|
@@ -18,19 +20,30 @@ export function serializeArbitrary(src: JSON.Value): void {
|
|
|
18
20
|
case JSON.Types.U64:
|
|
19
21
|
serializeInteger<u64>(src.get<u64>());
|
|
20
22
|
break;
|
|
23
|
+
case JSON.Types.F32:
|
|
24
|
+
serializeFloat<f32>(src.get<f32>());
|
|
25
|
+
break;
|
|
26
|
+
case JSON.Types.F64:
|
|
27
|
+
serializeFloat<f64>(src.get<f64>());
|
|
28
|
+
break;
|
|
21
29
|
case JSON.Types.String:
|
|
22
30
|
serializeString(src.get<string>());
|
|
23
31
|
break;
|
|
24
32
|
case JSON.Types.Bool:
|
|
25
33
|
serializeBool(src.get<bool>());
|
|
34
|
+
break;
|
|
26
35
|
case JSON.Types.Array: {
|
|
27
36
|
serializeArray(src.get<JSON.Value[]>());
|
|
28
37
|
break;
|
|
29
38
|
}
|
|
39
|
+
case JSON.Types.Object: {
|
|
40
|
+
serializeObject(src.get<JSON.Obj>());
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
30
43
|
default: {
|
|
31
44
|
const fn = JSON.Value.METHODS.get(src.type - JSON.Types.Struct);
|
|
32
|
-
const
|
|
33
|
-
call_indirect<
|
|
45
|
+
const ptr = src.get<usize>();
|
|
46
|
+
call_indirect<void>(fn, 0, ptr);
|
|
34
47
|
}
|
|
35
48
|
}
|
|
36
49
|
}
|
|
@@ -1,7 +1,44 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
}
|
|
1
|
+
import { JSON } from "../..";
|
|
2
|
+
import { bs } from "../../../modules/as-bs/assembly";
|
|
3
|
+
import { BRACE_LEFT, BRACE_RIGHT, QUOTE } from "../../custom/chars";
|
|
4
|
+
import { bytes } from "../../util";
|
|
4
5
|
|
|
5
|
-
export function serializeObject
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
export function serializeObject(data: JSON.Obj): void {
|
|
7
|
+
if (!data.size) {
|
|
8
|
+
store<u32>(bs.offset, 0);
|
|
9
|
+
bs.offset += 4;
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// This grabs `JSON.Obj.stackSize` which is private
|
|
14
|
+
bs.ensureSize(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(" "))
|
|
20
|
+
|
|
21
|
+
store<u16>(bs.offset, BRACE_LEFT);
|
|
22
|
+
bs.offset += 2;
|
|
23
|
+
|
|
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]));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
store<u16>(bs.offset, BRACE_RIGHT);
|
|
43
|
+
bs.offset += 2;
|
|
44
|
+
}
|
package/assembly/test.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { JSON } from ".";
|
|
2
|
+
import { bs } from "../modules/as-bs/assembly";
|
|
3
|
+
import { deserializeArbitraryArray } from "./deserialize/simple/array/arbitrary";
|
|
4
|
+
import { serializeObject } from "./serialize/simple/object";
|
|
2
5
|
import { bytes } from "./util";
|
|
3
6
|
|
|
4
7
|
@json
|
|
@@ -22,8 +25,7 @@ class Player {
|
|
|
22
25
|
lastName!: string;
|
|
23
26
|
lastActive!: i32[];
|
|
24
27
|
// Drop in a code block, function, or expression that evaluates to a boolean
|
|
25
|
-
@omitif((
|
|
26
|
-
@omitif('this.age <= 0')
|
|
28
|
+
@omitif((self: Player) => self.age < 18)
|
|
27
29
|
age!: i32;
|
|
28
30
|
@omitnull()
|
|
29
31
|
pos!: Vec3 | null;
|
|
@@ -56,4 +58,28 @@ const a3 = JSON.stringify(player);
|
|
|
56
58
|
// console.log("Bytes " + bytes(a3).toString());
|
|
57
59
|
console.log("a3: " + a3);
|
|
58
60
|
|
|
59
|
-
JSON.
|
|
61
|
+
const a4 = new JSON.Obj();
|
|
62
|
+
|
|
63
|
+
a4.set("x", 1.5);
|
|
64
|
+
a4.set("y", 5.4);
|
|
65
|
+
a4.set("z", 9.8);
|
|
66
|
+
a4.set("obj", obj)
|
|
67
|
+
a4.set<boolean>("bool", false);
|
|
68
|
+
|
|
69
|
+
console.log("a4: " + JSON.stringify(a4));
|
|
70
|
+
|
|
71
|
+
const a5 = JSON.parse<JSON.Obj>('{"foo":"bar"}');
|
|
72
|
+
|
|
73
|
+
console.log("a5: " + JSON.stringify(a5));
|
|
74
|
+
|
|
75
|
+
const a6 = JSON.parse<JSON.Obj>('{"x":1.5,"y":5.4,"z":9.8,"obj":{"foo":"bar"}}');
|
|
76
|
+
|
|
77
|
+
console.log("a6: " + JSON.stringify(a6));
|
|
78
|
+
|
|
79
|
+
const a7 = JSON.parse<JSON.Value[]>('["string",true,3.14,{"x":1.0,"y":2.0,"z":3.0},[1,2,3,true]]');
|
|
80
|
+
|
|
81
|
+
console.log("a7: " + JSON.stringify(a7));
|
|
82
|
+
|
|
83
|
+
const a8 = JSON.stringify(["hello", JSON.stringify("world"),"working?"]);
|
|
84
|
+
|
|
85
|
+
console.log("a8: " + a8);
|
package/assembly/util/atoi.ts
CHANGED
package/bench.js
CHANGED
|
@@ -34,8 +34,17 @@ const vec = {
|
|
|
34
34
|
let data;
|
|
35
35
|
|
|
36
36
|
const bench = new Bench({ time: 1000 })
|
|
37
|
-
.add("
|
|
38
|
-
data = JSON.stringify(
|
|
37
|
+
.add("serialize vec3", () =>
|
|
38
|
+
data = JSON.stringify(vec)
|
|
39
|
+
)
|
|
40
|
+
.add("deserialize vec3", () => {
|
|
41
|
+
data = JSON.parse('{"x":3,"y":1,"z":8}');
|
|
42
|
+
})
|
|
43
|
+
.add("serialize alphabet string", () => {
|
|
44
|
+
data = JSON.stringify("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~`!@#$%^&*()-_=+{[}]|\\:;\"'?/>.<,'\"}");
|
|
45
|
+
})
|
|
46
|
+
.add("deserialize alphabet string", () => {
|
|
47
|
+
data = JSON.parse('"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~`!@#$%^&*()-_=+{[}]|\\\\:;\\"\'?/>.<,\'\\"}"')
|
|
39
48
|
}) /*
|
|
40
49
|
.add("parse float", () => {
|
|
41
50
|
data = JSON.parse("1.2345")
|
|
@@ -87,11 +87,11 @@ export namespace bs {
|
|
|
87
87
|
// @ts-ignore: Decorator valid here
|
|
88
88
|
@inline export function resize(newSize: u32): void {
|
|
89
89
|
// @ts-ignore: exists
|
|
90
|
-
const newPtr = __renew(buffer, newSize);
|
|
90
|
+
const newPtr = changetype<ArrayBuffer>(__renew(changetype<usize>(buffer), newSize));
|
|
91
91
|
bufferSize = newSize;
|
|
92
|
+
offset = changetype<usize>(newPtr);
|
|
92
93
|
buffer = newPtr;
|
|
93
|
-
|
|
94
|
-
stackSize = newPtr;
|
|
94
|
+
stackSize = 0;
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "json-as",
|
|
3
|
-
"version": "1.0.0-
|
|
3
|
+
"version": "1.0.0-beta.1",
|
|
4
4
|
"author": "Jairus Tanaka",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"devDependencies": {
|
|
11
11
|
"@assemblyscript/wasi-shim": "^0.1.0",
|
|
12
12
|
"@types/node": "^22.13.1",
|
|
13
|
+
"as-bench": "JairusSW/as-bench",
|
|
13
14
|
"as-console": "^7.0.0",
|
|
14
15
|
"assemblyscript": "^0.27.34",
|
|
15
16
|
"assemblyscript-prettier": "^3.0.1",
|
|
@@ -52,7 +53,7 @@
|
|
|
52
53
|
},
|
|
53
54
|
"scripts": {
|
|
54
55
|
"test": "bash ./run-tests.sh",
|
|
55
|
-
"build:bench": "rm -rf ./build/ && asc assembly/__benches__/misc.bench.ts -o ./build/bench.wasm --textFile ./build/bench.wat --transform ./transform --optimizeLevel 3 --shrinkLevel 0 --converge --noAssert --uncheckedBehavior always --runtime
|
|
56
|
+
"build:bench": "rm -rf ./build/ && JSON_DEBUG=true asc assembly/__benches__/misc.bench.ts -o ./build/bench.wasm --textFile ./build/bench.wat --transform ./transform --optimizeLevel 3 --shrinkLevel 0 --converge --noAssert --uncheckedBehavior always --runtime stub --enable simd --enable bulk-memory",
|
|
56
57
|
"build:test": "rm -rf ./build/ && JSON_DEBUG=true asc assembly/test.ts --transform ./transform -o ./build/test.wasm --textFile ./build/test.wat --optimizeLevel 3 --shrinkLevel 0",
|
|
57
58
|
"build:test:simd": "rm -rf ./build/ && JSON_DEBUG=true asc assembly/test.ts --transform ./transform -o ./build/test.wasm --textFile ./build/test.wat --optimizeLevel 3 --shrinkLevel 0 --enable simd",
|
|
58
59
|
"test:wasmtime": "wasmtime ./build/test.wasm",
|