json-as 1.3.8 → 1.4.0

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 (84) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +49 -1
  3. package/assembly/deserialize/index/arbitrary.ts +2 -2
  4. package/assembly/deserialize/naive/array/arbitrary.ts +3 -136
  5. package/assembly/deserialize/naive/array/array.ts +30 -1
  6. package/assembly/deserialize/naive/array/integer.ts +1 -6
  7. package/assembly/deserialize/naive/array/map.ts +10 -14
  8. package/assembly/deserialize/naive/array/object.ts +10 -14
  9. package/assembly/deserialize/naive/float.ts +2 -4
  10. package/assembly/deserialize/naive/integer.ts +1 -2
  11. package/assembly/deserialize/naive/map.ts +40 -202
  12. package/assembly/deserialize/naive/object.ts +153 -174
  13. package/assembly/deserialize/naive/set.ts +1 -2
  14. package/assembly/deserialize/naive/staticarray.ts +1 -2
  15. package/assembly/deserialize/naive/string.ts +65 -18
  16. package/assembly/deserialize/naive/typedarray.ts +1 -2
  17. package/assembly/deserialize/naive/unsigned.ts +1 -2
  18. package/assembly/deserialize/simd/array/integer.ts +3 -6
  19. package/assembly/deserialize/simd/float.ts +2 -7
  20. package/assembly/deserialize/simd/integer.ts +4 -8
  21. package/assembly/deserialize/simd/string.ts +16 -21
  22. package/assembly/deserialize/swar/array/array.ts +1 -2
  23. package/assembly/deserialize/swar/array/bool.ts +1 -2
  24. package/assembly/deserialize/swar/array/float.ts +2 -3
  25. package/assembly/deserialize/swar/array/generic.ts +1 -2
  26. package/assembly/deserialize/swar/array/integer.ts +6 -11
  27. package/assembly/deserialize/swar/array/object.ts +1 -2
  28. package/assembly/deserialize/swar/array/shared.ts +3 -8
  29. package/assembly/deserialize/swar/array/string.ts +1 -2
  30. package/assembly/deserialize/swar/array/struct.ts +1 -1
  31. package/assembly/deserialize/swar/float.ts +3 -8
  32. package/assembly/deserialize/swar/integer.ts +4 -8
  33. package/assembly/deserialize/swar/string.ts +29 -41
  34. package/assembly/index.d.ts +248 -15
  35. package/assembly/index.ts +468 -146
  36. package/assembly/serialize/index/object.ts +18 -15
  37. package/assembly/serialize/naive/string.ts +9 -2
  38. package/assembly/serialize/swar/string.ts +1 -2
  39. package/assembly/util/atoi.ts +1 -2
  40. package/assembly/util/dragonbox.ts +0 -8
  41. package/assembly/util/itoa-fast.ts +3 -6
  42. package/assembly/util/parsefloat-fast.ts +1 -2
  43. package/assembly/util/scanValueEnd.ts +1 -2
  44. package/assembly/util/scanValueEndSimd.ts +160 -0
  45. package/assembly/util/scanValueEndSwar.ts +142 -0
  46. package/assembly/util/scientific.ts +3 -6
  47. package/assembly/util/simd-int.ts +4 -8
  48. package/assembly/util/snp.ts +1 -5
  49. package/assembly/util/stringScan.ts +2 -4
  50. package/assembly/util/swar-int.ts +3 -6
  51. package/lib/as-bs.ts +37 -0
  52. package/package.json +14 -4
  53. package/transform/lib/builder.d.ts +0 -1
  54. package/transform/lib/builder.js +0 -1
  55. package/transform/lib/index.d.ts +0 -1
  56. package/transform/lib/index.js +537 -290
  57. package/transform/lib/linkers/alias.d.ts +0 -1
  58. package/transform/lib/linkers/alias.js +0 -1
  59. package/transform/lib/linkers/custom.d.ts +0 -1
  60. package/transform/lib/linkers/custom.js +0 -1
  61. package/transform/lib/linkers/imports.d.ts +0 -1
  62. package/transform/lib/linkers/imports.js +0 -1
  63. package/transform/lib/types.d.ts +3 -2
  64. package/transform/lib/types.js +2 -1
  65. package/transform/lib/util.d.ts +0 -1
  66. package/transform/lib/util.js +0 -1
  67. package/transform/lib/visitor.d.ts +0 -1
  68. package/transform/lib/visitor.js +0 -1
  69. package/transform/lib/builder.d.ts.map +0 -1
  70. package/transform/lib/builder.js.map +0 -1
  71. package/transform/lib/index.d.ts.map +0 -1
  72. package/transform/lib/index.js.map +0 -1
  73. package/transform/lib/linkers/alias.d.ts.map +0 -1
  74. package/transform/lib/linkers/alias.js.map +0 -1
  75. package/transform/lib/linkers/custom.d.ts.map +0 -1
  76. package/transform/lib/linkers/custom.js.map +0 -1
  77. package/transform/lib/linkers/imports.d.ts.map +0 -1
  78. package/transform/lib/linkers/imports.js.map +0 -1
  79. package/transform/lib/types.d.ts.map +0 -1
  80. package/transform/lib/types.js.map +0 -1
  81. package/transform/lib/util.d.ts.map +0 -1
  82. package/transform/lib/util.js.map +0 -1
  83. package/transform/lib/visitor.d.ts.map +0 -1
  84. package/transform/lib/visitor.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  import { Node, Type, } from "assemblyscript/dist/assemblyscript.js";
2
2
  import { Transform } from "assemblyscript/dist/transform.js";
3
- import { readFileSync, writeFileSync } from "fs";
3
+ import { writeFileSync } from "fs";
4
4
  import * as path from "path";
5
5
  import { fileURLToPath } from "url";
6
6
  import { CustomTransform } from "./linkers/custom.js";
