json-as 1.0.0-alpha.3 → 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.
Files changed (42) hide show
  1. package/CHANGELOG +14 -0
  2. package/README.md +76 -59
  3. package/assembly/__benches__/misc.bench.ts +48 -0
  4. package/assembly/__benches__/schemas.ts +25 -0
  5. package/assembly/__tests__/arbitrary.spec.ts +19 -0
  6. package/assembly/__tests__/box.spec.ts +37 -0
  7. package/assembly/__tests__/date.spec.ts +38 -0
  8. package/assembly/__tests__/types.ts +3 -3
  9. package/assembly/deserialize/simd/string.ts +1 -1
  10. package/assembly/deserialize/simple/arbitrary.ts +1 -1
  11. package/assembly/deserialize/simple/array/arbitrary.ts +47 -24
  12. package/assembly/deserialize/simple/array/{object.ts → struct.ts} +1 -1
  13. package/assembly/deserialize/simple/array.ts +4 -9
  14. package/assembly/deserialize/simple/bool.ts +4 -7
  15. package/assembly/deserialize/simple/date.ts +2 -2
  16. package/assembly/deserialize/simple/integer.ts +2 -1
  17. package/assembly/deserialize/simple/map.ts +1 -1
  18. package/assembly/deserialize/simple/object.ts +13 -17
  19. package/assembly/deserialize/simple/struct.ts +158 -0
  20. package/assembly/index.ts +143 -24
  21. package/assembly/serialize/simd/string.ts +11 -11
  22. package/assembly/serialize/simple/arbitrary.ts +15 -2
  23. package/assembly/serialize/simple/array.ts +4 -3
  24. package/assembly/serialize/simple/float.ts +1 -1
  25. package/assembly/serialize/simple/integer.ts +7 -2
  26. package/assembly/serialize/simple/object.ts +43 -6
  27. package/assembly/serialize/simple/struct.ts +7 -0
  28. package/assembly/test.ts +84 -4
  29. package/assembly/util/atoi.ts +1 -1
  30. package/assembly/util/snp.ts +2 -2
  31. package/bench.js +11 -2
  32. package/modules/as-bs/assembly/index.ts +63 -32
  33. package/modules/as-bs/assembly/state.ts +8 -0
  34. package/package.json +7 -6
  35. package/transform/lib/builder.js +1340 -1262
  36. package/transform/lib/index.js +577 -512
  37. package/transform/lib/index.js.map +1 -1
  38. package/transform/lib/linker.js +12 -10
  39. package/transform/lib/types.js +19 -19
  40. package/transform/lib/util.js +34 -34
  41. package/transform/lib/visitor.js +529 -526
  42. package/transform/src/index.ts +25 -23
