json-as 1.0.0-alpha.4 → 1.0.0-beta.2

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 (40) hide show
  1. package/.trunk/configs/.markdownlint.yaml +2 -0
  2. package/.trunk/configs/.shellcheckrc +7 -0
  3. package/.trunk/configs/.yamllint.yaml +7 -0
  4. package/.trunk/trunk.yaml +36 -0
  5. package/CHANGELOG +23 -0
  6. package/README.md +59 -57
  7. package/assembly/__benches__/misc.bench.ts +48 -0
  8. package/assembly/__benches__/schemas.ts +25 -0
  9. package/assembly/__benches__/string.bench.ts +24 -0
  10. package/assembly/__benches__/struct.bench.ts +22 -0
  11. package/assembly/__tests__/arbitrary.spec.ts +19 -0
  12. package/assembly/__tests__/custom.spec.ts +42 -0
  13. package/assembly/__tests__/types.ts +3 -3
  14. package/assembly/custom/bench.ts +26 -0
  15. package/assembly/deserialize/simd/string.ts +1 -1
  16. package/assembly/deserialize/simple/arbitrary.ts +1 -1
  17. package/assembly/deserialize/simple/array/arbitrary.ts +47 -24
  18. package/assembly/deserialize/simple/array/{object.ts → struct.ts} +1 -1
  19. package/assembly/deserialize/simple/array.ts +4 -9
  20. package/assembly/deserialize/simple/integer.ts +2 -1
  21. package/assembly/deserialize/simple/map.ts +1 -1
  22. package/assembly/deserialize/simple/object.ts +11 -17
  23. package/assembly/deserialize/simple/struct.ts +158 -0
  24. package/assembly/index.d.ts +15 -1
  25. package/assembly/index.ts +144 -18
  26. package/assembly/serialize/simple/arbitrary.ts +15 -2
  27. package/assembly/serialize/simple/object.ts +43 -6
  28. package/assembly/serialize/simple/struct.ts +7 -0
  29. package/assembly/test.ts +61 -3
  30. package/assembly/util/atoi.ts +1 -1
  31. package/bench/bench.ts +15 -0
  32. package/bench/schemas.ts +5 -0
  33. package/bench/string.bench.ts +16 -0
  34. package/bench.js +11 -2
  35. package/modules/as-bs/assembly/index.ts +3 -3
  36. package/modules/as-bs/assembly/state.ts +8 -0
  37. package/package.json +3 -2
  38. package/transform/lib/index.js +59 -9
  39. package/transform/lib/index.js.map +1 -1
  40. package/transform/src/index.ts +75 -9
@@ -5,7 +5,7 @@ import { deserializeBooleanArray } from "./array/bool";
5
5
  import { deserializeFloatArray } from "./array/float";
6
6
  import { deserializeIntegerArray } from "./array/integer";
7
7
  import { deserializeMapArray } from "./array/map";
8
- import { deserializeObjectArray } from "./array/object";
8
+ import { deserializeStructArray } from "./array/struct";
9
9
  import { deserializeStringArray } from "./array/string";
10
10
 
11
11
  // @ts-ignore: Decorator valid here
@@ -28,21 +28,16 @@ export function deserializeArray<T extends unknown[]>(srcStart: usize, srcEnd: u
28
28
  const type = changetype<nonnull<valueof<T>>>(0);
29
29
  if (type instanceof JSON.Value) {
30
30
  // @ts-ignore: type
31
- return deserializeArbitraryArray<T>(srcStart, srcEnd, dst);
31
+ return deserializeArbitraryArray(srcStart, srcEnd, dst);
32
32
  } else if (type instanceof Map) {
33
33
  // @ts-ignore: type
34
34
  return deserializeMapArray<T>(srcStart, srcEnd, dst);
35
35
  // @ts-ignore: defined by transform
36
36
  } else if (isDefined(type.__DESERIALIZE)) {
37
- return deserializeObjectArray<T>(srcStart, srcEnd, dst);
37
+ return deserializeStructArray<T>(srcStart, srcEnd, dst);
38
38
  }
39
39
  throw new Error("Could not parse array of type " + nameof<T>() + "!");
40
40
  } else {
41
41
  throw new Error("Could not parse array of type " + nameof<T>() + "!");
42
42
  }
