json-as 1.3.3 → 1.3.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.
@@ -1,5 +1,5 @@
1
- import { bs, sc } from "../../../lib/as-bs";
2
- import { BACK_SLASH } from "../../custom/chars";
1
+ import { bs } from "../../../lib/as-bs";
2
+ import { BACK_SLASH, QUOTE } from "../../custom/chars";
3
3
  import { SERIALIZE_ESCAPE_TABLE } from "../../globals/tables";
4
4
  import { u16_to_hex4_swar } from "../../util/swar";
5
5
  import { OBJECT, TOTAL_OVERHEAD } from "rt/common";
@@ -11,18 +11,166 @@ import { OBJECT, TOTAL_OVERHEAD } from "rt/common";
11
11
 
12
12
  export function serializeString_SWAR(src: string): void {
13
13
  let srcStart = changetype<usize>(src);
14
+ const srcInitial = srcStart;
15
+ const srcSize = changetype<OBJECT>(srcStart - TOTAL_OVERHEAD).rtSize;
16
+ const srcEnd = srcStart + srcSize;
17
+ do {
18
+ const srcEnd8Fast = srcEnd - 8;
19
+ bs.proposeSize(srcSize + 4);
20
+
21
+ const dstStart = bs.offset;
22
+ let dst = dstStart + 2;
23
+
24
+ while (srcStart < srcEnd8Fast) {
25
+ const block = load<u64>(srcStart);
26
+ if ((block & 0xff00_ff00_ff00_ff00) != 0) break;
27
+ const lo = block & 0x00ff_00ff_00ff_00ff;
28
+ const asciiMask = ((lo - 0x0020_0020_0020_0020) | ((lo ^ 0x0022_0022_0022_0022) - 0x0001_0001_0001_0001) | ((lo ^ 0x005c_005c_005c_005c) - 0x0001_0001_0001_0001)) & (0x0080_0080_0080_0080 & ~lo);
29
+ if (asciiMask != 0) break;
30
+ store<u64>(dst, block);
31
+ srcStart += 8;
32
+ dst += 8;
33
+ }
34
+ if (srcStart < srcEnd8Fast) break;
35
+
36
+ while (srcStart <= srcEnd - 2) {
37
+ const code = load<u16>(srcStart);
38
+ if (code > 0x7f || code == BACK_SLASH || code == QUOTE || code < 32) break;
39
+ store<u16>(dst, code);
40
+ srcStart += 2;
41
+ dst += 2;
42
+ }
43
+ if (srcStart <= srcEnd - 2) break;
44
+
45
+ store<u16>(dstStart, QUOTE);
46
+ store<u16>(dst, QUOTE);
47
+ bs.offset = dst + 2;
48
+ return;
49
+ } while (false);
50
+
51
+ srcStart = srcInitial;
52
+ const srcEnd8 = srcEnd - 8;
53
+
54
+ bs.proposeSize(srcSize + 4);
55
+ store<u16>(bs.offset, 34); // "
56
+ bs.offset += 2;
57
+
58
+ while (srcStart < srcEnd8) {
59
+ const block = load<u64>(srcStart);
60
+ let mask = detect_escapable_u64_swar_safe(block);
61
+ store<u64>(bs.offset, block);
62
+
63
+ if (mask === 0) {
64
+ srcStart += 8;
65
+ bs.offset += 8;
66
+ continue;
67
+ }
68
+
69
+ do {
70
+ const laneIdx = usize(ctz(mask) >> 3);
71
+ const srcIdx = srcStart + laneIdx;
72
+ // Even (0 2 4 6) -> Confirmed ASCII Escape
73
+ // Odd (1 3 5 7) -> Possibly a Unicode code unit or surrogate
74
+ if ((laneIdx & 1) === 0) {
75
+ mask &= mask - 1;
76
+ const code = load<u16>(srcIdx);
77
+ const escaped = load<u32>(SERIALIZE_ESCAPE_TABLE + (code << 2));
78
+
79
+ if ((escaped & 0xffff) != BACK_SLASH) {
80
+ bs.growSize(10);
81
+ const dstIdx = bs.offset + laneIdx;
82
+ store<u64>(dstIdx, U00_MARKER);
83
+ store<u32>(dstIdx, escaped, 8);
84
+ store<u64>(dstIdx, load<u64>(srcIdx, 2), 12);
85
+ bs.offset += 10;
86
+ } else {
87
+ bs.growSize(2);
88
+ const dstIdx = bs.offset + laneIdx;
89
+ store<u32>(dstIdx, escaped);
90
+ store<u64>(dstIdx, load<u64>(srcIdx, 2), 4);
91
+ bs.offset += 2;
92
+ }
93
+ continue;
94
+ }
95
+ mask &= mask - 1;
96
+
97
+ const code = load<u16>(srcIdx - 1);
98
+ if (code < 0xd800 || code > 0xdfff) continue;
99
+
100
+ if (code <= 0xdbff && srcIdx + 2 < srcEnd) {
101
+ const next = load<u16>(srcIdx, 1);
102
+ if (next >= 0xdc00 && next <= 0xdfff) {
103
+ // paired surrogate
104
+ // mask &= ~(0xFF << ((laneIdx+2) << 3));
105
+ mask &= mask - 1;
106
+ continue;
107
+ }
108
+ }
109
+
110
+ bs.growSize(10);
111
+
112
+ // unpaired high/low surrogate
113
+ const dstIdx = bs.offset + laneIdx - 1;
114
+ store<u32>(dstIdx, U_MARKER); // \u
115
+ store<u64>(dstIdx, u16_to_hex4_swar(code), 4);
116
+ store<u64>(dstIdx, load<u64>(srcIdx, 1), 12);
117
+ bs.offset += 10;
118
+ } while (mask !== 0);
119
+
120
+ srcStart += 8;
121
+ bs.offset += 8;
122
+ }
123
+
124
+ while (srcStart <= srcEnd - 2) {
125
+ const code = load<u16>(srcStart);
126
+
127
+ if (code == BACK_SLASH || code == QUOTE || code < 32) {
128
+ const escaped = load<u32>(SERIALIZE_ESCAPE_TABLE + (code << 2));
129
+ if ((escaped & 0xffff) != BACK_SLASH) {
130
+ bs.growSize(10);
131
+ store<u64>(bs.offset, U00_MARKER);
132
+ store<u32>(bs.offset, escaped, 8);
133
+ bs.offset += 12;
134
+ } else {
135
+ bs.growSize(2);
136
+ store<u32>(bs.offset, escaped);
137
+ bs.offset += 4;
138
+ }
139
+ srcStart += 2;
140
+ continue;
141
+ }
142
+
143
+ if (code < 0xd800 || code > 0xdfff) {
144
+ store<u16>(bs.offset, code);
145
+ bs.offset += 2;
146
+ srcStart += 2;
147
+ continue;
148
+ }
14
149
 
15
- if (isDefined(JSON_CACHE)) {
16
- const e = unchecked(sc.entries[i32((srcStart >> 4) & sc.CACHE_MASK)]);
17
- if (e.key == srcStart) {
18
- bs.offset += e.len;
19
- bs.stackSize += e.len;
20
- bs.cacheOutput = e.ptr;
21
- bs.cacheOutputLen = e.len;
22
- return;
150
+ if (code <= 0xdbff && srcStart + 2 <= srcEnd - 2) {
151
+ const next = load<u16>(srcStart, 2);
152
+ if (next >= 0xdc00 && next <= 0xdfff) {
153
+ // valid surrogate pair
154
+ store<u16>(bs.offset, code);
155
+ store<u16>(bs.offset + 2, next);
156
+ bs.offset += 4;
157
+ srcStart += 4;
158
+ continue;
159
+ }
23
160
  }
161
+
162
+ // unpaired high/low surrogate
163
+ write_u_escape(code);
164
+ srcStart += 2;
165
+ continue;
24
166
  }
25
167
 
168
+ store<u16>(bs.offset, 34); // "
169
+ bs.offset += 2;
170
+ }
171
+
172
+ export function serializeString_SWAR_ExperimentalTableEscapes(src: string): void {
173
+ let srcStart = changetype<usize>(src);
26
174
  const srcSize = changetype<OBJECT>(srcStart - TOTAL_OVERHEAD).rtSize;
27
175
  const srcEnd = srcStart + srcSize;
28
176
  const srcEnd8 = srcEnd - 8;
@@ -32,10 +180,9 @@ export function serializeString_SWAR(src: string): void {
32
180
  bs.offset += 2;
33
181
 
34
182
  while (srcStart < srcEnd8) {
35
- let block = load<u64>(srcStart);
36
- store<u64>(bs.offset, block);
37
-
183
+ const block = load<u64>(srcStart);
38
184
  let mask = detect_escapable_u64_swar_safe(block);
185
+ store<u64>(bs.offset, block);
39
186
 
40
187
  if (mask === 0) {
41
188
  srcStart += 8;
@@ -49,7 +196,7 @@ export function serializeString_SWAR(src: string): void {
49
196
  // Even (0 2 4 6) -> Confirmed ASCII Escape
50
197
  // Odd (1 3 5 7) -> Possibly a Unicode code unit or surrogate
51
198
  if ((laneIdx & 1) === 0) {
52
- mask &= ~(0xffff << (laneIdx << 3));
199
+ mask &= mask - 1;
53
200
  const code = load<u16>(srcIdx);
54
201
  const escaped = load<u32>(SERIALIZE_ESCAPE_TABLE + (code << 2));
55
202
 
@@ -69,7 +216,7 @@ export function serializeString_SWAR(src: string): void {
69
216
  }
70
217
  continue;
71
218
  }
72
- mask &= ~(0xffff << (laneIdx << 3));
219
+ mask &= mask - 1;
73
220
 
74
221
  const code = load<u16>(srcIdx - 1);
75
222
  if (code < 0xd800 || code > 0xdfff) continue;
@@ -101,7 +248,7 @@ export function serializeString_SWAR(src: string): void {
101
248
  while (srcStart <= srcEnd - 2) {
102
249
  const code = load<u16>(srcStart);
103
250
 
104
- if (code == 92 || code == 34 || code < 32) {
251
+ if (code == BACK_SLASH || code == QUOTE || code < 32) {
105
252
  const escaped = load<u32>(SERIALIZE_ESCAPE_TABLE + (code << 2));
106
253
  if ((escaped & 0xffff) != BACK_SLASH) {
107
254
  bs.growSize(10);
@@ -144,8 +291,6 @@ export function serializeString_SWAR(src: string): void {
144
291
 
145
292
  store<u16>(bs.offset, 34); // "
146
293
  bs.offset += 2;
147
-
148
- if (isDefined(JSON_CACHE)) sc.insertCached(changetype<usize>(src), srcStart, srcSize);
149
294
  }
150
295
 
151
296
  // @ts-expect-error: @inline is a valid decorator
@@ -158,8 +303,10 @@ export function serializeString_SWAR(src: string): void {
158
303
 
159
304
  // @ts-expect-error: @inline is a valid decorator
160
305
  @inline export function detect_escapable_u64_swar_safe(block: u64): u64 {
306
+ const hi = block & 0xff00_ff00_ff00_ff00;
161
307
  const lo = block & 0x00ff_00ff_00ff_00ff;
162
308
  const ascii_mask = ((lo - 0x0020_0020_0020_0020) | ((lo ^ 0x0022_0022_0022_0022) - 0x0001_0001_0001_0001) | ((lo ^ 0x005c_005c_005c_005c) - 0x0001_0001_0001_0001)) & (0x0080_0080_0080_0080 & ~lo);
309
+ if (hi == 0) return ascii_mask;
163
310
  const hi_mask = ((block - 0x0100_0100_0100_0100) & ~block & 0x8000_8000_8000_8000) ^ 0x8000_8000_8000_8000;
164
311
  return (ascii_mask & (~hi_mask >> 8)) | hi_mask;
165
312
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-as",
3
- "version": "1.3.3",
3
+ "version": "1.3.4",
4
4
  "author": "Jairus Tanaka",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAA4G,eAAe,EAA8G,MAAM,EAAE,OAAO,EAAS,MAAM,EAA6C,MAAM,uCAAuC,CAAC;AAC3X,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAK7D,OAAO,EAA2B,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAE7E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAmJvC,qBAAa,aAAc,SAAQ,OAAO;IACxC,MAAM,CAAC,EAAE,EAAE,aAAa,CAAuB;IAExC,OAAO,EAAG,OAAO,CAAC;IAClB,OAAO,EAAG,MAAM,CAAC;IACjB,MAAM,EAAG,MAAM,CAAC;IAChB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAA+B;IAC7D,MAAM,EAAG,MAAM,CAAC;IAChB,OAAO,EAAE,SAAS,CAAmB;IACrC,OAAO,EAAE,eAAe,EAAE,CAAM;IAChC,cAAc,EAAE,MAAM,EAAE,CAAM;IAE9B,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAqB;IAEvD,OAAO,CAAC,4BAA4B;IA6CpC,wBAAwB,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IAYtD,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,cAAoB,GAAG,MAAM;IAsC3E,qBAAqB,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IAghDnD,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAItC,oBAAoB,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IA4ClD,oBAAoB,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI;IAIjD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI/B,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IA+J9B,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,OAAe,GAAG,MAAM,EAAE;IA0BxD,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO;CAc3D;AA4BD,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,SAAS;IAChD,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAyBvD,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;CAwDjC;AAoKD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO9C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAA4G,eAAe,EAA8G,MAAM,EAAE,OAAO,EAAS,MAAM,EAA6C,MAAM,uCAAuC,CAAC;AAC3X,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAK7D,OAAO,EAA2B,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAE7E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAuJvC,qBAAa,aAAc,SAAQ,OAAO;IACxC,MAAM,CAAC,EAAE,EAAE,aAAa,CAAuB;IAExC,OAAO,EAAG,OAAO,CAAC;IAClB,OAAO,EAAG,MAAM,CAAC;IACjB,MAAM,EAAG,MAAM,CAAC;IAChB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAA+B;IAC7D,MAAM,EAAG,MAAM,CAAC;IAChB,OAAO,EAAE,SAAS,CAAmB;IACrC,OAAO,EAAE,eAAe,EAAE,CAAM;IAChC,cAAc,EAAE,MAAM,EAAE,CAAM;IAE9B,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAqB;IAEvD,OAAO,CAAC,4BAA4B;IA6CpC,wBAAwB,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IAYtD,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,cAAoB,GAAG,MAAM;IAsC3E,qBAAqB,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IAuiDnD,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAItC,oBAAoB,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IA4ClD,oBAAoB,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI;IAIjD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI/B,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IA+J9B,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,OAAe,GAAG,MAAM,EAAE;IA0BxD,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO;CAc3D;AA4BD,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,SAAS;IAChD,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAyBvD,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;CAwDjC;AA+MD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO9C"}
@@ -75,6 +75,9 @@ function getSerializeCall(type, realName) {
75
75
  }
76
76
  return needsReferenceLoad(type) ? `JSON.__serialize<${type}>(changetype<${type}>(load<usize>(ptr, offsetof<this>(${JSON.stringify(realName)}))));\n` : `JSON.__serialize<${type}>(load<${type}>(ptr, offsetof<this>(${JSON.stringify(realName)})));\n`;
77
77
  }
78
+ function isRawType(type) {
79
+ return type == "JSON.Raw" || type == "Raw";
80
+ }
78
81
  const CUSTOM_JSON_KINDS = new Set(["any", "string", "number", "object", "array", "boolean", "null", "any | null", "string | null", "number | null", "object | null", "array | null", "boolean | null"]);
79
82
  function parseCustomJsonKind(method, decoratorName) {
80
83
  const decorator = method.decorators?.find((v) => v.name.text.toLowerCase() == decoratorName);
@@ -498,7 +501,7 @@ export class JSONTransform extends Visitor {
498
501
  mem.type = type;
499
502
  mem.value = value;
500
503
  mem.node = member;
501
- mem.byteSize = sizeof(mem.type);
504
+ mem.byteSize = estimatedSerializedByteSize(mem.type, source, this.parser);
502
505
  mem.custom = schema.deps.some((dep) => dep?.name == stripNull(type) && dep.custom);
503
506
  this.schema.byteSize += mem.byteSize;
504
507
  if (member.decorators) {
@@ -682,8 +685,14 @@ export class JSONTransform extends Visitor {
682
685
  sortedMembers.null.push(member);
683
686
  if (isString(type) || type == "Date")
684
687
  sortedMembers.string.push(member);
685
- else if (type == "JSON.Raw")
688
+ else if (isRawType(type)) {
689
+ sortedMembers.string.push(member);
690
+ sortedMembers.number.push(member);
691
+ sortedMembers.boolean.push(member);
692
+ sortedMembers.null.push(member);
686
693
  sortedMembers.object.push(member);
694
+ sortedMembers.array.push(member);
695
+ }
687
696
  else if (isBoolean(type) || type.startsWith("JSON.Box<bool"))
688
697
  sortedMembers.boolean.push(member);
689
698
  else if (isPrimitive(type) || type.startsWith("JSON.Box<") || isEnum(type, this.sources.get(this.schema.node.range.source), this.parser))
@@ -763,7 +772,7 @@ export class JSONTransform extends Visitor {
763
772
  out.push(` if (load<u16>(${valuePtr}) != 0x22) break;`);
764
773
  out.push(` let dateEnd = ${valuePtr} + 2;`);
765
774
  out.push(` while (dateEnd < srcEnd) {`);
766
- out.push(" if (load<u16>(dateEnd) == 0x22 && load<u16>(dateEnd - 2) != 0x5c) break;");
775
+ out.push(" if (load<u16>(dateEnd) == 0x22 && JSON.Util.isUnescapedQuote(dateEnd)) break;");
767
776
  out.push(" dateEnd += 2;");
768
777
  out.push(" }");
769
778
  out.push(" if (dateEnd >= srcEnd) break;");
@@ -808,7 +817,7 @@ export class JSONTransform extends Visitor {
808
817
  }
809
818
  out.push("}");
810
819
  }
811
- else if (resolvedType == "JSON.Raw") {
820
+ else if (isRawType(resolvedType)) {
812
821
  out.push("{");
813
822
  out.push(` const valueStart = ${srcPtr};`);
814
823
  out.push(" let depth: i32 = 0;");
@@ -816,7 +825,7 @@ export class JSONTransform extends Visitor {
816
825
  out.push(` while (${srcPtr} < srcEnd) {`);
817
826
  out.push(` const code = load<u16>(${srcPtr});`);
818
827
  out.push(" if (inString) {");
819
- out.push(` if (code == 0x22 && load<u16>(${srcPtr} - 2) != 0x5c) inString = false;`);
828
+ out.push(` if (code == 0x22 && JSON.Util.isUnescapedQuote(${srcPtr})) inString = false;`);
820
829
  out.push(` ${srcPtr} += 2;`);
821
830
  out.push(" continue;");
822
831
  out.push(" }");
@@ -1181,7 +1190,7 @@ export class JSONTransform extends Visitor {
1181
1190
  DESERIALIZE += indent + " let code = load<u16>(srcStart);\n";
1182
1191
  DESERIALIZE += indent + " while (JSON.Util.isSpace(code)) code = load<u16>(srcStart += 2);\n";
1183
1192
  DESERIALIZE += indent + " if (keyStart == 0) {\n";
1184
- DESERIALIZE += indent + " if (code == 34 && load<u16>(srcStart - 2) !== 92) {\n";
1193
+ DESERIALIZE += indent + " if (code == 34 && JSON.Util.isUnescapedQuote(srcStart)) {\n";
1185
1194
  DESERIALIZE += indent + " if (isKey) {\n";
1186
1195
  DESERIALIZE += indent + " keyStart = lastIndex;\n";
1187
1196
  DESERIALIZE += indent + " keyEnd = srcStart;\n";
@@ -1286,7 +1295,7 @@ export class JSONTransform extends Visitor {
1286
1295
  DESERIALIZE += " srcStart += 2;\n";
1287
1296
  DESERIALIZE += " while (srcStart < srcEnd) {\n";
1288
1297
  DESERIALIZE += " const code = load<u16>(srcStart);\n";
1289
- DESERIALIZE += " if (code == 34 && load<u16>(srcStart - 2) !== 92) {\n";
1298
+ DESERIALIZE += " if (code == 34 && JSON.Util.isUnescapedQuote(srcStart)) {\n";
1290
1299
  if (DEBUG > 1)
1291
1300
  DESERIALIZE += ' console.log("Value (string, ' + ++id + '): " + JSON.Util.ptrToStr(lastIndex, srcStart + 2));';
1292
1301
  generateGroups(sortedMembers.string, (group) => {
@@ -1385,7 +1394,7 @@ export class JSONTransform extends Visitor {
1385
1394
  DESERIALIZE += " const code = load<u16>(srcStart);\n";
1386
1395
  DESERIALIZE += " if (code == 34) {\n";
1387
1396
  DESERIALIZE += " srcStart += 2;\n";
1388
- DESERIALIZE += " while (!(load<u16>(srcStart) == 34 && load<u16>(srcStart - 2) != 92)) srcStart += 2;\n";
1397
+ DESERIALIZE += " while (!(load<u16>(srcStart) == 34 && JSON.Util.isUnescapedQuote(srcStart))) srcStart += 2;\n";
1389
1398
  DESERIALIZE += " } else if (code == 125) {\n";
1390
1399
  DESERIALIZE += " if (--depth == 0) {\n";
1391
1400
  DESERIALIZE += " srcStart += 2;\n";
@@ -1439,7 +1448,7 @@ export class JSONTransform extends Visitor {
1439
1448
  DESERIALIZE += " const code = load<u16>(srcStart);\n";
1440
1449
  DESERIALIZE += " if (code == 34) {\n";
1441
1450
  DESERIALIZE += " srcStart += 2;\n";
1442
- DESERIALIZE += " while (!(load<u16>(srcStart) == 34 && load<u16>(srcStart - 2) != 92)) srcStart += 2;\n";
1451
+ DESERIALIZE += " while (!(load<u16>(srcStart) == 34 && JSON.Util.isUnescapedQuote(srcStart))) srcStart += 2;\n";
1443
1452
  DESERIALIZE += " } else if (code == 93) {\n";
1444
1453
  DESERIALIZE += " if (--depth == 0) {\n";
1445
1454
  DESERIALIZE += " srcStart += 2;\n";
@@ -1495,7 +1504,10 @@ export class JSONTransform extends Visitor {
1495
1504
  const first = group[0];
1496
1505
  const fName = first.alias || first.name;
1497
1506
  DESERIALIZE += indent + " if (" + (first.generic ? "isBoolean<" + first.type + ">() && " : "") + getComparison(fName) + ") { // " + fName + "\n";
1498
- if (first.type.startsWith("JSON.Box<bool") || first.type.startsWith("JSON.Box<boolean") || first.type.startsWith("Box<bool") || first.type.startsWith("Box<boolean")) {
1507
+ if (isRawType(first.type)) {
1508
+ DESERIALIZE += indent + " store<" + first.type + ">(changetype<usize>(out), JSON.__deserialize<" + first.type + ">(srcStart - 8, srcStart), offsetof<this>(" + JSON.stringify(first.name) + "));\n";
1509
+ }
1510
+ else if (first.type.startsWith("JSON.Box<bool") || first.type.startsWith("JSON.Box<boolean") || first.type.startsWith("Box<bool") || first.type.startsWith("Box<boolean")) {
1499
1511
  DESERIALIZE += indent + " store<" + first.type + ">(changetype<usize>(out), changetype<" + first.type + ">(JSON.Box.from<bool>(true)), offsetof<this>(" + JSON.stringify(first.name) + "));\n";
1500
1512
  }
1501
1513
  else {
@@ -1509,7 +1521,10 @@ export class JSONTransform extends Visitor {
1509
1521
  const mem = group[i];
1510
1522
  const memName = mem.alias || mem.name;
1511
1523
  DESERIALIZE += indent + " else if (" + (mem.generic ? "isBoolean<" + mem.type + ">() && " : "") + getComparison(memName) + ") { // " + memName + "\n";
1512
- if (mem.type.startsWith("JSON.Box<bool") || mem.type.startsWith("JSON.Box<boolean") || mem.type.startsWith("Box<bool") || mem.type.startsWith("Box<boolean")) {
1524
+ if (isRawType(mem.type)) {
1525
+ DESERIALIZE += indent + " store<" + mem.type + ">(changetype<usize>(out), JSON.__deserialize<" + mem.type + ">(srcStart - 8, srcStart), offsetof<this>(" + JSON.stringify(mem.name) + "));\n";
1526
+ }
1527
+ else if (mem.type.startsWith("JSON.Box<bool") || mem.type.startsWith("JSON.Box<boolean") || mem.type.startsWith("Box<bool") || mem.type.startsWith("Box<boolean")) {
1513
1528
  DESERIALIZE += indent + " store<" + mem.type + ">(changetype<usize>(out), changetype<" + mem.type + ">(JSON.Box.from<bool>(true)), offsetof<this>(" + JSON.stringify(mem.name) + "));\n";
1514
1529
  }
1515
1530
  else {
@@ -1549,7 +1564,10 @@ export class JSONTransform extends Visitor {
1549
1564
  const first = group[0];
1550
1565
  const fName = first.alias || first.name;
1551
1566
  DESERIALIZE += indent + " if (" + (first.generic ? "isBoolean<" + first.type + ">() && " : "") + getComparison(fName) + ") { // " + fName + "\n";
1552
- if (first.type.startsWith("JSON.Box<bool") || first.type.startsWith("JSON.Box<boolean") || first.type.startsWith("Box<bool") || first.type.startsWith("Box<boolean")) {
1567
+ if (isRawType(first.type)) {
1568
+ DESERIALIZE += indent + " store<" + first.type + ">(changetype<usize>(out), JSON.__deserialize<" + first.type + ">(srcStart - 10, srcStart), offsetof<this>(" + JSON.stringify(first.name) + "));\n";
1569
+ }
1570
+ else if (first.type.startsWith("JSON.Box<bool") || first.type.startsWith("JSON.Box<boolean") || first.type.startsWith("Box<bool") || first.type.startsWith("Box<boolean")) {
1553
1571
  DESERIALIZE += indent + " store<" + first.type + ">(changetype<usize>(out), changetype<" + first.type + ">(JSON.Box.from<bool>(false)), offsetof<this>(" + JSON.stringify(first.name) + "));\n";
1554
1572
  }
1555
1573
  else {
@@ -1563,7 +1581,10 @@ export class JSONTransform extends Visitor {
1563
1581
  const mem = group[i];
1564
1582
  const memName = mem.alias || mem.name;
1565
1583
  DESERIALIZE += indent + " else if (" + (mem.generic ? "isBoolean<" + mem.type + ">() && " : "") + getComparison(memName) + ") { // " + memName + "\n";
1566
- if (mem.type.startsWith("JSON.Box<bool") || mem.type.startsWith("JSON.Box<boolean") || mem.type.startsWith("Box<bool") || mem.type.startsWith("Box<boolean")) {
1584
+ if (isRawType(mem.type)) {
1585
+ DESERIALIZE += indent + " store<" + mem.type + ">(changetype<usize>(out), JSON.__deserialize<" + mem.type + ">(srcStart - 10, srcStart), offsetof<this>(" + JSON.stringify(mem.name) + "));\n";
1586
+ }
1587
+ else if (mem.type.startsWith("JSON.Box<bool") || mem.type.startsWith("JSON.Box<boolean") || mem.type.startsWith("Box<bool") || mem.type.startsWith("Box<boolean")) {
1567
1588
  DESERIALIZE += indent + " store<" + mem.type + ">(changetype<usize>(out), changetype<" + mem.type + ">(JSON.Box.from<bool>(false)), offsetof<this>(" + JSON.stringify(mem.name) + "));\n";
1568
1589
  }
1569
1590
  else {
@@ -1602,7 +1623,12 @@ export class JSONTransform extends Visitor {
1602
1623
  const first = group[0];
1603
1624
  const fName = first.alias || first.name;
1604
1625
  DESERIALIZE += indent + " if (" + (first.generic ? "isNullable<" + first.type + ">() && " : "") + getComparison(fName) + ") { // " + fName + "\n";
1605
- DESERIALIZE += indent + " store<usize>(changetype<usize>(out), 0, offsetof<this>(" + JSON.stringify(first.name) + "));\n";
1626
+ if (isRawType(first.type) && !first.node.type.isNullable) {
1627
+ DESERIALIZE += indent + " store<" + first.type + ">(changetype<usize>(out), JSON.__deserialize<" + first.type + ">(srcStart - 8, srcStart), offsetof<this>(" + JSON.stringify(first.name) + "));\n";
1628
+ }
1629
+ else {
1630
+ DESERIALIZE += indent + " store<usize>(changetype<usize>(out), 0, offsetof<this>(" + JSON.stringify(first.name) + "));\n";
1631
+ }
1606
1632
  DESERIALIZE += indent + " srcStart += 2;\n";
1607
1633
  DESERIALIZE += indent + " keyStart = 0;\n";
1608
1634
  DESERIALIZE += indent + " break;\n";
@@ -1611,7 +1637,12 @@ export class JSONTransform extends Visitor {
1611
1637
  const mem = group[i];
1612
1638
  const memName = mem.alias || mem.name;
1613
1639
  DESERIALIZE += indent + " else if (" + (mem.generic ? "isNullable<" + mem.type + ">() && " : "") + getComparison(memName) + ") { // " + memName + "\n";
1614
- DESERIALIZE += indent + " store<usize>(changetype<usize>(out), 0, offsetof<this>(" + JSON.stringify(mem.name) + "));\n";
1640
+ if (isRawType(mem.type) && !mem.node.type.isNullable) {
1641
+ DESERIALIZE += indent + " store<" + mem.type + ">(changetype<usize>(out), JSON.__deserialize<" + mem.type + ">(srcStart - 8, srcStart), offsetof<this>(" + JSON.stringify(mem.name) + "));\n";
1642
+ }
1643
+ else {
1644
+ DESERIALIZE += indent + " store<usize>(changetype<usize>(out), 0, offsetof<this>(" + JSON.stringify(mem.name) + "));\n";
1645
+ }
1615
1646
  DESERIALIZE += indent + " srcStart += 2;\n";
1616
1647
  DESERIALIZE += indent + " keyStart = 0;\n";
1617
1648
  DESERIALIZE += indent + " break;\n";
@@ -2104,15 +2135,56 @@ function sizeof(type) {
2104
2135
  return 20;
2105
2136
  else if (type == "i32")
2106
2137
  return 22;
2138
+ else if (type == "usize")
2139
+ return 40;
2140
+ else if (type == "isize")
2141
+ return 42;
2107
2142
  else if (type == "u64")
2108
2143
  return 40;
2109
2144
  else if (type == "i64")
2110
- return 40;
2145
+ return 42;
2146
+ else if (type == "f32")
2147
+ return 34;
2148
+ else if (type == "f64")
2149
+ return 66;
2111
2150
  else if (type == "bool" || type == "boolean")
2112
2151
  return 10;
2113
2152
  else
2114
2153
  return 0;
2115
2154
  }
2155
+ function estimatedSerializedByteSize(type, source, parser) {
2156
+ const trimmed = type.trim();
2157
+ const baseType = stripNull(trimmed);
2158
+ const nullable = trimmed != baseType;
2159
+ let estimated = sizeof(baseType);
2160
+ if (estimated == 0) {
2161
+ if (isEnum(baseType, source, parser)) {
2162
+ estimated = 22;
2163
+ }
2164
+ else if (baseType == "Date") {
2165
+ estimated = 52;
2166
+ }
2167
+ else if (isString(baseType)) {
2168
+ estimated = 4;
2169
+ }
2170
+ else if (isArray(baseType) || baseType.startsWith("Map<")) {
2171
+ estimated = 4;
2172
+ }
2173
+ else if (baseType == "JSON.Obj" || baseType == "Obj" || baseType == "JSON.Raw" || baseType == "Raw" || baseType == "JSON.Value" || baseType == "Value") {
2174
+ estimated = 4;
2175
+ }
2176
+ else if (baseType == "ArrayBuffer" || needsReferenceLoad(baseType)) {
2177
+ estimated = 4;
2178
+ }
2179
+ else {
2180
+ estimated = 4;
2181
+ }
2182
+ }
2183
+ if (nullable) {
2184
+ estimated = Math.max(estimated, 8);
2185
+ }
2186
+ return estimated;
2187
+ }
2116
2188
  function isPrimitive(type) {
2117
2189
  const primitiveTypes = ["u8", "u16", "u32", "u64", "i8", "i16", "i32", "i64", "f32", "f64", "bool", "boolean"];
2118
2190
  return primitiveTypes.some((v) => type.startsWith(v));