@@ -76,7 +76,7 @@ export function deserializeMap<T extends Map<any, any>>(srcStart: usize, srcEnd:
76
76
  srcStart += 2;
77
77
  while (srcStart < srcEnd) {
78
78
  const code = load<u16>(srcStart);
79
- if (((code ^ BRACE_RIGHT) | (code ^ BRACKET_RIGHT)) == 32) {
79
+ if (code == BRACKET_RIGHT) {
80
80
  if (--depth == 0) {
81
81
  // @ts-ignore: type
82
82
  out.set(key, JSON.__deserialize<valueof<T>>(lastIndex, srcStart));
@@ -1,8 +1,11 @@
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";
5
+ import { deserializeArbitrary } from "./arbitrary";
3
6
 
4
- export function deserializeObject<T>(srcStart: usize, srcEnd: usize, dst: usize): T {
5
- const out = changetype<nonnull<T>>(dst || __new(offsetof<T>(), idof<T>()));
7
+ export function deserializeObject(srcStart: usize, srcEnd: usize, dst: usize): JSON.Obj {
8
+ const out = new JSON.Obj();
6
9
 
7
10
  let keyStart: usize = 0;
8
11
  let keyEnd: usize = 0;
@@ -20,7 +23,7 @@ export function deserializeObject<T>(srcStart: usize, srcEnd: usize, dst: usize)
20
23
  if (isKey) {
21
24
  keyStart = lastIndex;
22
25
  keyEnd = srcStart;
23
- // console.log("Key: " + ptrToStr(lastIndex, srcStart));
26
+ // console.log("Key: " + ptrToStr(keyStart, keyEnd));
24
27
  // console.log("Next: " + String.fromCharCode(load<u16>(srcStart + 2)));
25
28
  srcStart += 2;
26
29
  // while (isSpace((code = load<u16>((srcStart += 2))))) {
@@ -44,8 +47,7 @@ export function deserializeObject<T>(srcStart: usize, srcEnd: usize, dst: usize)
44
47
  const code = load<u16>(srcStart);
45
48
  if (code == QUOTE && load<u16>(srcStart - 2) !== BACK_SLASH) {
46
49
  // console.log("Value (string): " + ptrToStr(lastIndex, srcStart + 2));
47
- // @ts-ignore: exists
48
- out.__DESERIALIZE(keyStart, keyEnd, lastIndex, srcStart + 2, dst);
50
+ out.set(ptrToStr(keyStart, keyEnd), deserializeArbitrary(lastIndex, srcStart + 2, dst));
49
51
  // while (isSpace(load<u16>(srcStart))) srcStart += 2;
50
52
  srcStart += 4;
51
53
  // console.log("Next: " + String.fromCharCode(load<u16>(srcStart)));
@@ -60,9 +62,8 @@ 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)) {
63
- // @ts-ignore: exists
64
- out.__DESERIALIZE(keyStart, keyEnd, lastIndex, srcStart, dst);
65
65
  // console.log("Value (number): " + ptrToStr(lastIndex, srcStart));
66
+ out.set(ptrToStr(keyStart, keyEnd), deserializeArbitrary(lastIndex, srcStart, dst));
66
67
  // while (isSpace(load<u16>((srcStart += 2)))) {
67
68
  // /* empty */
68
69
  // }
@@ -82,8 +83,7 @@ export function deserializeObject<T>(srcStart: usize, srcEnd: usize, dst: usize)
82
83
  if (code == BRACE_RIGHT) {
83
84
  if (--depth == 0) {
84
85
  // console.log("Value (object): " + ptrToStr(lastIndex, srcStart + 2));
85
- // @ts-ignore: exists
86
- out.__DESERIALIZE(keyStart, keyEnd, lastIndex, (srcStart += 2), dst);
86
+ out.set(ptrToStr(keyStart, keyEnd), deserializeArbitrary(lastIndex, srcStart += 2, dst));
87
87
  // console.log("Next: " + String.fromCharCode(load<u16>(srcStart)));
88
88
  keyStart = 0;
89
89
  // while (isSpace(load<u16>(srcStart))) {
@@ -103,8 +103,7 @@ export function deserializeObject<T>(srcStart: usize, srcEnd: usize, dst: usize)
103
103
  if (code == BRACKET_RIGHT) {
104
104
  if (--depth == 0) {
105
105
  // console.log("Value (array): " + ptrToStr(lastIndex, srcStart + 2));
106
- // @ts-ignore: exists
107
- out.__DESERIALIZE(keyStart, keyEnd, lastIndex, (srcStart += 2), dst);
106
+ out.set(ptrToStr(keyStart, keyEnd), deserializeArbitrary(lastIndex, srcStart += 2, dst));
108
107
  // console.log("Next: " + String.fromCharCode(load<u16>(srcStart)));
109
108
  keyStart = 0;
110
109
  // while (isSpace(load<u16>((srcStart += 2)))) {
@@ -118,8 +117,7 @@ export function deserializeObject<T>(srcStart: usize, srcEnd: usize, dst: usize)
118
117
  } else if (code == CHAR_T) {
119
118
  if (load<u64>(srcStart) == 28429475166421108) {
120
119
  // console.log("Value (bool): " + ptrToStr(srcStart, srcStart + 8));
121
- // @ts-ignore: exists
122
- out.__DESERIALIZE(keyStart, keyEnd, srcStart, (srcStart += 8), dst);
120
+ out.set(ptrToStr(keyStart, keyEnd), deserializeArbitrary(lastIndex, srcStart += 8, dst));
123
121
  // while (isSpace(load<u16>((srcStart += 2)))) {
124
122
  // /* empty */
125
123
  // }
@@ -130,8 +128,7 @@ export function deserializeObject<T>(srcStart: usize, srcEnd: usize, dst: usize)
130
128
  } else if (code == CHAR_F) {
131
129
  if (load<u64>(srcStart, 2) == 28429466576093281) {
132
130
  // console.log("Value (bool): " + ptrToStr(srcStart, srcStart + 10));
133
- // @ts-ignore: exists
134
- out.__DESERIALIZE(keyStart, keyEnd, srcStart, (srcStart += 10), dst);
131
+ out.set(ptrToStr(keyStart, keyEnd), deserializeArbitrary(lastIndex, srcStart += 10, dst));
135
132
  // while (isSpace(load<u16>((srcStart += 2)))) {
136
133
  // /* empty */
137
134
  // }
@@ -142,8 +139,7 @@ export function deserializeObject<T>(srcStart: usize, srcEnd: usize, dst: usize)
142
139
  } else if (code == CHAR_N) {
143
140
  if (load<u64>(srcStart) == 30399761348886638) {
144
141
  // console.log("Value (null): " + ptrToStr(srcStart, srcStart + 8));
145
- // @ts-ignore: exists
146
- out.__DESERIALIZE(keyStart, keyEnd, srcStart, (srcStart += 8), dst);
142
+ out.set(ptrToStr(keyStart, keyEnd), deserializeArbitrary(lastIndex, srcStart += 8, dst));
147
143
  // while (isSpace(load<u16>((srcStart += 2)))) {
148
144
  /* empty */
149
145
  // }
@@ -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 { deserializeObject } from "./deserialize/simple/object";
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 { serializeObject } from "./serialize/simple/object";
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
 
@@ -36,6 +40,11 @@ export type Raw = string;
36
40
  * JSON Encoder/Decoder for AssemblyScript
37
41
  */
38
42
  export namespace JSON {
43
+ export namespace Memory {
44
+ export function shrink(): void {
45
+ bs.resize(64);
46
+ }
47
+ }
39
48
  /**
40
49
  * Serializes valid JSON data
41
50
  * ```js
@@ -44,7 +53,8 @@ export namespace JSON {
44
53
  * @param data T
45
54
  * @returns string
46
55
  */
47
- export function stringify<T>(data: T, out: string | null = null): string {
56
+ // @ts-ignore: inline
57
+ @inline export function stringify<T>(data: T, out: string | null = null): string {
48
58
  if (isBoolean<T>()) {
49
59
  if (out) {
50
60
  if (<bool>data == true) {
@@ -107,9 +117,7 @@ export namespace JSON {
107
117
  serializeString(changetype<string>(data));
108
118
  return bs.out<string>();
109
119
  // @ts-ignore: Supplied by transform
110
- } else if (isDefined(data.__SERIALIZE) && isDefined(data.__ALLOCATE)) {
111
- // @ts-ignore
112
- // data.__ALLOCATE();
120
+ } else if (isDefined(data.__SERIALIZE)) {
113
121
  // @ts-ignore
114
122
  data.__SERIALIZE(changetype<usize>(data));
115
123
  return bs.out<string>();
@@ -119,8 +127,8 @@ export namespace JSON {
119
127
 
120
128
  store<u16>(changetype<usize>(out), QUOTE);
121
129
  memory.copy(changetype<usize>(out) + 2, changetype<usize>(data.toISOString()), 48);
122
- store<u16>(changetype<usize>(out), 50);
123
- return out;
130
+ store<u16>(changetype<usize>(out), QUOTE, 50);
131
+ return changetype<string>(out);
124
132
  } else if (data instanceof Array) {
125
133
  // @ts-ignore
126
134
  serializeArray(changetype<nonnull<T>>(data));
@@ -132,6 +140,9 @@ export namespace JSON {
132
140
  } else if (data instanceof JSON.Value) {
133
141
  serializeArbitrary(data);
134
142
  return bs.out<string>();
143
+ } else if (data instanceof JSON.Obj) {
144
+ serializeObject(data);
145
+ return bs.out<string>();
135
146
  } else if (data instanceof JSON.Box) {
136
147
  return JSON.stringify(data.value);
137
148
  } else {
@@ -147,7 +158,8 @@ export namespace JSON {
147
158
  * @param data string
148
159
  * @returns T
149
160
  */
150
- export function parse<T>(data: string): T {
161
+ // @ts-ignore: inline
162
+ @inline export function parse<T>(data: string): T {
151
163
  const dataSize = bytes(data);
152
164
  const dataPtr = changetype<usize>(data);
153
165
  if (isBoolean<T>()) {
@@ -156,7 +168,7 @@ export namespace JSON {
156
168
  return deserializeInteger<T>(dataPtr, dataPtr + dataSize);
157
169
  } else if (isFloat<T>()) {
158
170
  return deserializeFloat<T>(dataPtr, dataPtr + dataSize);
159
- } else if (isNullable<T>() && data.length == 4 && data == "null") {
171
+ } else if (isNullable<T>() && dataSize == 8 && load<u64>(dataPtr) == 30399761348886638) {
160
172
  // @ts-ignore
161
173
  return null;
162
174
  } else if (isString<T>()) {
@@ -168,21 +180,27 @@ export namespace JSON {
168
180
  }
169
181
  let type: nonnull<T> = changetype<nonnull<T>>(0);
170
182
  // @ts-ignore: Defined by transform
171
- if (isDefined(type.__DESERIALIZE) && isDefined(type.__INITIALIZE)) {
183
+ if (isDefined(type.__DESERIALIZE)) {
172
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();
173
187
  // @ts-ignore
174
- changetype<nonnull<T>>(out).__INITIALIZE();
175
- // @ts-ignore
176
- return deserializeObject<nonnull<T>>(dataPtr, dataPtr + dataSize, out);
188
+ return deserializeStruct<nonnull<T>>(dataPtr, dataPtr + dataSize, out);
177
189
  } else if (type instanceof Map) {
178
190
  // @ts-ignore
179
191
  return deserializeMap<nonnull<T>>(dataPtr, dataPtr + dataSize);
180
192
  } else if (type instanceof Date) {
181
193
  // @ts-ignore
182
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);
183
201
  } else if (type instanceof JSON.Box) {
184
202
  // @ts-ignore
185
- return new JSON.Box(JSON.parse<indexof<T>>(data));
203
+ return new JSON.Box(parseBox(data, changetype<nonnull<T>>(0).value));
186
204
  } else {
187
205
  throw new Error(`Could not deserialize data ${data} to type ${nameof<T>()}. Make sure to add the correct decorators to classes.`);
188
206
  }
@@ -254,7 +272,7 @@ export namespace JSON {
254
272
  this.type = JSON.Types.U64;
255
273
  store<T>(changetype<usize>(this), value, STORAGE);
256
274
  } else if (value instanceof f32) {
257
- this.type = JSON.Types.F64;
275
+ this.type = JSON.Types.F32;
258
276
  store<T>(changetype<usize>(this), value, STORAGE);
259
277
  } else if (value instanceof f64) {
260
278
  this.type = JSON.Types.F64;
@@ -274,6 +292,9 @@ export namespace JSON {
274
292
  // @ts-ignore
275
293
  if (!JSON.Value.METHODS.has(idof<T>())) JSON.Value.METHODS.set(idof<T>(), value.__SERIALIZE.index);
276
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;
277
298
  store<T>(changetype<usize>(this), value, STORAGE);
278
299
  // @ts-ignore
279
300
  } else if (isArray<T>() && idof<valueof<T>>() == idof<JSON.Value>()) {
@@ -305,6 +326,10 @@ export namespace JSON {
305
326
  return this.get<u32>().toString();
306
327
  case JSON.Types.U64:
307
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();
308
333
  case JSON.Types.String:
309
334
  return '"' + this.get<string>() + '"';
310
335
  case JSON.Types.Bool:
@@ -326,20 +351,88 @@ export namespace JSON {
326
351
  out.write("]");
327
352
  return out.toString();
328
353
  }
354
+ case JSON.Types.Object: {
355
+ return JSON.stringify(this.get<JSON.Obj>());
356
+ }
329
357
  default: {
330
358
  const fn = JSON.Value.METHODS.get(this.type - JSON.Types.Struct);
331
359
  const value = this.get<usize>();
332
- return call_indirect<string>(fn, 0, value);
360
+ call_indirect<void>(fn, 0, value);
361
+ return bs.out<string>();
333
362
  }
334
363
  }
335
364
  }
336
365
  }
337
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
+ }
338
429
  /**
339
430
  * Box for primitive types
340
431
  */
341
432
  export class Box<T> {
342
- constructor(public value: T) {}
433
+ constructor(public value: T) {
434
+ if (!isInteger<T>() && !isFloat<T>()) ERROR("JSON.Box should only hold primitive types!");
435
+ }
343
436
  /**
344
437
  * Creates a reference to a primitive type
345
438
  * This means that it can create a nullable primitive
@@ -353,9 +446,16 @@ export namespace JSON {
353
446
  @inline static from<T>(value: T): Box<T> {
354
447
  return new Box(value);
355
448
  }
449
+ toString(): string {
450
+ if (isNullable<this>() && changetype<usize>(this) == null) return "null";
451
+ // @ts-ignore: type
452
+ if (isDefined(this.value.toString)) return this.value.toString();
453
+ return "null";
454
+ }
356
455
  }
357
456
 
358
- export function __serialize<T>(src: T): void {
457
+ // @ts-ignore: inline
458
+ @inline export function __serialize<T>(src: T): void {
359
459
  if (isBoolean<T>()) {
360
460
  serializeBool(src as bool);
361
461
  } else if (isInteger<T>() && nameof<T>() == "usize" && src == 0) {
@@ -378,7 +478,7 @@ export namespace JSON {
378
478
  // @ts-ignore: Supplied by transform
379
479
  } else if (isDefined(src.__SERIALIZE)) {
380
480
  // @ts-ignore
381
- serializeObject(changetype<nonnull<T>>(src));
481
+ serializeStruct(changetype<nonnull<T>>(src));
382
482
  } else if (src instanceof Date) {
383
483
  // @ts-ignore
384
484
  serializeDate(changetype<nonnull<T>>(src));
@@ -390,18 +490,22 @@ export namespace JSON {
390
490
  serializeMap(changetype<nonnull<T>>(src));
391
491
  } else if (src instanceof JSON.Value) {
392
492
  serializeArbitrary(src);
493
+ } else if (src instanceof JSON.Obj) {
494
+ serializeObject(src);
393
495
  } else if (src instanceof JSON.Box) {
394
496
  __serialize(src.value);
395
497
  } else {
396
498
  throw new Error(`Could not serialize provided data. Make sure to add the correct decorators to classes.`);
397
499
  }
398
500
  }
399
- export function __deserialize<T>(srcStart: usize, srcEnd: usize, dst: usize = 0): T {
501
+
502
+ // @ts-ignore: inline
503
+ @inline export function __deserialize<T>(srcStart: usize, srcEnd: usize, dst: usize = 0): T {
400
504
  if (isBoolean<T>()) {
401
505
  // @ts-ignore: type
402
506
  return deserializeBoolean(srcStart, srcEnd);
403
507
  } else if (isInteger<T>()) {
404
- return deserializeInteger<T>(srcStart, srcEnd);
508
+ return atoi<T>(srcStart, srcEnd);
405
509
  } else if (isFloat<T>()) {
406
510
  return deserializeFloat<T>(srcStart, srcEnd);
407
511
  } else if (isString<T>()) {
@@ -414,15 +518,30 @@ export namespace JSON {
414
518
  let type: nonnull<T> = changetype<nonnull<T>>(0);
415
519
  // @ts-ignore: declared by transform
416
520
  if (isDefined(type.__DESERIALIZE)) {
417
- return deserializeObject<T>(srcStart, srcEnd, dst);
521
+ return deserializeStruct<T>(srcStart, srcEnd, dst);
418
522
  } else if (type instanceof Map) {
419
523
  // @ts-ignore: type
420
524
  return deserializeMap<T>(srcStart, srcEnd, dst);
421
525
  } else if (type instanceof Date) {
422
526
  // @ts-ignore: type
423
527
  return deserializeDate(srcStart, srcEnd);
528
+ } else if (type instanceof JSON.Value) {
529
+ // @ts-ignore: type
530
+ return deserializeArbitrary(srcStart, srcEnd, 0);
531
+ } else if (type instanceof JSON.Box) {
532
+ // @ts-ignore: type
533
+ return new JSON.Box(deserializeBox(srcStart, srcEnd, dst, changetype<nonnull<T>>(0).value));
424
534
  }
425
535
  }
426
536
  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
537
  }
428
538
  }
539
+
540
+ // @ts-ignore: decorator
541
+ @inline function parseBox<T>(data: string, ty: T): T {
542
+ return JSON.parse<T>(data);
543
+ }
544
+
545
+ function deserializeBox<T>(srcStart: usize, srcEnd: usize, dst: usize, ty: T): T {
546
+ return JSON.__deserialize<T>(srcStart, srcEnd, dst);
547
+ }
@@ -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.ensureSize(srcSize + 4);
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.addSize(10);
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.addSize(2);
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.addSize(10);
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.addSize(2);
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.addSize(10);
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.addSize(2);
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.addSize(10);
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.addSize(2);
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.addSize(10);
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.addSize(2);
164
+ bs.growSize(2);
165
165
  store<u32>(bs.offset, escaped);
166
166
  bs.offset += 4;
167
167
  }