43
- }
44
-
45
- function isMap<T>(): boolean {
46
- let type: T = changetype<T>(0);
47
- return type instanceof Map;
48
- }
43
+ }
@@ -1,5 +1,6 @@
1
1
  import { atoi } from "../../util/atoi";
2
2
 
3
- export function deserializeInteger<T>(srcStart: usize, srcEnd: usize): T {
3
+ // @ts-ignore: inline
4
+ @inline export function deserializeInteger<T>(srcStart: usize, srcEnd: usize): T {
4
5
  return atoi<T>(srcStart, srcEnd);
5
6
  }
@@ -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));
@@ -2,9 +2,10 @@ import { JSON } from "../..";
2
2
  import { BACK_SLASH, COMMA, CHAR_F, BRACE_LEFT, BRACKET_LEFT, CHAR_N, QUOTE, BRACE_RIGHT, BRACKET_RIGHT, CHAR_T } from "../../custom/chars";
3
3
  import { isSpace } from "../../util";
4
4
  import { ptrToStr } from "../../util/ptrToStr";
5
+ import { deserializeArbitrary } from "./arbitrary";
5
6
 
6
- export function deserializeObject<T>(srcStart: usize, srcEnd: usize, dst: usize): T {
7
- 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();
8
9
 
9
10
  let keyStart: usize = 0;
10
11
  let keyEnd: usize = 0;
@@ -22,7 +23,7 @@ export function deserializeObject<T>(srcStart: usize, srcEnd: usize, dst: usize)
22
23
  if (isKey) {
23
24
  keyStart = lastIndex;
24
25
  keyEnd = srcStart;
25
- // console.log("Key: " + ptrToStr(lastIndex, srcStart));
26
+ // console.log("Key: " + ptrToStr(keyStart, keyEnd));
26
27
  // console.log("Next: " + String.fromCharCode(load<u16>(srcStart + 2)));
27
28
  srcStart += 2;
28
29
  // while (isSpace((code = load<u16>((srcStart += 2))))) {
@@ -46,8 +47,7 @@ export function deserializeObject<T>(srcStart: usize, srcEnd: usize, dst: usize)
46
47
  const code = load<u16>(srcStart);
47
48
  if (code == QUOTE && load<u16>(srcStart - 2) !== BACK_SLASH) {
48
49
  // console.log("Value (string): " + ptrToStr(lastIndex, srcStart + 2));
49
- // @ts-ignore: exists
50
- out.__DESERIALIZE(keyStart, keyEnd, lastIndex, srcStart + 2, dst);
50
+ out.set(ptrToStr(keyStart, keyEnd), deserializeArbitrary(lastIndex, srcStart + 2, dst));
51
51
  // while (isSpace(load<u16>(srcStart))) srcStart += 2;
52
52
  srcStart += 4;
53
53
  // console.log("Next: " + String.fromCharCode(load<u16>(srcStart)));
@@ -63,8 +63,7 @@ export function deserializeObject<T>(srcStart: usize, srcEnd: usize, dst: usize)
63
63
  const code = load<u16>(srcStart);
64
64
  if (code == COMMA || code == BRACE_RIGHT || isSpace(code)) {
65
65
  // console.log("Value (number): " + ptrToStr(lastIndex, srcStart));
66
- // @ts-ignore: exists
67
- out.__DESERIALIZE(keyStart, keyEnd, lastIndex, srcStart, dst);
66
+ out.set(ptrToStr(keyStart, keyEnd), deserializeArbitrary(lastIndex, srcStart, dst));
68
67
  // while (isSpace(load<u16>((srcStart += 2)))) {
69
68
  // /* empty */
70
69
  // }
@@ -84,8 +83,7 @@ export function deserializeObject<T>(srcStart: usize, srcEnd: usize, dst: usize)
84
83
  if (code == BRACE_RIGHT) {
85
84
  if (--depth == 0) {
86
85
  // console.log("Value (object): " + ptrToStr(lastIndex, srcStart + 2));
87
- // @ts-ignore: exists
88
- out.__DESERIALIZE(keyStart, keyEnd, lastIndex, (srcStart += 2), dst);
86
+ out.set(ptrToStr(keyStart, keyEnd), deserializeArbitrary(lastIndex, srcStart += 2, dst));
89
87
  // console.log("Next: " + String.fromCharCode(load<u16>(srcStart)));
90
88
  keyStart = 0;
91
89
  // while (isSpace(load<u16>(srcStart))) {
@@ -105,8 +103,7 @@ export function deserializeObject<T>(srcStart: usize, srcEnd: usize, dst: usize)
105
103
  if (code == BRACKET_RIGHT) {
106
104
  if (--depth == 0) {
107
105
  // console.log("Value (array): " + ptrToStr(lastIndex, srcStart + 2));
108
- // @ts-ignore: exists
109
- out.__DESERIALIZE(keyStart, keyEnd, lastIndex, (srcStart += 2), dst);
106
+ out.set(ptrToStr(keyStart, keyEnd), deserializeArbitrary(lastIndex, srcStart += 2, dst));
110
107
  // console.log("Next: " + String.fromCharCode(load<u16>(srcStart)));
111
108
  keyStart = 0;
112
109
  // while (isSpace(load<u16>((srcStart += 2)))) {
@@ -120,8 +117,7 @@ export function deserializeObject<T>(srcStart: usize, srcEnd: usize, dst: usize)
120
117
  } else if (code == CHAR_T) {
121
118
  if (load<u64>(srcStart) == 28429475166421108) {
122
119
  // console.log("Value (bool): " + ptrToStr(srcStart, srcStart + 8));
123
- // @ts-ignore: exists
124
- out.__DESERIALIZE(keyStart, keyEnd, srcStart, (srcStart += 8), dst);
120
+ out.set(ptrToStr(keyStart, keyEnd), deserializeArbitrary(lastIndex, srcStart += 8, dst));
125
121
  // while (isSpace(load<u16>((srcStart += 2)))) {
126
122
  // /* empty */
127
123
  // }
@@ -132,8 +128,7 @@ export function deserializeObject<T>(srcStart: usize, srcEnd: usize, dst: usize)
132
128
  } else if (code == CHAR_F) {
133
129
  if (load<u64>(srcStart, 2) == 28429466576093281) {
134
130
  // console.log("Value (bool): " + ptrToStr(srcStart, srcStart + 10));
135
- // @ts-ignore: exists
136
- out.__DESERIALIZE(keyStart, keyEnd, srcStart, (srcStart += 10), dst);
131
+ out.set(ptrToStr(keyStart, keyEnd), deserializeArbitrary(lastIndex, srcStart += 10, dst));
137
132
  // while (isSpace(load<u16>((srcStart += 2)))) {
138
133
  // /* empty */
139
134
  // }
@@ -144,8 +139,7 @@ export function deserializeObject<T>(srcStart: usize, srcEnd: usize, dst: usize)
144
139
  } else if (code == CHAR_N) {
145
140
  if (load<u64>(srcStart) == 30399761348886638) {
146
141
  // console.log("Value (null): " + ptrToStr(srcStart, srcStart + 8));
147
- // @ts-ignore: exists
148
- out.__DESERIALIZE(keyStart, keyEnd, srcStart, (srcStart += 8), dst);
142
+ out.set(ptrToStr(keyStart, keyEnd), deserializeArbitrary(lastIndex, srcStart += 8, dst));
149
143
  // while (isSpace(load<u16>((srcStart += 2)))) {
150
144
  /* empty */
151
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
+ }
@@ -1,11 +1,13 @@
1
1
  /**
2
2
  * Class decorator that enables the class to be recognized as JSON.
3
3
  */
4
+ // @ts-ignore: type
4
5
  declare function json(..._): void;
5
6
 
6
7
  /**
7
8
  * Class decorator that enables the class to be recognized as JSON.
8
9
  */
10
+ // @ts-ignore: type
9
11
  declare function serializable(..._): void;
10
12
 
11
13
  /**
@@ -16,6 +18,7 @@ declare function alias(newName: string): Function;
16
18
  /**
17
19
  * Property decorator that allows omits a field, making it be ignored.
18
20
  */
21
+ // @ts-ignore: type
19
22
  declare function omit(..._): void;
20
23
 
21
24
  /**
@@ -26,6 +29,17 @@ declare function omitif(condition: string | ((value: any) => boolean)): Function
26
29
  /**
27
30
  * Property decorator that allows a field to be omitted when a property is null.
28
31
  */
32
+ // @ts-ignore: type
29
33
  declare function omitnull(..._): Function;
30
34
 
31
- declare type Raw = number;
35
+ /**
36
+ * Method decorator that denotes a function to handle that schema's serialization.
37
+ */
38
+ // @ts-ignore: type
39
+ declare function serializer(..._): any;
40
+
41
+ /**
42
+ * Method decorator that denotes a function to handle that schema's deserialization.
43
+ */
44
+ // @ts-ignore: type
45
+ declare function deserializer(..._): any;
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
 
@@ -49,7 +53,8 @@ export namespace JSON {
49
53
  * @param data T
50
54
  * @returns string
51
55
  */
52
- 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 {
53
58
  if (isBoolean<T>()) {
54
59
  if (out) {
55
60
  if (<bool>data == true) {
@@ -112,6 +117,11 @@ export namespace JSON {
112
117
  serializeString(changetype<string>(data));
113
118
  return bs.out<string>();
114
119
  // @ts-ignore: Supplied by transform
120
+ } else if (isDefined(data.__SERIALIZE_CUSTOM)) {
121
+ // @ts-ignore
122
+ data.__SERIALIZE_CUSTOM(changetype<usize>(data));
123
+ return bs.out<string>();
124
+ // @ts-ignore: Supplied by transform
115
125
  } else if (isDefined(data.__SERIALIZE)) {
116
126
  // @ts-ignore
117
127
  data.__SERIALIZE(changetype<usize>(data));
@@ -135,6 +145,9 @@ export namespace JSON {
135
145
  } else if (data instanceof JSON.Value) {
136
146
  serializeArbitrary(data);
137
147
  return bs.out<string>();
148
+ } else if (data instanceof JSON.Obj) {
149
+ serializeObject(data);
150
+ return bs.out<string>();
138
151
  } else if (data instanceof JSON.Box) {
139
152
  return JSON.stringify(data.value);
140
153
  } else {
@@ -150,7 +163,8 @@ export namespace JSON {
150
163
  * @param data string
151
164
  * @returns T
152
165
  */
153
- export function parse<T>(data: string): T {
166
+ // @ts-ignore: inline
167
+ @inline export function parse<T>(data: string): T {
154
168
  const dataSize = bytes(data);
155
169
  const dataPtr = changetype<usize>(data);
156
170
  if (isBoolean<T>()) {
@@ -171,18 +185,31 @@ export namespace JSON {
171
185
  }
172
186
  let type: nonnull<T> = changetype<nonnull<T>>(0);
173
187
  // @ts-ignore: Defined by transform
174
- if (isDefined(type.__DESERIALIZE) && isDefined(type.__INITIALIZE)) {
175
- const out = __new(offsetof<nonnull<T>>(), idof<nonnull<T>>());
188
+ if (isDefined(type.__DESERIALIZE_CUSTOM)) {
189
+ const out = changetype<nonnull<T>>(0);
190
+ // @ts-ignore: Defined by transform
191
+ if (isDefined(type.__INITIALIZE)) out.__INITIALIZE();
176
192
  // @ts-ignore
177
- changetype<nonnull<T>>(out).__INITIALIZE();
193
+ return out.__DESERIALIZE_CUSTOM(ptrToStr(dataPtr, dataPtr + dataSize));
194
+ // @ts-ignore: Defined by transform
195
+ } else if (isDefined(type.__DESERIALIZE)) {
196
+ const out = __new(offsetof<nonnull<T>>(), idof<nonnull<T>>());
197
+ // @ts-ignore: Defined by transform
198
+ if (isDefined(type.__INITIALIZE)) changetype<nonnull<T>>(out).__INITIALIZE();
178
199
  // @ts-ignore
179
- return deserializeObject<nonnull<T>>(dataPtr, dataPtr + dataSize, out);
200
+ return deserializeStruct<nonnull<T>>(dataPtr, dataPtr + dataSize, out);
180
201
  } else if (type instanceof Map) {
181
202
  // @ts-ignore
182
203
  return deserializeMap<nonnull<T>>(dataPtr, dataPtr + dataSize);
183
204
  } else if (type instanceof Date) {
184
205
  // @ts-ignore
185
206
  return deserializeDate(dataPtr, dataPtr + dataSize);
207
+ } else if (type instanceof JSON.Value) {
208
+ // @ts-ignore
209
+ return deserializeArbitrary(dataPtr, dataPtr + dataSize, 0);
210
+ } else if (type instanceof JSON.Obj) {
211
+ // @ts-ignore
212
+ return deserializeObject(dataPtr, dataPtr + dataSize, 0);
186
213
  } else if (type instanceof JSON.Box) {
187
214
  // @ts-ignore
188
215
  return new JSON.Box(parseBox(data, changetype<nonnull<T>>(0).value));
@@ -257,7 +284,7 @@ export namespace JSON {
257
284
  this.type = JSON.Types.U64;
258
285
  store<T>(changetype<usize>(this), value, STORAGE);
259
286
  } else if (value instanceof f32) {
260
- this.type = JSON.Types.F64;
287
+ this.type = JSON.Types.F32;
261
288
  store<T>(changetype<usize>(this), value, STORAGE);
262
289
  } else if (value instanceof f64) {
263
290
  this.type = JSON.Types.F64;
@@ -271,12 +298,22 @@ export namespace JSON {
271
298
  }
272
299
  this.type = JSON.Types.Struct;
273
300
  store<T>(changetype<usize>(this), value, STORAGE);
301
+ // @ts-ignore: supplied by transform
302
+ }else if (isDefined(value.__SERIALIZE_CUSTOM)) {
303
+ this.type = idof<T>() + JSON.Types.Struct;
304
+ // @ts-ignore
305
+ if (!JSON.Value.METHODS.has(idof<T>())) JSON.Value.METHODS.set(idof<T>(), value.__SERIALIZE_CUSTOM.index);
274
306
  // @ts-ignore
307
+ store<usize>(changetype<usize>(this), changetype<usize>(value), STORAGE);
308
+ // @ts-ignore: supplied by transform
275
309
  } else if (isDefined(value.__SERIALIZE)) {
276
310
  this.type = idof<T>() + JSON.Types.Struct;
277
311
  // @ts-ignore
278
312
  if (!JSON.Value.METHODS.has(idof<T>())) JSON.Value.METHODS.set(idof<T>(), value.__SERIALIZE.index);
279
313
  // @ts-ignore
314
+ store<usize>(changetype<usize>(this), changetype<usize>(value), STORAGE);
315
+ } else if (value instanceof JSON.Obj) {
316
+ this.type = JSON.Types.Object;
280
317
  store<T>(changetype<usize>(this), value, STORAGE);
281
318
  // @ts-ignore
282
319
  } else if (isArray<T>() && idof<valueof<T>>() == idof<JSON.Value>()) {
@@ -308,6 +345,10 @@ export namespace JSON {
308
345
  return this.get<u32>().toString();
309
346
  case JSON.Types.U64:
310
347
  return this.get<u64>().toString();
348
+ case JSON.Types.F32:
349
+ return this.get<f32>().toString();
350
+ case JSON.Types.F64:
351
+ return this.get<f64>().toString();
311
352
  case JSON.Types.String:
312
353
  return '"' + this.get<string>() + '"';
313
354
  case JSON.Types.Bool:
@@ -329,15 +370,81 @@ export namespace JSON {
329
370
  out.write("]");
330
371
  return out.toString();
331
372
  }
373
+ case JSON.Types.Object: {
374
+ return JSON.stringify(this.get<JSON.Obj>());
375
+ }
332
376
  default: {
333
377
  const fn = JSON.Value.METHODS.get(this.type - JSON.Types.Struct);
334
378
  const value = this.get<usize>();
335
- return call_indirect<string>(fn, 0, value);
379
+ call_indirect<void>(fn, 0, value);
380
+ return bs.out<string>();
336
381
  }
337
382
  }
338
383
  }
339
384
  }
340
385
 
386
+ export class Obj {
387
+ // When accessing stackSize, subtract 2
388
+ // @ts-ignore: type
389
+ private stackSize: u32 = 6;
390
+ // @ts-ignore: type
391
+ private storage: Map<string, JSON.Value> = new Map<string, JSON.Value>();
392
+
393
+ constructor() { }
394
+
395
+ // @ts-ignore: decorator
396
+ @inline get size(): i32 {
397
+ return this.storage.size;
398
+ }
399
+
400
+ // @ts-ignore: decorator
401
+ @inline set<T>(key: string, value: T): void {
402
+ if (!this.storage.has(key)) this.stackSize += bytes(key) + 8;
403
+ this.storage.set(key, JSON.Value.from<T>(value));
404
+ }
405
+
406
+ // @ts-ignore: decorator
407
+ @inline get(key: string): JSON.Value | null {
408
+ if (!this.storage.has(key)) return null;
409
+ return this.storage.get(key);
410
+ }
411
+
412
+ // @ts-ignore: decorator
413
+ @inline has(key: string): bool {
414
+ return this.storage.has(key);
415
+ }
416
+
417
+ // @ts-ignore: decorator
418
+ @inline delete(key: string): bool {
419
+ return this.storage.delete(key);
420
+ }
421
+
422
+ // @ts-ignore: decorator
423
+ @inline keys(): string[] {
424
+ return this.storage.keys();
425
+ }
426
+
427
+ // @ts-ignore: decorator
428
+ @inline values(): JSON.Value[] {
429
+ return this.storage.values();
430
+ }
431
+
432
+ // @ts-ignore: decorator
433
+ @inline toString(): string {
434
+ return JSON.stringify(this);
435
+ }
436
+
437
+ // @ts-ignore: decorator
438
+ @inline static from<T>(value: T): JSON.Obj {
439
+ if (value instanceof JSON.Obj) return value;
440
+ const out = changetype<JSON.Obj>(__new(offsetof<JSON.Obj>(), idof<JSON.Obj>()));
441
+
442
+ if (value instanceof Map) {
443
+
444
+ }
445
+ return out;
446
+ }
447
+ }
341
448
  /**
342
449
  * Box for primitive types
343
450
  */
@@ -366,7 +473,8 @@ export namespace JSON {
366
473
  }
367
474
  }
368
475
 
369
- export function __serialize<T>(src: T): void {
476
+ // @ts-ignore: inline
477
+ @inline export function __serialize<T>(src: T): void {
370
478
  if (isBoolean<T>()) {
371
479
  serializeBool(src as bool);
372
480
  } else if (isInteger<T>() && nameof<T>() == "usize" && src == 0) {
@@ -387,9 +495,13 @@ export namespace JSON {
387
495
  } else if (isString<nonnull<T>>()) {
388
496
  serializeString(src as string);
389
497
  // @ts-ignore: Supplied by transform
498
+ } else if (isDefined(src.__SERIALIZE_CUSTOM)) {
499
+ // @ts-ignore
500
+ return src.__SERIALIZE_CUSTOM(changetype<nonnull<T>>(src));
501
+ // @ts-ignore: Supplied by transform
390
502
  } else if (isDefined(src.__SERIALIZE)) {
391
503
  // @ts-ignore
392
- serializeObject(changetype<nonnull<T>>(src));
504
+ serializeStruct(changetype<nonnull<T>>(src));
393
505
  } else if (src instanceof Date) {
394
506
  // @ts-ignore
395
507
  serializeDate(changetype<nonnull<T>>(src));
@@ -401,18 +513,22 @@ export namespace JSON {
401
513
  serializeMap(changetype<nonnull<T>>(src));
402
514
  } else if (src instanceof JSON.Value) {
403
515
  serializeArbitrary(src);
516
+ } else if (src instanceof JSON.Obj) {
517
+ serializeObject(src);
404
518
  } else if (src instanceof JSON.Box) {
405
519
  __serialize(src.value);
406
520
  } else {
407
521
  throw new Error(`Could not serialize provided data. Make sure to add the correct decorators to classes.`);
408
522
  }
409
523
  }
410
- export function __deserialize<T>(srcStart: usize, srcEnd: usize, dst: usize = 0): T {
524
+
525
+ // @ts-ignore: inline
526
+ @inline export function __deserialize<T>(srcStart: usize, srcEnd: usize, dst: usize = 0): T {
411
527
  if (isBoolean<T>()) {
412
528
  // @ts-ignore: type
413
529
  return deserializeBoolean(srcStart, srcEnd);
414
530
  } else if (isInteger<T>()) {
415
- return deserializeInteger<T>(srcStart, srcEnd);
531
+ return atoi<T>(srcStart, srcEnd);
416
532
  } else if (isFloat<T>()) {
417
533
  return deserializeFloat<T>(srcStart, srcEnd);
418
534
  } else if (isString<T>()) {
@@ -423,15 +539,25 @@ export namespace JSON {
423
539
  return deserializeArray<T>(srcStart, srcEnd, dst);
424
540
  } else {
425
541
  let type: nonnull<T> = changetype<nonnull<T>>(0);
426
- // @ts-ignore: declared by transform
427
- if (isDefined(type.__DESERIALIZE)) {
428
- return deserializeObject<T>(srcStart, srcEnd, dst);
542
+ // @ts-ignore: Defined by transform
543
+ if (isDefined(type.__DESERIALIZE_CUSTOM)) {
544
+ const out = __new(offsetof<nonnull<T>>(), idof<nonnull<T>>());
545
+ // @ts-ignore: Defined by transform
546
+ if (isDefined(type.__INITIALIZE)) changetype<nonnull<T>>(out).__INITIALIZE();
547
+ // @ts-ignore
548
+ return changetype<nonnull<T>>(out).__DESERIALIZE_CUSTOM(ptrToStr(dataPtr, dataPtr + dataSize));
549
+ // @ts-ignore: Defined by transform
550
+ } else if (isDefined(type.__DESERIALIZE)) {
551
+ return deserializeStruct<T>(srcStart, srcEnd, dst);
429
552
  } else if (type instanceof Map) {
430
553
  // @ts-ignore: type
431
554
  return deserializeMap<T>(srcStart, srcEnd, dst);
432
555
  } else if (type instanceof Date) {
433
556
  // @ts-ignore: type
434
557
  return deserializeDate(srcStart, srcEnd);
558
+ } else if (type instanceof JSON.Value) {
559
+ // @ts-ignore: type
560
+ return deserializeArbitrary(srcStart, srcEnd, 0);
435
561
  } else if (type instanceof JSON.Box) {
436
562
  // @ts-ignore: type
437
563
  return new JSON.Box(deserializeBox(srcStart, srcEnd, dst, changetype<nonnull<T>>(0).value));