@@ -301,10 +301,124 @@ export class JSONTransform extends Visitor {
301
301
  return;
302
302
  if (!this.schemas.has(source.internalPath))
303
303
  this.schemas.set(source.internalPath, []);
304
+ const lazyInner = new Map();
305
+ const lazyMode = classLazyMode(node);
306
+ const hasCustomSerde = node.members.some((m) => m.kind === NodeKind.MethodDeclaration &&
307
+ (m.decorators?.some((d) => {
308
+ const t = d.name.text.toLowerCase();
309
+ return t === "serializer" || t === "deserializer";
310
+ }) ??
311
+ false));
312
+ let __hasLazy = false;
313
+ for (let i = node.members.length - 1; i >= 0; i--) {
314
+ const fd = node.members[i];
315
+ if (fd.kind !== NodeKind.FieldDeclaration ||
316
+ fd.is(32) ||
317
+ fd.is(512) ||
318
+ fd.is(1024) ||
319
+ !fd.type)
320
+ continue;
321
+ const written = toString(fd.type).trim();
322
+ const decos = fd.decorators;
323
+ const hasDeco = (name) => decos?.some((d) => d.name.text === name) ??
324
+ false;
325
+ let inner = lazyWrapperInner(fd.type);
326
+ if (inner === null) {
327
+ if (hasDeco("lazy")) {
328
+ inner = written;
329
+ }
330
+ else if (lazyMode !== "none" &&
331
+ !hasDeco("eager") &&
332
+ !hasDeco("omit")) {
333
+ if (lazyMode === "all")
334
+ inner = written;
335
+ else if (lazyAutoCost(this.resolveType(written, source), source, this.parser) >= LAZY_AUTO_THRESHOLD)
336
+ inner = written;
337
+ }
338
+ }
339
+ if (inner === null)
340
+ continue;
341
+ if (hasCustomSerde)
342
+ throwError("Lazy fields (@lazy / JSON.Lazy<T> / @json({ lazy })) are not supported " +
343
+ "on a class with a custom @serializer/@deserializer — the custom methods " +
344
+ "bypass the generated (de)serializer, so the deferred slot is never filled. " +
345
+ "Remove the lazy marker or the custom (de)serializer.", fd.range);
346
+ const fname = fd.name.text;
347
+ const key = JSON.stringify(fname);
348
+ const T = inner;
349
+ const baseT = stripNull(T);
350
+ const storesScalar = isPrimitive(baseT) || isEnum(baseT, source, this.parser);
351
+ const valueType = storesScalar || baseT != T ? T : `${T} | null`;
352
+ const valueDefault = isBoolean(baseT)
353
+ ? "false"
354
+ : storesScalar
355
+ ? "0"
356
+ : "null";
357
+ const fdInit = fd.initializer;
358
+ const fieldDefault = fdInit ? toString(fdInit) : null;
359
+ __hasLazy = true;
360
+ const omitIfDeco = decos?.find((d) => d.name.text === "omitif");
361
+ lazyInner.set("__" + fname + "_lz", {
362
+ inner: T,
363
+ valueType,
364
+ omitNull: hasDeco("omitnull"),
365
+ omitIf: omitIfDeco?.args?.[0] ?? null,
366
+ });
367
+ const packScalar = baseT === "i8" ||
368
+ baseT === "u8" ||
369
+ baseT === "i16" ||
370
+ baseT === "u16" ||
371
+ baseT === "i32" ||
372
+ baseT === "u32" ||
373
+ baseT === "bool" ||
374
+ baseT === "boolean" ||
375
+ baseT === "f32";
376
+ const encVal = (v) => baseT === "f32"
377
+ ? `(<u64>reinterpret<u32>(${v}))`
378
+ : `(<u64><u32>(${v}))`;
379
+ const decSlot = (lz) => baseT === "f32"
380
+ ? `reinterpret<f32>(<u32>(${lz}))`
381
+ : `(<${T}>(<u32>(${lz})))`;
382
+ const lowered = (packScalar
383
+ ? [
384
+ `@alias(${key}) private __${fname}_lz: u64 = ${fieldDefault != null
385
+ ? `(((<u64>0xffffffff) << 32) | ${encVal(`<${T}>(${fieldDefault})`)})`
386
+ : "0"};`,
387
+ `get ${fname}(): ${T} {\n` +
388
+ ` const __lz = this.__${fname}_lz;\n` +
389
+ ` if ((__lz >>> 32) == 0xffffffff) return ${decSlot("__lz")};\n` +
390
+ ` if (__lz != 0) {\n` +
391
+ ` const __v = JSON.__deserialize<${T}>(<usize>(__lz >>> 32), <usize>(<u32>__lz));\n` +
392
+ ` this.__${fname}_lz = ((<u64>0xffffffff) << 32) | ${encVal("__v")};\n` +
393
+ ` return __v;\n` +
394
+ ` }\n` +
395
+ ` return ${valueDefault};\n}`,
396
+ `set ${fname}(value: ${T}) {\n` +
397
+ ` this.__${fname}_lz = ((<u64>0xffffffff) << 32) | ${encVal("value")};\n}`,
398
+ ]
399
+ : [
400
+ `@alias(${key}) private __${fname}_lz: u64 = ${fieldDefault != null ? "u64.MAX_VALUE" : "0"};`,
401
+ `private __${fname}_val: ${valueType} = ${fieldDefault ?? valueDefault};`,
402
+ `get ${fname}(): ${T} {\n` +
403
+ ` const __lz = this.__${fname}_lz;\n` +
404
+ ` if (__lz != 0 && __lz != u64.MAX_VALUE) {\n` +
405
+ ` this.__${fname}_val = JSON.__deserialize<${T}>(<usize>(__lz >>> 32), <usize>(<u32>__lz));\n` +
406
+ ` this.__${fname}_lz = u64.MAX_VALUE;\n` +
407
+ ` }\n` +
408
+ ` return this.__${fname}_val as ${T};\n}`,
409
+ `set ${fname}(value: ${T}) {\n` +
410
+ ` this.__${fname}_val = value;\n` +
411
+ ` this.__${fname}_lz = u64.MAX_VALUE;\n}`,
412
+ ]).map((src) => SimpleParser.parseClassMember(src, node));
413
+ node.members.splice(i, 1, ...lowered);
414
+ }
415
+ if (__hasLazy) {
416
+ node.members.push(SimpleParser.parseClassMember(`private __src: string = "";`, node), SimpleParser.parseClassMember(`__SET_SRC(s: string): void { this.__src = s; }`, node));
417
+ }
304
418
  const members = [
305
419
  ...node.members.filter((v) => v.kind === NodeKind.FieldDeclaration &&
306
420
  !v.is(32) &&
307
- !v.is(512) &&
421
+ (!v.is(512) || lazyInner.has(v.name.text)) &&
308
422
  !v.is(1024) &&
309
423
  !v.decorators?.some((decorator) => decorator.name.text === "omit")),
310
424
  ];
@@ -549,8 +663,7 @@ export class JSONTransform extends Visitor {
549
663
  this.schemas.get(source.internalPath).push(schema);
550
664
  this.schema = schema;
551
665
  this.visitedClasses.add(fullClassPath);
552
- const codegenMode = getCodegenMode(this.program);
553
- const requestedFastPath = USE_FAST_PATH && codegenMode !== JSONMode.NAIVE;
666
+ const requestedFastPath = USE_FAST_PATH;
554
667
  let SERIALIZE = "__SERIALIZE(ptr: usize): void {\n";
555
668
  let INITIALIZE = "@inline __INITIALIZE(): this {\n";
556
669
  let DESERIALIZE = "__DESERIALIZE_SLOW<__JSON_T>(srcStart: usize, srcEnd: usize, out: __JSON_T): usize {\n";
@@ -663,9 +776,7 @@ export class JSONTransform extends Visitor {
663
776
  DESERIALIZE_CUSTOM +=
664
777
  " @inline __DESERIALIZE_CUSTOM(data: string): this {\n";
665
778
  DESERIALIZE_CUSTOM +=
666
- " return inline.always(this." +
667
- deserializer.name.text +
668
- "(data));\n";
779
+ " return this." + deserializer.name.text + "(data);\n";
669
780
  DESERIALIZE_CUSTOM += " }\n";
670
781
  }
671
782
  if (!members.length && !deserializers.length && !serializers.length) {
@@ -689,6 +800,19 @@ export class JSONTransform extends Visitor {
689
800
  mem.node = member;
690
801
  mem.byteSize = estimatedSerializedByteSize(mem.type, source, this.parser);
691
802
  mem.custom = schema.deps.some((dep) => dep?.name == stripNull(type) && dep.custom);
803
+ const lzInner = lazyInner.get(name.text);
804
+ if (lzInner !== undefined) {
805
+ mem.flags.set(PropertyFlags.Lazy, null);
806
+ mem.lazyInner = lzInner.inner;
807
+ if (lzInner.omitNull) {
808
+ mem.flags.set(PropertyFlags.OmitNull, null);
809
+ this.schema.static = false;
810
+ }
811
+ if (lzInner.omitIf) {
812
+ mem.flags.set(PropertyFlags.OmitIf, lzInner.omitIf);
813
+ this.schema.static = false;
814
+ }
815
+ }
692
816
  this.schema.byteSize += mem.byteSize;
693
817
  if (member.decorators) {
694
818
  for (const decorator of member.decorators) {
@@ -738,6 +862,7 @@ export class JSONTransform extends Visitor {
738
862
  const hasOmitIfMembers = this.schema.members.some((v) => v.flags.has(PropertyFlags.OmitIf));
739
863
  const hasOmitNullMembers = this.schema.members.some((v) => v.flags.has(PropertyFlags.OmitNull));
740
864
  const hasOptionalMembers = hasOmitIfMembers || hasOmitNullMembers;
865
+ const hasLazyMembers = this.schema.members.some((v) => v.flags.has(PropertyFlags.Lazy));
741
866
  const supportsFastOptionalPath = requestedFastPath && hasOptionalMembers;
742
867
  const hasTypeParams = !!node.typeParameters && node.typeParameters.length > 0;
743
868
  const useFastPath = requestedFastPath &&
@@ -748,6 +873,9 @@ export class JSONTransform extends Visitor {
748
873
  if (this.schema.members.some((v) => v.flags.has(PropertyFlags.OmitNull))) {
749
874
  SERIALIZE += indent + "let block: usize = 0;\n";
750
875
  }
876
+ if (hasOptionalMembers) {
877
+ SERIALIZE += indent + "let wrote = false;\n";
878
+ }
751
879
  this.schema.byteSize += 2;
752
880
  SERIALIZE += indent + "store<u16>(bs.offset, 123, 0); // {\n";
753
881
  SERIALIZE += indent + "bs.offset += 2;\n";
@@ -755,11 +883,64 @@ export class JSONTransform extends Visitor {
755
883
  const isPure = this.schema.static;
756
884
  let isRegular = isPure;
757
885
  let isFirst = true;
886
+ const serValue = (member, realName) => {
887
+ if (!member.flags.has(PropertyFlags.Lazy))
888
+ return getSerializeCall(member.type, realName);
889
+ const T = member.lazyInner;
890
+ const baseName = realName.slice(0, -3);
891
+ const baseT = stripNull(T);
892
+ const packScalar = baseT === "i8" ||
893
+ baseT === "u8" ||
894
+ baseT === "i16" ||
895
+ baseT === "u16" ||
896
+ baseT === "i32" ||
897
+ baseT === "u32" ||
898
+ baseT === "bool" ||
899
+ baseT === "boolean" ||
900
+ baseT === "f32";
901
+ if (packScalar) {
902
+ const dec = baseT === "f32"
903
+ ? `reinterpret<f32>(<u32>(__s))`
904
+ : `(<${T}>(<u32>(__s)))`;
905
+ const def = baseT === "bool" || baseT === "boolean" ? "false" : "0";
906
+ return (`{\n` +
907
+ ` const __s = this.${realName};\n` +
908
+ ` if ((__s >>> 32) == 0xffffffff) {\n` +
909
+ ` JSON.__serialize<${T}>(${dec});\n` +
910
+ ` } else if (__s != 0) {\n` +
911
+ ` const __hi = <usize>(__s >>> 32);\n` +
912
+ ` const __len = (<usize>(<u32>__s)) - __hi;\n` +
913
+ ` bs.ensureSize(<u32>__len);\n` +
914
+ ` memory.copy(bs.offset, __hi, __len);\n` +
915
+ ` bs.offset += __len;\n` +
916
+ ` } else {\n` +
917
+ ` JSON.__serialize<${T}>(${def});\n` +
918
+ ` }\n` +
919
+ `}\n`);
920
+ }
921
+ return (`{\n` +
922
+ ` const __s = this.${realName};\n` +
923
+ ` if (__s == u64.MAX_VALUE) {\n` +
924
+ ` JSON.__serialize<${T}>(this.${baseName}_val as ${T});\n` +
925
+ ` } else if (__s != 0) {\n` +
926
+ ` const __hi = <usize>(__s >>> 32);\n` +
927
+ ` const __len = (<usize>(<u32>__s)) - __hi;\n` +
928
+ ` bs.ensureSize(<u32>__len);\n` +
929
+ ` memory.copy(bs.offset, __hi, __len);\n` +
930
+ ` bs.offset += __len;\n` +
931
+ ` } else {\n` +
932
+ (isPrimitive(baseT)
933
+ ? ` JSON.__serialize<${T}>(0);\n`
934
+ : ` bs.ensureSize(8);\n` +
935
+ ` store<u64>(bs.offset, 0x006c006c0075006e);\n` +
936
+ ` bs.offset += 8;\n`) +
937
+ ` }\n` +
938
+ `}\n`);
939
+ };
758
940
  for (let i = 0; i < this.schema.members.length; i++) {
759
941
  const member = this.schema.members[i];
760
942
  const aliasName = JSON.stringify(member.alias || member.name);
761
943
  const realName = member.name;
762
- const isLast = i == this.schema.members.length - 1;
763
944
  if (member.value) {
764
945
  if (member.value != "null" &&
765
946
  member.value != "0" &&
@@ -801,40 +982,69 @@ export class JSONTransform extends Visitor {
801
982
  if (isRegular && isPure) {
802
983
  const keyPart = (isFirst ? "{" : ",") + aliasName + ":";
803
984
  this.schema.byteSize += keyPart.length << 1;
985
+ if (hasLazyMembers)
986
+ SERIALIZE += indent + `bs.ensureSize(${keyPart.length << 1});\n`;
804
987
  SERIALIZE += this.getStores(keyPart, SIMD_ENABLED)
805
988
  .map((v) => indent + v + "\n")
806
989
  .join("");
807
- SERIALIZE += indent + getSerializeCall(member.type, realName);
990
+ SERIALIZE += indent + serValue(member, realName);
808
991
  if (isFirst)
809
992
  isFirst = false;
810
993
  }
811
994
  else if (isRegular && !isPure) {
812
- const keyPart = (isFirst ? "" : ",") + aliasName + ":";
813
- this.schema.byteSize += keyPart.length << 1;
814
- SERIALIZE += this.getStores(keyPart, SIMD_ENABLED)
815
- .map((v) => indent + v + "\n")
816
- .join("");
817
- SERIALIZE += indent + getSerializeCall(member.type, realName);
995
+ if (isFirst && hasOptionalMembers) {
996
+ const keyPart = aliasName + ":";
997
+ this.schema.byteSize += 2 + (keyPart.length << 1);
998
+ SERIALIZE +=
999
+ indent +
1000
+ "if (wrote) { store<u16>(bs.offset, 44, 0); bs.offset += 2; } // ,\n";
1001
+ if (hasLazyMembers)
1002
+ SERIALIZE += indent + `bs.ensureSize(${keyPart.length << 1});\n`;
1003
+ SERIALIZE += this.getStores(keyPart, SIMD_ENABLED)
1004
+ .map((v) => indent + v + "\n")
1005
+ .join("");
1006
+ SERIALIZE += indent + serValue(member, realName);
1007
+ }
1008
+ else {
1009
+ const keyPart = (isFirst ? "" : ",") + aliasName + ":";
1010
+ this.schema.byteSize += keyPart.length << 1;
1011
+ if (hasLazyMembers)
1012
+ SERIALIZE += indent + `bs.ensureSize(${keyPart.length << 1});\n`;
1013
+ SERIALIZE += this.getStores(keyPart, SIMD_ENABLED)
1014
+ .map((v) => indent + v + "\n")
1015
+ .join("");
1016
+ SERIALIZE += indent + serValue(member, realName);
1017
+ }
818
1018
  if (isFirst)
819
1019
  isFirst = false;
820
1020
  }
821
1021
  else {
822
1022
  if (member.flags.has(PropertyFlags.OmitNull)) {
823
- SERIALIZE +=
824
- indent +
825
- `if ((block = load<usize>(ptr, offsetof<this>(${JSON.stringify(realName)}))) !== 0) {\n`;
1023
+ let omitNullCond;
1024
+ if (member.flags.has(PropertyFlags.Lazy)) {
1025
+ const base = realName.slice(0, -3);
1026
+ omitNullCond =
1027
+ `!JSON.__lazyIsNull(` +
1028
+ `load<usize>(ptr, offsetof<this>(${JSON.stringify(base + "_val")})), ` +
1029
+ `load<u64>(ptr, offsetof<this>(${JSON.stringify(realName)})))`;
1030
+ }
1031
+ else {
1032
+ omitNullCond = `(block = load<usize>(ptr, offsetof<this>(${JSON.stringify(realName)}))) !== 0`;
1033
+ }
1034
+ SERIALIZE += indent + `if (${omitNullCond}) {\n`;
826
1035
  indentInc();
827
1036
  const keyPart = aliasName + ":";
828
- this.schema.byteSize += keyPart.length << 1;
1037
+ this.schema.byteSize += 2 + (keyPart.length << 1);
1038
+ SERIALIZE +=
1039
+ indent +
1040
+ "if (wrote) { store<u16>(bs.offset, 44, 0); bs.offset += 2; } // ,\n";
1041
+ if (hasLazyMembers)
1042
+ SERIALIZE += indent + `bs.ensureSize(${keyPart.length << 1});\n`;
829
1043
  SERIALIZE += this.getStores(keyPart, SIMD_ENABLED)
830
1044
  .map((v) => indent + v + "\n")
831
1045
  .join("");
832
- SERIALIZE += indent + getSerializeCall(member.type, realName);
833
- if (!isLast) {
834
- this.schema.byteSize += 2;
835
- SERIALIZE += indent + `store<u16>(bs.offset, 44, 0); // ,\n`;
836
- SERIALIZE += indent + `bs.offset += 2;\n`;
837
- }
1046
+ SERIALIZE += indent + serValue(member, realName);
1047
+ SERIALIZE += indent + "wrote = true;\n";
838
1048
  indentDec();
839
1049
  this.schema.byteSize += 2;
840
1050
  SERIALIZE += indent + `}\n`;
@@ -860,15 +1070,15 @@ export class JSONTransform extends Visitor {
860
1070
  SERIALIZE += indent + `if (!(${rendered})) {\n`;
861
1071
  }
862
1072
  indentInc();
1073
+ this.schema.byteSize += 2;
1074
+ SERIALIZE +=
1075
+ indent +
1076
+ "if (wrote) { store<u16>(bs.offset, 44, 0); bs.offset += 2; } // ,\n";
863
1077
  SERIALIZE += this.getStores(aliasName + ":", SIMD_ENABLED)
864
1078
  .map((v) => indent + v + "\n")
865
1079
  .join("");
866
- SERIALIZE += indent + getSerializeCall(member.type, realName);
867
- if (!isLast) {
868
- this.schema.byteSize += 2;
869
- SERIALIZE += indent + `store<u16>(bs.offset, 44, 0); // ,\n`;
870
- SERIALIZE += indent + `bs.offset += 2;\n`;
871
- }
1080
+ SERIALIZE += indent + serValue(member, realName);
1081
+ SERIALIZE += indent + "wrote = true;\n";
872
1082
  indentDec();
873
1083
  SERIALIZE += indent + `}\n`;
874
1084
  }
@@ -912,6 +1122,23 @@ export class JSONTransform extends Visitor {
912
1122
  sortedMembers.object.push(member);
913
1123
  }
914
1124
  }
1125
+ const lazyMembers = this.schema.members.filter((member) => member.flags.has(PropertyFlags.Lazy));
1126
+ const withLazyMembers = (members) => {
1127
+ if (!lazyMembers.length)
1128
+ return members;
1129
+ const out = members.slice();
1130
+ for (const member of lazyMembers) {
1131
+ if (!out.includes(member))
1132
+ out.push(member);
1133
+ }
1134
+ return out;
1135
+ };
1136
+ const slowStringMembers = withLazyMembers(sortedMembers.string);
1137
+ const slowNumberMembers = withLazyMembers(sortedMembers.number);
1138
+ const slowObjectMembers = withLazyMembers(sortedMembers.object);
1139
+ const slowArrayMembers = withLazyMembers(sortedMembers.array);
1140
+ const slowBooleanMembers = withLazyMembers(sortedMembers.boolean);
1141
+ const slowNullMembers = withLazyMembers(sortedMembers.null);
915
1142
  const getComparisions = (data, ptr, operator) => {
916
1143
  const dataBytes = data.length << 1;
917
1144
  let offset = 0;
@@ -952,6 +1179,17 @@ export class JSONTransform extends Visitor {
952
1179
  const resolvedSchema = this.getSchema(resolvedType);
953
1180
  const fieldOffset = `offsetof<this>(${JSON.stringify(member.name)})`;
954
1181
  const valuePtr = keyOffset ? `${srcPtr} + ${keyOffset}` : srcPtr;
1182
+ if (member.flags.has(PropertyFlags.Lazy)) {
1183
+ const lazyInner = member.lazyInner;
1184
+ out.push("{");
1185
+ out.push(` const valueStart = JSON.Util.skipWhitespace(${valuePtr}, srcEnd);`);
1186
+ out.push(` const valueEnd = JSON.Util.scanValueEnd<${lazyInner}>(valueStart, srcEnd);`);
1187
+ out.push(" if (!valueEnd) break;");
1188
+ out.push(` store<u64>(${outPtr}, ((<u64>valueStart) << 32) | (<u64>(<u32>valueEnd)), ${fieldOffset});`);
1189
+ out.push(` ${srcPtr} = valueEnd;`);
1190
+ out.push("}");
1191
+ return out;
1192
+ }
955
1193
  if (INTEGER_TYPES.includes(resolvedType)) {
956
1194
  const helper = SIGNED_INTEGER_TYPES.includes(resolvedType)
957
1195
  ? "__deserializeIntegerField"
@@ -1121,7 +1359,7 @@ export class JSONTransform extends Visitor {
1121
1359
  out.push(` store<${resolvedType}>(${outPtr}, value, ${fieldOffset});`);
1122
1360
  out.push(" }");
1123
1361
  out.push(` const valueStart = ${valuePtr};`);
1124
- out.push(` const valueEnd = JSON.Util.scanValueEnd(valueStart, srcEnd);`);
1362
+ out.push(` const valueEnd = JSON.Util.scanValueEnd<${resolvedType}>(valueStart, srcEnd);`);
1125
1363
  out.push(" if (!valueEnd) break;");
1126
1364
  if (fastPath) {
1127
1365
  out.push(` ${srcPtr} = changetype<nonnull<${resolvedType}>>(value).__DESERIALIZE_FAST<${resolvedType}>(valueStart, valueEnd, value);`);
@@ -1273,6 +1511,50 @@ export class JSONTransform extends Visitor {
1273
1511
  return out;
1274
1512
  };
1275
1513
  indent = " ";
1514
+ const FAST_CHUNK_SIZE = 32;
1515
+ const fastChunkMethods = [];
1516
+ let fastChunkId = 0;
1517
+ const chunkFastBlocks = (blocks, tag, callIndent) => {
1518
+ if (blocks.length <= FAST_CHUNK_SIZE)
1519
+ return blocks.join("");
1520
+ let calls = "";
1521
+ for (let c = 0; c < blocks.length; c += FAST_CHUNK_SIZE) {
1522
+ const name = `__DESERIALIZE_FAST_${tag}_${fastChunkId++}`;
1523
+ const body = blocks
1524
+ .slice(c, c + FAST_CHUNK_SIZE)
1525
+ .join("")
1526
+ .replace(/\bbreak;/g, "return 0;");
1527
+ fastChunkMethods.push(`${name}(srcStart: usize, srcEnd: usize, dst: usize): usize {\n${body}\n return srcStart;\n}`);
1528
+ calls +=
1529
+ `${callIndent}srcStart = this.${name}(srcStart, srcEnd, dst);\n` +
1530
+ `${callIndent}if (srcStart == 0) break;\n`;
1531
+ }
1532
+ return calls;
1533
+ };
1534
+ const chunkFastBlocksOptional = (blocks, tag, callIndent, needsKp) => {
1535
+ if (blocks.length <= FAST_CHUNK_SIZE)
1536
+ return blocks.join("");
1537
+ let calls = "";
1538
+ for (let c = 0; c < blocks.length; c += FAST_CHUNK_SIZE) {
1539
+ const name = `__DESERIALIZE_FAST_${tag}_${fastChunkId++}`;
1540
+ const body = blocks
1541
+ .slice(c, c + FAST_CHUNK_SIZE)
1542
+ .join("")
1543
+ .replace(/\bbreak;/g, "return 0;");
1544
+ fastChunkMethods.push(`${name}(srcStart: usize, srcEnd: usize, dst: usize, seenAny: bool): u64 {\n` +
1545
+ (needsKp ? " let kp: usize = 0;\n" : "") +
1546
+ `${body}\n` +
1547
+ ` return (<u64>srcStart) | ((<u64>(seenAny ? 1 : 0)) << 32);\n}`);
1548
+ calls +=
1549
+ `${callIndent}{\n` +
1550
+ `${callIndent} const __r = this.${name}(srcStart, srcEnd, dst, seenAny);\n` +
1551
+ `${callIndent} if (__r == 0) break;\n` +
1552
+ `${callIndent} srcStart = <usize>(<u32>__r);\n` +
1553
+ `${callIndent} seenAny = (<u32>(__r >>> 32)) != 0;\n` +
1554
+ `${callIndent}}\n`;
1555
+ }
1556
+ return calls;
1557
+ };
1276
1558
  DESERIALIZE_FAST += indent + "const start = srcStart;\n";
1277
1559
  DESERIALIZE_FAST += indent + "const dst = changetype<usize>(out);\n";
1278
1560
  DESERIALIZE_FAST += indent + "do {\n";
@@ -1282,6 +1564,7 @@ export class JSONTransform extends Visitor {
1282
1564
  indent + "if (load<u16>(srcStart) !== 0x7b) break; // {\n";
1283
1565
  DESERIALIZE_FAST += indent + "srcStart += 2;\n";
1284
1566
  DESERIALIZE_FAST += indent + "let seenAny = false;\n\n";
1567
+ const t1opt = [];
1285
1568
  for (let i = 0; i < this.schema.members.length; i++) {
1286
1569
  const member = this.schema.members[i];
1287
1570
  const key = JSON.stringify(member.alias || member.name);
@@ -1298,89 +1581,92 @@ export class JSONTransform extends Visitor {
1298
1581
  const isOptional = member.flags.has(PropertyFlags.OmitNull) ||
1299
1582
  member.flags.has(PropertyFlags.OmitIf);
1300
1583
  if (!deserializerFirst.length || !deserializerNext.length) {
1301
- DESERIALIZE_FAST += indent + "break;\n\n";
1584
+ t1opt.push(indent + "break;\n\n");
1302
1585
  continue;
1303
1586
  }
1304
- DESERIALIZE_FAST += indent + "if (!seenAny) {\n";
1587
+ let blk = indent + "if (!seenAny) {\n";
1305
1588
  indent += " ";
1306
- DESERIALIZE_FAST +=
1589
+ blk +=
1307
1590
  indent +
1308
1591
  `if ( // ${firstKeySection}\n${(indent += " ")}${getComparisions(firstKeySection, "srcStart", "!=").join("\n" + indent + "|| ")}\n${(indent = indent.slice(0, -2))}) {\n`;
1309
1592
  indent += " ";
1310
1593
  if (isOptional) {
1311
- DESERIALIZE_FAST += indent + "// optional @omitnull field omitted\n";
1594
+ blk += indent + "// optional @omitnull field omitted\n";
1312
1595
  }
1313
1596
  else {
1314
- DESERIALIZE_FAST += indent + "break;\n";
1597
+ blk += indent + "break;\n";
1315
1598
  }
1316
1599
  indent = indent.slice(0, -2);
1317
- DESERIALIZE_FAST += indent + "} else {\n";
1600
+ blk += indent + "} else {\n";
1318
1601
  indent += " ";
1319
1602
  if (!inlineStringValue)
1320
- DESERIALIZE_FAST += indent + `srcStart += ${firstKeyOffset};\n`;
1321
- DESERIALIZE_FAST +=
1603
+ blk += indent + `srcStart += ${firstKeyOffset};\n`;
1604
+ blk +=
1322
1605
  indent +
1323
1606
  `if (JSON.Util.isSpace(load<u16>(${inlineStringValue ? `srcStart + ${firstKeyOffset}` : "srcStart"}))) break;\n`;
1324
- DESERIALIZE_FAST +=
1325
- indent + deserializerFirst.join("\n" + indent) + "\n";
1326
- DESERIALIZE_FAST += indent + "seenAny = true;\n";
1607
+ blk += indent + deserializerFirst.join("\n" + indent) + "\n";
1608
+ blk += indent + "seenAny = true;\n";
1327
1609
  indent = indent.slice(0, -2);
1328
- DESERIALIZE_FAST += indent + "}\n";
1610
+ blk += indent + "}\n";
1329
1611
  indent = indent.slice(0, -2);
1330
- DESERIALIZE_FAST += indent + "} else {\n";
1612
+ blk += indent + "} else {\n";
1331
1613
  indent += " ";
1332
- DESERIALIZE_FAST +=
1614
+ blk +=
1333
1615
  indent +
1334
1616
  `if ( // ${nextKeySection}\n${(indent += " ")}${getComparisions(nextKeySection, "srcStart", "!=").join("\n" + indent + "|| ")}\n${(indent = indent.slice(0, -2))}) {\n`;
1335
1617
  indent += " ";
1336
1618
  if (isOptional) {
1337
- DESERIALIZE_FAST += indent + "// optional @omitnull field omitted\n";
1619
+ blk += indent + "// optional @omitnull field omitted\n";
1338
1620
  }
1339
1621
  else {
1340
- DESERIALIZE_FAST += indent + "break;\n";
1622
+ blk += indent + "break;\n";
1341
1623
  }
1342
1624
  indent = indent.slice(0, -2);
1343
- DESERIALIZE_FAST += indent + "} else {\n";
1625
+ blk += indent + "} else {\n";
1344
1626
  indent += " ";
1345
1627
  if (!inlineStringValue)
1346
- DESERIALIZE_FAST += indent + `srcStart += ${nextKeyOffset};\n`;
1347
- DESERIALIZE_FAST +=
1628
+ blk += indent + `srcStart += ${nextKeyOffset};\n`;
1629
+ blk +=
1348
1630
  indent +
1349
1631
  `if (JSON.Util.isSpace(load<u16>(${inlineStringValue ? `srcStart + ${nextKeyOffset}` : "srcStart"}))) break;\n`;
1350
- DESERIALIZE_FAST +=
1351
- indent + deserializerNext.join("\n" + indent) + "\n";
1632
+ blk += indent + deserializerNext.join("\n" + indent) + "\n";
1352
1633
  indent = indent.slice(0, -2);
1353
- DESERIALIZE_FAST += indent + "}\n";
1634
+ blk += indent + "}\n";
1354
1635
  indent = indent.slice(0, -2);
1355
- DESERIALIZE_FAST += indent + "}\n\n";
1636
+ blk += indent + "}\n\n";
1637
+ t1opt.push(blk);
1356
1638
  }
1639
+ DESERIALIZE_FAST += chunkFastBlocksOptional(t1opt, "T1O", indent, false);
1357
1640
  }
1358
1641
  else {
1642
+ const t1blocks = [];
1359
1643
  for (let i = 0; i < this.schema.members.length; i++) {
1360
1644
  const member = this.schema.members[i];
1361
1645
  const key = JSON.stringify(member.alias || member.name);
1362
1646
  if (key.length <= 2)
1363
1647
  throw new Error("Key cannot be empty!");
1364
1648
  const keySection = (i == 0 ? "{" : ",") + key + ":";
1365
- DESERIALIZE_FAST +=
1366
- indent +
1367
- `if ( // ${keySection}\n${(indent += " ")}${getComparisions(keySection, "srcStart", "!=").join("\n" + indent + "|| ")}\n${(indent = indent.slice(0, -2))}) break;\n`;
1649
+ let blk = indent +
1650
+ `if ( // ${keySection}\n${(indent += " ")}${getComparisions(keySection, "srcStart", "!=").join("\n" + indent + "|| ")}\n${(indent = indent.slice(0, -2))}) break;\n`;
1368
1651
  const keyOffset = keySection.length << 1;
1369
1652
  const resolvedType = stripNull(member.type);
1370
1653
  const inlineStringValue = ["string", "String"].includes(resolvedType);
1371
1654
  if (!inlineStringValue) {
1372
- DESERIALIZE_FAST += indent + `srcStart += ${keyOffset};\n\n`;
1655
+ blk += indent + `srcStart += ${keyOffset};\n\n`;
1373
1656
  }
1374
1657
  const deserializer = getDeserializer(member.type, "srcStart", "dst", member, inlineStringValue ? keyOffset : 0, true);
1375
1658
  if (!deserializer.length) {
1376
- DESERIALIZE_FAST += indent + "break;\n\n";
1659
+ blk += indent + "break;\n\n";
1660
+ t1blocks.push(blk);
1377
1661
  continue;
1378
1662
  }
1379
- DESERIALIZE_FAST +=
1663
+ blk +=
1380
1664
  indent +
1381
1665
  `if (JSON.Util.isSpace(load<u16>(${inlineStringValue ? `srcStart + ${keyOffset}` : "srcStart"}))) break;\n`;
1382
- DESERIALIZE_FAST += indent + deserializer.join("\n" + indent) + "\n\n";
1666
+ blk += indent + deserializer.join("\n" + indent) + "\n\n";
1667
+ t1blocks.push(blk);
1383
1668
  }
1669
+ DESERIALIZE_FAST += chunkFastBlocks(t1blocks, "T1", indent);
1384
1670
  }
1385
1671
  DESERIALIZE_FAST +=
1386
1672
  indent + "if (load<u16>(srcStart) !== 0x7d) break; // }\n";
@@ -1399,31 +1685,32 @@ export class JSONTransform extends Visitor {
1399
1685
  DESERIALIZE_FAST += skip;
1400
1686
  DESERIALIZE_FAST += i2 + "if (load<u16>(srcStart) != 0x7b) break; // {\n";
1401
1687
  DESERIALIZE_FAST += i2 + "srcStart += 2;\n";
1688
+ const t2blocks = [];
1402
1689
  for (let i = 0; i < this.schema.members.length; i++) {
1403
1690
  const member = this.schema.members[i];
1404
1691
  const key = JSON.stringify(member.alias || member.name);
1405
1692
  const keyBytes = key.length << 1;
1406
- DESERIALIZE_FAST += "\n";
1407
- DESERIALIZE_FAST += skip;
1408
- DESERIALIZE_FAST +=
1693
+ let blk = "\n";
1694
+ blk += skip;
1695
+ blk +=
1409
1696
  i2 +
1410
1697
  `if ( // ${key}\n${i2} ` +
1411
1698
  getComparisions(key, "srcStart", "!=").join("\n" + i2 + " || ") +
1412
1699
  `\n${i2}) break;\n`;
1413
- DESERIALIZE_FAST += i2 + `srcStart += ${keyBytes};\n`;
1414
- DESERIALIZE_FAST += skip;
1415
- DESERIALIZE_FAST +=
1416
- i2 + "if (load<u16>(srcStart) != 0x3a) break; // :\n";
1417
- DESERIALIZE_FAST += i2 + "srcStart += 2;\n";
1418
- DESERIALIZE_FAST += skip;
1419
- DESERIALIZE_FAST += i2 + tier2Desers[i].join("\n" + i2) + "\n";
1700
+ blk += i2 + `srcStart += ${keyBytes};\n`;
1701
+ blk += skip;
1702
+ blk += i2 + "if (load<u16>(srcStart) != 0x3a) break; // :\n";
1703
+ blk += i2 + "srcStart += 2;\n";
1704
+ blk += skip;
1705
+ blk += i2 + tier2Desers[i].join("\n" + i2) + "\n";
1420
1706
  if (i < this.schema.members.length - 1) {
1421
- DESERIALIZE_FAST += skip;
1422
- DESERIALIZE_FAST +=
1423
- i2 + "if (load<u16>(srcStart) != 0x2c) break; // ,\n";
1424
- DESERIALIZE_FAST += i2 + "srcStart += 2;\n";
1707
+ blk += skip;
1708
+ blk += i2 + "if (load<u16>(srcStart) != 0x2c) break; // ,\n";
1709
+ blk += i2 + "srcStart += 2;\n";
1425
1710
  }
1711
+ t2blocks.push(blk);
1426
1712
  }
1713
+ DESERIALIZE_FAST += chunkFastBlocks(t2blocks, "T2", i2);
1427
1714
  DESERIALIZE_FAST += "\n";
1428
1715
  DESERIALIZE_FAST += skip;
1429
1716
  DESERIALIZE_FAST += i2 + "if (load<u16>(srcStart) != 0x7d) break; // }\n";
@@ -1445,33 +1732,34 @@ export class JSONTransform extends Visitor {
1445
1732
  DESERIALIZE_FAST += i2 + "let kp: usize = 0;\n";
1446
1733
  if (multi)
1447
1734
  DESERIALIZE_FAST += i2 + "let seenAny = false;\n";
1735
+ const t2opt = [];
1448
1736
  for (let i = 0; i < this.schema.members.length; i++) {
1449
1737
  const member = this.schema.members[i];
1450
1738
  const key = JSON.stringify(member.alias || member.name);
1451
1739
  const keyBytes = key.length << 1;
1452
- DESERIALIZE_FAST += "\n";
1453
- DESERIALIZE_FAST +=
1454
- i2 + "kp = JSON.Util.skipWhitespace(srcStart, srcEnd);\n";
1740
+ let blk = "\n";
1741
+ blk += i2 + "kp = JSON.Util.skipWhitespace(srcStart, srcEnd);\n";
1455
1742
  if (multi && i > 0) {
1456
- DESERIALIZE_FAST +=
1743
+ blk +=
1457
1744
  i2 +
1458
1745
  "if (seenAny && load<u16>(kp) == 0x2c) kp = JSON.Util.skipWhitespace(kp + 2, srcEnd);\n";
1459
1746
  }
1460
- DESERIALIZE_FAST +=
1747
+ blk +=
1461
1748
  i2 +
1462
1749
  `if ( // ${key}\n${i2} ` +
1463
1750
  getComparisions(key, "kp", "==").join("\n" + i2 + " && ") +
1464
1751
  `\n${i2}) {\n`;
1465
- DESERIALIZE_FAST += i3 + `kp += ${keyBytes};\n`;
1466
- DESERIALIZE_FAST += i3 + "kp = JSON.Util.skipWhitespace(kp, srcEnd);\n";
1467
- DESERIALIZE_FAST += i3 + "if (load<u16>(kp) != 0x3a) break; // :\n";
1468
- DESERIALIZE_FAST +=
1469
- i3 + "srcStart = JSON.Util.skipWhitespace(kp + 2, srcEnd);\n";
1470
- DESERIALIZE_FAST += i3 + tier2Desers[i].join("\n" + i3) + "\n";
1752
+ blk += i3 + `kp += ${keyBytes};\n`;
1753
+ blk += i3 + "kp = JSON.Util.skipWhitespace(kp, srcEnd);\n";
1754
+ blk += i3 + "if (load<u16>(kp) != 0x3a) break; // :\n";
1755
+ blk += i3 + "srcStart = JSON.Util.skipWhitespace(kp + 2, srcEnd);\n";
1756
+ blk += i3 + tier2Desers[i].join("\n" + i3) + "\n";
1471
1757
  if (multi)
1472
- DESERIALIZE_FAST += i3 + "seenAny = true;\n";
1473
- DESERIALIZE_FAST += i2 + "}\n";
1758
+ blk += i3 + "seenAny = true;\n";
1759
+ blk += i2 + "}\n";
1760
+ t2opt.push(blk);
1474
1761
  }
1762
+ DESERIALIZE_FAST += chunkFastBlocksOptional(t2opt, "T2O", i2, true);
1475
1763
  DESERIALIZE_FAST += "\n";
1476
1764
  DESERIALIZE_FAST +=
1477
1765
  i2 + "srcStart = JSON.Util.skipWhitespace(srcStart, srcEnd);\n";
@@ -1498,7 +1786,7 @@ export class JSONTransform extends Visitor {
1498
1786
  DESERIALIZE += indent + " let keyStart: usize = 0;\n";
1499
1787
  DESERIALIZE += indent + " let keyEnd: usize = 0;\n";
1500
1788
  DESERIALIZE += indent + " let isKey = false;\n";
1501
- if (!STRICT || sortedMembers.object.length || sortedMembers.array.length)
1789
+ if (!STRICT || slowObjectMembers.length || slowArrayMembers.length)
1502
1790
  DESERIALIZE += indent + " let depth: i32 = 0;\n";
1503
1791
  DESERIALIZE += indent + " let lastIndex: usize = 0;\n\n";
1504
1792
  DESERIALIZE +=
@@ -1643,8 +1931,37 @@ export class JSONTransform extends Visitor {
1643
1931
  DESERIALIZE += toMemCDecl(Math.max(...members.map((m) => (m.alias || m.name).length << 1)), " ");
1644
1932
  }
1645
1933
  };
1934
+ const getLazyRangeStore = (member, valueStart, valueEnd, prefix) => {
1935
+ return (prefix +
1936
+ `store<u64>(changetype<usize>(out), ((<u64>${valueStart}) << 32) | (<u64>(<u32>${valueEnd})), offsetof<this>(${JSON.stringify(member.name)}));\n`);
1937
+ };
1938
+ const getSlowValueStore = (member, valueStart, valueEnd, prefix) => {
1939
+ if (member.flags.has(PropertyFlags.Lazy))
1940
+ return getLazyRangeStore(member, valueStart, valueEnd, prefix);
1941
+ return (prefix +
1942
+ `store<${member.type}>(changetype<usize>(out), JSON.__deserialize<${member.type}>(${valueStart}, ${valueEnd}), offsetof<this>(${JSON.stringify(member.name)}));\n`);
1943
+ };
1944
+ const getSlowBooleanStore = (member, value, valueStart, valueEnd, prefix) => {
1945
+ if (member.flags.has(PropertyFlags.Lazy))
1946
+ return getLazyRangeStore(member, valueStart, valueEnd, prefix);
1947
+ if (member.type.startsWith("JSON.Box<bool") ||
1948
+ member.type.startsWith("JSON.Box<boolean") ||
1949
+ member.type.startsWith("Box<bool") ||
1950
+ member.type.startsWith("Box<boolean")) {
1951
+ return (prefix +
1952
+ `store<${member.type}>(changetype<usize>(out), changetype<${member.type}>(JSON.Box.from<bool>(${value})), offsetof<this>(${JSON.stringify(member.name)}));\n`);
1953
+ }
1954
+ return (prefix +
1955
+ `store<boolean>(changetype<usize>(out), ${value}, offsetof<this>(${JSON.stringify(member.name)}));\n`);
1956
+ };
1957
+ const getSlowNullStore = (member, valueStart, valueEnd, prefix) => {
1958
+ if (member.flags.has(PropertyFlags.Lazy))
1959
+ return getLazyRangeStore(member, valueStart, valueEnd, prefix);
1960
+ return (prefix +
1961
+ `store<usize>(changetype<usize>(out), 0, offsetof<this>(${JSON.stringify(member.name)}));\n`);
1962
+ };
1646
1963
  let mbElse = " ";
1647
- if (!STRICT || sortedMembers.string.length) {
1964
+ if (!STRICT || slowStringMembers.length) {
1648
1965
  DESERIALIZE += mbElse + "if (code == 34) {\n";
1649
1966
  DESERIALIZE += " lastIndex = srcStart;\n";
1650
1967
  DESERIALIZE += " srcStart += 2;\n";
@@ -1657,7 +1974,7 @@ export class JSONTransform extends Visitor {
1657
1974
  ' console.log("Value (string, ' +
1658
1975
  ++id +
1659
1976
  '): " + JSON.Util.ptrToStr(lastIndex, srcStart + 2));';
1660
- generateGroups(sortedMembers.string, (group) => {
1977
+ generateGroups(slowStringMembers, (group) => {
1661
1978
  generateConsts(group);
1662
1979
  const first = group[0];
1663
1980
  const fName = first.alias || first.name;
@@ -1669,15 +1986,7 @@ export class JSONTransform extends Visitor {
1669
1986
  ") { // " +
1670
1987
  fName +
1671
1988
  "\n";
1672
- DESERIALIZE +=
1673
- indent +
1674
- " store<" +
1675
- first.type +
1676
- ">(changetype<usize>(out), JSON.__deserialize<" +
1677
- first.type +
1678
- ">(lastIndex, srcStart + 2), offsetof<this>(" +
1679
- JSON.stringify(first.name) +
1680
- "));\n";
1989
+ DESERIALIZE += getSlowValueStore(first, "lastIndex", "srcStart + 2", indent + " ");
1681
1990
  DESERIALIZE += indent + " srcStart += 4;\n";
1682
1991
  DESERIALIZE += indent + " keyStart = 0;\n";
1683
1992
  DESERIALIZE += indent + " break;\n";
@@ -1693,15 +2002,7 @@ export class JSONTransform extends Visitor {
1693
2002
  ") { // " +
1694
2003
  memName +
1695
2004
  "\n";
1696
- DESERIALIZE +=
1697
- indent +
1698
- " store<" +
1699
- mem.type +
1700
- ">(changetype<usize>(out), JSON.__deserialize<" +
1701
- mem.type +
1702
- ">(lastIndex, srcStart + 2), offsetof<this>(" +
1703
- JSON.stringify(mem.name) +
1704
- "));\n";
2005
+ DESERIALIZE += getSlowValueStore(mem, "lastIndex", "srcStart + 2", indent + " ");
1705
2006
  DESERIALIZE += indent + " srcStart += 4;\n";
1706
2007
  DESERIALIZE += indent + " keyStart = 0;\n";
1707
2008
  DESERIALIZE += indent + " break;\n";
@@ -1728,7 +2029,7 @@ export class JSONTransform extends Visitor {
1728
2029
  DESERIALIZE += " }\n";
1729
2030
  mbElse = " else ";
1730
2031
  }
1731
- if (!STRICT || sortedMembers.number.length) {
2032
+ if (!STRICT || slowNumberMembers.length) {
1732
2033
  DESERIALIZE += mbElse + "if (code - 48 <= 9 || code == 45) {\n";
1733
2034
  DESERIALIZE += " lastIndex = srcStart;\n";
1734
2035
  DESERIALIZE += " srcStart += 2;\n";
@@ -1741,7 +2042,7 @@ export class JSONTransform extends Visitor {
1741
2042
  ' console.log("Value (number, ' +
1742
2043
  ++id +
1743
2044
  '): " + JSON.Util.ptrToStr(lastIndex, srcStart));';
1744
- generateGroups(sortedMembers.number, (group) => {
2045
+ generateGroups(slowNumberMembers, (group) => {
1745
2046
  generateConsts(group);
1746
2047
  const first = group[0];
1747
2048
  const fName = first.alias || first.name;
@@ -1759,15 +2060,7 @@ export class JSONTransform extends Visitor {
1759
2060
  ") { // " +
1760
2061
  fName +
1761
2062
  "\n";
1762
- DESERIALIZE +=
1763
- indent +
1764
- " store<" +
1765
- first.type +
1766
- ">(changetype<usize>(out), JSON.__deserialize<" +
1767
- first.type +
1768
- ">(lastIndex, srcStart), offsetof<this>(" +
1769
- JSON.stringify(first.name) +
1770
- "));\n";
2063
+ DESERIALIZE += getSlowValueStore(first, "lastIndex", "srcStart", indent + " ");
1771
2064
  DESERIALIZE += indent + " srcStart += 2;\n";
1772
2065
  DESERIALIZE += indent + " keyStart = 0;\n";
1773
2066
  DESERIALIZE += indent + " break;\n";
@@ -1789,15 +2082,7 @@ export class JSONTransform extends Visitor {
1789
2082
  ") { // " +
1790
2083
  memName +
1791
2084
  "\n";
1792
- DESERIALIZE +=
1793
- indent +
1794
- " store<" +
1795
- mem.type +
1796
- ">(changetype<usize>(out), JSON.__deserialize<" +
1797
- mem.type +
1798
- ">(lastIndex, srcStart), offsetof<this>(" +
1799
- JSON.stringify(mem.name) +
1800
- "));\n";
2085
+ DESERIALIZE += getSlowValueStore(mem, "lastIndex", "srcStart", indent + " ");
1801
2086
  DESERIALIZE += indent + " srcStart += 2;\n";
1802
2087
  DESERIALIZE += indent + " keyStart = 0;\n";
1803
2088
  DESERIALIZE += indent + " break;\n";
@@ -1824,7 +2109,7 @@ export class JSONTransform extends Visitor {
1824
2109
  DESERIALIZE += " }";
1825
2110
  mbElse = " else ";
1826
2111
  }
1827
- if (!STRICT || sortedMembers.object.length) {
2112
+ if (!STRICT || slowObjectMembers.length) {
1828
2113
  DESERIALIZE += mbElse + "if (code == 123) {\n";
1829
2114
  DESERIALIZE += " lastIndex = srcStart;\n";
1830
2115
  DESERIALIZE += " depth++;\n";
@@ -1844,7 +2129,7 @@ export class JSONTransform extends Visitor {
1844
2129
  ++id +
1845
2130
  '): " + JSON.Util.ptrToStr(lastIndex, srcStart));';
1846
2131
  indent = " ";
1847
- generateGroups(sortedMembers.object, (group) => {
2132
+ generateGroups(slowObjectMembers, (group) => {
1848
2133
  generateConsts(group);
1849
2134
  const first = group[0];
1850
2135
  const fName = first.alias || first.name;
@@ -1855,15 +2140,7 @@ export class JSONTransform extends Visitor {
1855
2140
  ") { // " +
1856
2141
  fName +
1857
2142
  "\n";
1858
- DESERIALIZE +=
1859
- indent +
1860
- " store<" +
1861
- first.type +
1862
- ">(changetype<usize>(out), JSON.__deserialize<" +
1863
- first.type +
1864
- ">(lastIndex, srcStart), offsetof<this>(" +
1865
- JSON.stringify(first.name) +
1866
- "));\n";
2143
+ DESERIALIZE += getSlowValueStore(first, "lastIndex", "srcStart", indent + " ");
1867
2144
  DESERIALIZE += indent + " keyStart = 0;\n";
1868
2145
  DESERIALIZE += indent + " break;\n";
1869
2146
  DESERIALIZE += indent + " }";
@@ -1877,15 +2154,7 @@ export class JSONTransform extends Visitor {
1877
2154
  ") { // " +
1878
2155
  memName +
1879
2156
  "\n";
1880
- DESERIALIZE +=
1881
- indent +
1882
- " store<" +
1883
- mem.type +
1884
- ">(changetype<usize>(out), JSON.__deserialize<" +
1885
- mem.type +
1886
- ">(lastIndex, srcStart), offsetof<this>(" +
1887
- JSON.stringify(mem.name) +
1888
- "));\n";
2157
+ DESERIALIZE += getSlowValueStore(mem, "lastIndex", "srcStart", indent + " ");
1889
2158
  DESERIALIZE += indent + " keyStart = 0;\n";
1890
2159
  DESERIALIZE += indent + " break;\n";
1891
2160
  DESERIALIZE += indent + " }";
@@ -1912,7 +2181,7 @@ export class JSONTransform extends Visitor {
1912
2181
  DESERIALIZE += " }";
1913
2182
  mbElse = " else ";
1914
2183
  }
1915
- if (!STRICT || sortedMembers.array.length) {
2184
+ if (!STRICT || slowArrayMembers.length) {
1916
2185
  DESERIALIZE += mbElse + "if (code == 91) {\n";
1917
2186
  DESERIALIZE += " lastIndex = srcStart;\n";
1918
2187
  DESERIALIZE += " depth++;\n";
@@ -1932,7 +2201,7 @@ export class JSONTransform extends Visitor {
1932
2201
  ++id +
1933
2202
  '): " + JSON.Util.ptrToStr(lastIndex, srcStart));';
1934
2203
  indent = " ";
1935
- generateGroups(sortedMembers.array, (group) => {
2204
+ generateGroups(slowArrayMembers, (group) => {
1936
2205
  generateConsts(group);
1937
2206
  const first = group[0];
1938
2207
  const fName = first.alias || first.name;
@@ -1944,15 +2213,7 @@ export class JSONTransform extends Visitor {
1944
2213
  ") { // " +
1945
2214
  fName +
1946
2215
  "\n";
1947
- DESERIALIZE +=
1948
- indent +
1949
- " store<" +
1950
- first.type +
1951
- ">(changetype<usize>(out), JSON.__deserialize<" +
1952
- first.type +
1953
- ">(lastIndex, srcStart), offsetof<this>(" +
1954
- JSON.stringify(first.name) +
1955
- "));\n";
2216
+ DESERIALIZE += getSlowValueStore(first, "lastIndex", "srcStart", indent + " ");
1956
2217
  DESERIALIZE += indent + " keyStart = 0;\n";
1957
2218
  DESERIALIZE += indent + " break;\n";
1958
2219
  DESERIALIZE += indent + " }";
@@ -1967,15 +2228,7 @@ export class JSONTransform extends Visitor {
1967
2228
  ") { // " +
1968
2229
  memName +
1969
2230
  "\n";
1970
- DESERIALIZE +=
1971
- indent +
1972
- " store<" +
1973
- mem.type +
1974
- ">(changetype<usize>(out), JSON.__deserialize<" +
1975
- mem.type +
1976
- ">(lastIndex, srcStart), offsetof<this>(" +
1977
- JSON.stringify(mem.name) +
1978
- "));\n";
2231
+ DESERIALIZE += getSlowValueStore(mem, "lastIndex", "srcStart", indent + " ");
1979
2232
  DESERIALIZE += indent + " keyStart = 0;\n";
1980
2233
  DESERIALIZE += indent + " break;\n";
1981
2234
  DESERIALIZE += indent + " }";
@@ -2002,7 +2255,7 @@ export class JSONTransform extends Visitor {
2002
2255
  DESERIALIZE += " }";
2003
2256
  mbElse = " else ";
2004
2257
  }
2005
- if (!STRICT || sortedMembers.boolean.length) {
2258
+ if (!STRICT || slowBooleanMembers.length) {
2006
2259
  DESERIALIZE += mbElse + "if (code == 116) {\n";
2007
2260
  DESERIALIZE +=
2008
2261
  " if (load<u64>(srcStart) == 28429475166421108) {\n";
@@ -2012,7 +2265,7 @@ export class JSONTransform extends Visitor {
2012
2265
  ' console.log("Value (bool, ' +
2013
2266
  ++id +
2014
2267
  '): " + JSON.Util.ptrToStr(lastIndex, srcStart - 8));';
2015
- generateGroups(sortedMembers.boolean, (group) => {
2268
+ generateGroups(slowBooleanMembers, (group) => {
2016
2269
  generateConsts(group);
2017
2270
  const first = group[0];
2018
2271
  const fName = first.alias || first.name;
@@ -2024,27 +2277,7 @@ export class JSONTransform extends Visitor {
2024
2277
  ") { // " +
2025
2278
  fName +
2026
2279
  "\n";
2027
- if (first.type.startsWith("JSON.Box<bool") ||
2028
- first.type.startsWith("JSON.Box<boolean") ||
2029
- first.type.startsWith("Box<bool") ||
2030
- first.type.startsWith("Box<boolean")) {
2031
- DESERIALIZE +=
2032
- indent +
2033
- " store<" +
2034
- first.type +
2035
- ">(changetype<usize>(out), changetype<" +
2036
- first.type +
2037
- ">(JSON.Box.from<bool>(true)), offsetof<this>(" +
2038
- JSON.stringify(first.name) +
2039
- "));\n";
2040
- }
2041
- else {
2042
- DESERIALIZE +=
2043
- indent +
2044
- " store<boolean>(changetype<usize>(out), true, offsetof<this>(" +
2045
- JSON.stringify(first.name) +
2046
- "));\n";
2047
- }
2280
+ DESERIALIZE += getSlowBooleanStore(first, "true", "srcStart - 8", "srcStart", indent + " ");
2048
2281
  DESERIALIZE += indent + " srcStart += 2;\n";
2049
2282
  DESERIALIZE += indent + " keyStart = 0;\n";
2050
2283
  DESERIALIZE += indent + " break;\n";
@@ -2060,27 +2293,7 @@ export class JSONTransform extends Visitor {
2060
2293
  ") { // " +
2061
2294
  memName +
2062
2295
  "\n";
2063
- if (mem.type.startsWith("JSON.Box<bool") ||
2064
- mem.type.startsWith("JSON.Box<boolean") ||
2065
- mem.type.startsWith("Box<bool") ||
2066
- mem.type.startsWith("Box<boolean")) {
2067
- DESERIALIZE +=
2068
- indent +
2069
- " store<" +
2070
- mem.type +
2071
- ">(changetype<usize>(out), changetype<" +
2072
- mem.type +
2073
- ">(JSON.Box.from<bool>(true)), offsetof<this>(" +
2074
- JSON.stringify(mem.name) +
2075
- "));\n";
2076
- }
2077
- else {
2078
- DESERIALIZE +=
2079
- indent +
2080
- " store<boolean>(changetype<usize>(out), true, offsetof<this>(" +
2081
- JSON.stringify(mem.name) +
2082
- "));\n";
2083
- }
2296
+ DESERIALIZE += getSlowBooleanStore(mem, "true", "srcStart - 8", "srcStart", indent + " ");
2084
2297
  DESERIALIZE += indent + " srcStart += 2;\n";
2085
2298
  DESERIALIZE += indent + " keyStart = 0;\n";
2086
2299
  DESERIALIZE += indent + " break;\n";
@@ -2116,7 +2329,7 @@ export class JSONTransform extends Visitor {
2116
2329
  ' console.log("Value (bool, ' +
2117
2330
  ++id +
2118
2331
  '): " + JSON.Util.ptrToStr(lastIndex, srcStart - 10));';
2119
- generateGroups(sortedMembers.boolean, (group) => {
2332
+ generateGroups(slowBooleanMembers, (group) => {
2120
2333
  generateConsts(group);
2121
2334
  const first = group[0];
2122
2335
  const fName = first.alias || first.name;
@@ -2128,27 +2341,7 @@ export class JSONTransform extends Visitor {
2128
2341
  ") { // " +
2129
2342
  fName +
2130
2343
  "\n";
2131
- if (first.type.startsWith("JSON.Box<bool") ||
2132
- first.type.startsWith("JSON.Box<boolean") ||
2133
- first.type.startsWith("Box<bool") ||
2134
- first.type.startsWith("Box<boolean")) {
2135
- DESERIALIZE +=
2136
- indent +
2137
- " store<" +
2138
- first.type +
2139
- ">(changetype<usize>(out), changetype<" +
2140
- first.type +
2141
- ">(JSON.Box.from<bool>(false)), offsetof<this>(" +
2142
- JSON.stringify(first.name) +
2143
- "));\n";
2144
- }
2145
- else {
2146
- DESERIALIZE +=
2147
- indent +
2148
- " store<boolean>(changetype<usize>(out), false, offsetof<this>(" +
2149
- JSON.stringify(first.name) +
2150
- "));\n";
2151
- }
2344
+ DESERIALIZE += getSlowBooleanStore(first, "false", "srcStart - 10", "srcStart", indent + " ");
2152
2345
  DESERIALIZE += indent + " srcStart += 2;\n";
2153
2346
  DESERIALIZE += indent + " keyStart = 0;\n";
2154
2347
  DESERIALIZE += indent + " break;\n";
@@ -2164,27 +2357,7 @@ export class JSONTransform extends Visitor {
2164
2357
  ") { // " +
2165
2358
  memName +
2166
2359
  "\n";
2167
- if (mem.type.startsWith("JSON.Box<bool") ||
2168
- mem.type.startsWith("JSON.Box<boolean") ||
2169
- mem.type.startsWith("Box<bool") ||
2170
- mem.type.startsWith("Box<boolean")) {
2171
- DESERIALIZE +=
2172
- indent +
2173
- " store<" +
2174
- mem.type +
2175
- ">(changetype<usize>(out), changetype<" +
2176
- mem.type +
2177
- ">(JSON.Box.from<bool>(false)), offsetof<this>(" +
2178
- JSON.stringify(mem.name) +
2179
- "));\n";
2180
- }
2181
- else {
2182
- DESERIALIZE +=
2183
- indent +
2184
- " store<boolean>(changetype<usize>(out), false, offsetof<this>(" +
2185
- JSON.stringify(mem.name) +
2186
- "));\n";
2187
- }
2360
+ DESERIALIZE += getSlowBooleanStore(mem, "false", "srcStart - 10", "srcStart", indent + " ");
2188
2361
  DESERIALIZE += indent + " srcStart += 2;\n";
2189
2362
  DESERIALIZE += indent + " keyStart = 0;\n";
2190
2363
  DESERIALIZE += indent + " break;\n";
@@ -2209,7 +2382,7 @@ export class JSONTransform extends Visitor {
2209
2382
  DESERIALIZE += "\n }";
2210
2383
  mbElse = " else ";
2211
2384
  }
2212
- if (!STRICT || sortedMembers.null.length) {
2385
+ if (!STRICT || slowNullMembers.length) {
2213
2386
  DESERIALIZE += mbElse + "if (code == 110) {\n";
2214
2387
  DESERIALIZE +=
2215
2388
  " if (load<u64>(srcStart) == 30399761348886638) {\n";
@@ -2219,7 +2392,7 @@ export class JSONTransform extends Visitor {
2219
2392
  ' console.log("Value (null, ' +
2220
2393
  ++id +
2221
2394
  '): " + JSON.Util.ptrToStr(lastIndex, srcStart - 8));';
2222
- generateGroups(sortedMembers.null, (group) => {
2395
+ generateGroups(slowNullMembers, (group) => {
2223
2396
  generateConsts(group);
2224
2397
  const first = group[0];
2225
2398
  const fName = first.alias || first.name;
@@ -2231,11 +2404,7 @@ export class JSONTransform extends Visitor {
2231
2404
  ") { // " +
2232
2405
  fName +
2233
2406
  "\n";
2234
- DESERIALIZE +=
2235
- indent +
2236
- " store<usize>(changetype<usize>(out), 0, offsetof<this>(" +
2237
- JSON.stringify(first.name) +
2238
- "));\n";
2407
+ DESERIALIZE += getSlowNullStore(first, "srcStart - 8", "srcStart", indent + " ");
2239
2408
  DESERIALIZE += indent + " srcStart += 2;\n";
2240
2409
  DESERIALIZE += indent + " keyStart = 0;\n";
2241
2410
  DESERIALIZE += indent + " break;\n";
@@ -2251,11 +2420,7 @@ export class JSONTransform extends Visitor {
2251
2420
  ") { // " +
2252
2421
  memName +
2253
2422
  "\n";
2254
- DESERIALIZE +=
2255
- indent +
2256
- " store<usize>(changetype<usize>(out), 0, offsetof<this>(" +
2257
- JSON.stringify(mem.name) +
2258
- "));\n";
2423
+ DESERIALIZE += getSlowNullStore(mem, "srcStart - 8", "srcStart", indent + " ");
2259
2424
  DESERIALIZE += indent + " srcStart += 2;\n";
2260
2425
  DESERIALIZE += indent + " keyStart = 0;\n";
2261
2426
  DESERIALIZE += indent + " break;\n";
@@ -2308,6 +2473,11 @@ export class JSONTransform extends Visitor {
2308
2473
  console.log(INITIALIZE);
2309
2474
  console.log(DESERIALIZE_CUSTOM || DESERIALIZE);
2310
2475
  }
2476
+ const WIDE_STRUCT_FIELD_LIMIT = 32;
2477
+ if (this.schema.members.length > WIDE_STRUCT_FIELD_LIMIT) {
2478
+ INITIALIZE = INITIALIZE.replace(/^@inline /, "");
2479
+ DESERIALIZE_FAST = DESERIALIZE_FAST.replace(/^@inline /, "");
2480
+ }
2311
2481
  const SERIALIZE_METHOD = SimpleParser.parseClassMember(SERIALIZE_CUSTOM || SERIALIZE, node);
2312
2482
  const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node);
2313
2483
  const DESERIALIZE_CUSTOM_METHOD = DESERIALIZE_CUSTOM
@@ -2334,6 +2504,13 @@ export class JSONTransform extends Visitor {
2334
2504
  DESERIALIZE_FAST_METHOD &&
2335
2505
  !node.members.find((v) => v.name.text == "__DESERIALIZE_FAST"))
2336
2506
  node.members.push(DESERIALIZE_FAST_METHOD);
2507
+ if (useFastPath && !DESERIALIZE_CUSTOM) {
2508
+ for (const chunk of fastChunkMethods) {
2509
+ const chunkMethod = SimpleParser.parseClassMember(chunk, node);
2510
+ if (!node.members.find((v) => v.name.text == chunkMethod.name.text))
2511
+ node.members.push(chunkMethod);
2512
+ }
2513
+ }
2337
2514
  super.visitClassDeclaration(node);
2338
2515
  }
2339
2516
  getSchema(name) {
@@ -2382,7 +2559,7 @@ export class JSONTransform extends Visitor {
2382
2559
  const atoiImport = this.imports.find((i) => i.declarations?.find((d) => d.foreignName.text == "atoi" || d.name.text == "atoi"));
2383
2560
  const scanValueEndImport = this.imports.find((i) => i.declarations?.find((d) => d.foreignName.text == "scanValueEnd" || d.name.text == "scanValueEnd"));
2384
2561
  const fieldHelpersImport = this.imports.find((i) => i.declarations?.find((d) => d.name.text == "__deserializeStringField"));
2385
- const sourceText = readFileSync(fromPath).toString();
2562
+ const sourceText = node.text;
2386
2563
  const hasLocalScanValueEnd = /\bscanValueEnd\b/.test(sourceText);
2387
2564
  const baseRel = computeImportBaseRel(path.dirname(fromPath), path.join(baseDir));
2388
2565
  if (!bsImport) {
@@ -2552,25 +2729,6 @@ var JSONMode;
2552
2729
  JSONMode[JSONMode["NAIVE"] = 2] = "NAIVE";
2553
2730
  })(JSONMode || (JSONMode = {}));
2554
2731
  let MODE = JSONMode.SWAR;
2555
- function getCodegenMode(program) {
2556
- let mode = program.options.hasFeature(16)
2557
- ? JSONMode.SIMD
2558
- : JSONMode.SWAR;
2559
- if (process.env["JSON_MODE"]) {
2560
- switch (process.env["JSON_MODE"].toLowerCase().trim()) {
2561
- case "simd":
2562
- mode = JSONMode.SIMD;
2563
- break;
2564
- case "swar":
2565
- mode = JSONMode.SWAR;
2566
- break;
2567
- case "naive":
2568
- mode = JSONMode.NAIVE;
2569
- break;
2570
- }
2571
- }
2572
- return mode;
2573
- }
2574
2732
  export default class Transformer extends Transform {
2575
2733
  afterInitialize(program) {
2576
2734
  if (program.options.hasFeature(16))
@@ -2648,6 +2806,12 @@ export default class Transformer extends Transform {
2648
2806
  writeFileSync(path.join(process.cwd(), this.baseDir, removeExtension(source.normalizedPath) + ".tmp.ts"), toString(source));
2649
2807
  }
2650
2808
  }
2809
+ for (const source of parser.sources) {
2810
+ const p = source.internalPath;
2811
+ if (p === "assembly/index" || p.endsWith("/json-as/assembly/index")) {
2812
+ source.sourceKind = 2;
2813
+ }
2814
+ }
2651
2815
  }
2652
2816
  }
2653
2817
  function sortMembers(members) {
@@ -2808,6 +2972,90 @@ function sizeof(type) {
2808
2972
  else
2809
2973
  return 0;
2810
2974
  }
2975
+ function classLazyMode(node) {
2976
+ const dec = node.decorators?.find((d) => {
2977
+ const n = d.name.text;
2978
+ return n === "json" || n === "serializable";
2979
+ });
2980
+ if (!dec || !dec.args || dec.args.length === 0)
2981
+ return "none";
2982
+ const arg = dec.args[0];
2983
+ if (arg.kind !== NodeKind.Literal ||
2984
+ arg.literalKind !== 6)
2985
+ return "none";
2986
+ const obj = arg;
2987
+ for (let i = 0; i < obj.names.length; i++) {
2988
+ if (obj.names[i].text !== "lazy")
2989
+ continue;
2990
+ const v = obj.values[i];
2991
+ if (v.kind === NodeKind.Literal &&
2992
+ v.literalKind === 2) {
2993
+ const s = v.value;
2994
+ if (s === "none" || s === "auto" || s === "all")
2995
+ return s;
2996
+ }
2997
+ throwError(`@json lazy must be "none", "auto", or "all"`, v.range);
2998
+ }
2999
+ return "none";
3000
+ }
3001
+ const LAZY_AUTO_THRESHOLD = 10;
3002
+ function lazyTypeCost(type, source, parser) {
3003
+ const base = stripNull(type);
3004
+ if (isPrimitive(base) || isBoolean(base) || isEnum(base, source, parser))
3005
+ return 1;
3006
+ if (base === "Date")
3007
+ return 4;
3008
+ if (isString(base))
3009
+ return 10;
3010
+ if (base === "JSON.Value" ||
3011
+ base === "Value" ||
3012
+ base === "JSON.Obj" ||
3013
+ base === "Obj" ||
3014
+ base === "JSON.Raw" ||
3015
+ base === "Raw")
3016
+ return 15;
3017
+ return 20;
3018
+ }
3019
+ function lazyAutoCost(type, source, parser) {
3020
+ const direct = lazyTypeCost(type, source, parser);
3021
+ if (direct < 20)
3022
+ return direct;
3023
+ const decl = source.getClass(stripNull(type));
3024
+ if (!decl)
3025
+ return 20;
3026
+ let sum = 0;
3027
+ for (let i = 0; i < decl.members.length; i++) {
3028
+ const m = decl.members[i];
3029
+ if (m.kind !== NodeKind.FieldDeclaration)
3030
+ continue;
3031
+ const fd = m;
3032
+ if (fd.is(32) ||
3033
+ fd.is(512) ||
3034
+ fd.is(1024) ||
3035
+ !fd.type)
3036
+ continue;
3037
+ sum += lazyTypeCost(toString(fd.type), source, parser);
3038
+ if (sum >= LAZY_AUTO_THRESHOLD)
3039
+ return sum;
3040
+ }
3041
+ return sum;
3042
+ }
3043
+ function lazyWrapperInner(typeNode) {
3044
+ if (!typeNode || typeNode.kind !== NodeKind.NamedType)
3045
+ return null;
3046
+ const named = typeNode;
3047
+ let seg = named.name;
3048
+ while (seg.next)
3049
+ seg = seg.next;
3050
+ if (seg.identifier.text !== "Lazy")
3051
+ return null;
3052
+ if (!named.typeArguments || named.typeArguments.length !== 1)
3053
+ return null;
3054
+ let inner = toString(named.typeArguments[0]).trim();
3055
+ if (named.isNullable && !inner.endsWith("null"))
3056
+ inner += " | null";
3057
+ return inner;
3058
+ }
2811
3059
  function estimatedSerializedByteSize(type, source, parser) {
2812
3060
  const trimmed = type.trim();
2813
3061
  const baseType = stripNull(trimmed);
@@ -2905,4 +3153,3 @@ function getComparison(data) {
2905
3153
  }
2906
3154
  }
2907
3155
  }
2908
- //# sourceMappingURL=index.js.map