json-as 1.3.9 → 1.5.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 (122) hide show
  1. package/CHANGELOG.md +60 -19
  2. package/README.md +120 -21
  3. package/assembly/custom/chars.ts +39 -78
  4. package/assembly/deserialize/index/arbitrary.ts +28 -10
  5. package/assembly/deserialize/index/float.ts +2 -4
  6. package/assembly/deserialize/index/integer.ts +2 -4
  7. package/assembly/deserialize/index/object.ts +6 -1
  8. package/assembly/deserialize/index/string.ts +2 -7
  9. package/assembly/deserialize/index/unsigned.ts +2 -4
  10. package/assembly/deserialize/naive/array/arbitrary.ts +3 -136
  11. package/assembly/deserialize/naive/array/array.ts +30 -1
  12. package/assembly/deserialize/naive/array/integer.ts +2 -7
  13. package/assembly/deserialize/naive/array/map.ts +10 -14
  14. package/assembly/deserialize/naive/array/object.ts +10 -14
  15. package/assembly/deserialize/naive/array/struct.ts +19 -1
  16. package/assembly/deserialize/naive/bool.ts +1 -5
  17. package/assembly/deserialize/naive/date.ts +1 -2
  18. package/assembly/deserialize/naive/float.ts +4 -11
  19. package/assembly/deserialize/naive/integer.ts +2 -4
  20. package/assembly/deserialize/naive/map.ts +42 -205
  21. package/assembly/deserialize/naive/object.ts +291 -174
  22. package/assembly/deserialize/naive/raw.ts +1 -5
  23. package/assembly/deserialize/naive/set.ts +3 -6
  24. package/assembly/deserialize/naive/staticarray.ts +2 -4
  25. package/assembly/deserialize/naive/string.ts +68 -24
  26. package/assembly/deserialize/naive/typedarray.ts +1 -2
  27. package/assembly/deserialize/naive/unsigned.ts +2 -4
  28. package/assembly/deserialize/simd/array/integer.ts +5 -13
  29. package/assembly/deserialize/simd/float.ts +5 -12
  30. package/assembly/deserialize/simd/integer.ts +6 -15
  31. package/assembly/deserialize/simd/string.ts +21 -43
  32. package/assembly/deserialize/swar/array/arbitrary.ts +1 -2
  33. package/assembly/deserialize/swar/array/array.ts +2 -4
  34. package/assembly/deserialize/swar/array/bool.ts +2 -4
  35. package/assembly/deserialize/swar/array/box.ts +1 -2
  36. package/assembly/deserialize/swar/array/float.ts +8 -21
  37. package/assembly/deserialize/swar/array/generic.ts +2 -4
  38. package/assembly/deserialize/swar/array/integer.ts +13 -27
  39. package/assembly/deserialize/swar/array/map.ts +1 -2
  40. package/assembly/deserialize/swar/array/object.ts +2 -4
  41. package/assembly/deserialize/swar/array/raw.ts +1 -2
  42. package/assembly/deserialize/swar/array/shared.ts +9 -21
  43. package/assembly/deserialize/swar/array/string.ts +4 -10
  44. package/assembly/deserialize/swar/array/struct.ts +3 -9
  45. package/assembly/deserialize/swar/array.ts +1 -3
  46. package/assembly/deserialize/swar/float.ts +7 -17
  47. package/assembly/deserialize/swar/integer.ts +6 -15
  48. package/assembly/deserialize/swar/string.ts +40 -54
  49. package/assembly/deserialize/swar/typedarray.ts +4 -4
  50. package/assembly/index.d.ts +259 -21
  51. package/assembly/index.ts +1704 -266
  52. package/assembly/serialize/index/arbitrary.ts +70 -4
  53. package/assembly/serialize/index/jsonarray.ts +51 -0
  54. package/assembly/serialize/index/object.ts +39 -14
  55. package/assembly/serialize/index/string.ts +1 -2
  56. package/assembly/serialize/index/typedarray.ts +1 -2
  57. package/assembly/serialize/index.ts +1 -0
  58. package/assembly/serialize/naive/array.ts +23 -34
  59. package/assembly/serialize/naive/bool.ts +0 -1
  60. package/assembly/serialize/naive/float.ts +16 -25
  61. package/assembly/serialize/naive/integer.ts +1 -5
  62. package/assembly/serialize/naive/raw.ts +1 -2
  63. package/assembly/serialize/naive/set.ts +0 -4
  64. package/assembly/serialize/naive/staticarray.ts +0 -5
  65. package/assembly/serialize/naive/string.ts +11 -7
  66. package/assembly/serialize/naive/typedarray.ts +0 -6
  67. package/assembly/serialize/simd/string.ts +1 -3
  68. package/assembly/serialize/swar/string.ts +2 -4
  69. package/assembly/util/atoi-fast.ts +4 -14
  70. package/assembly/util/atoi.ts +1 -2
  71. package/assembly/util/bytes.ts +1 -2
  72. package/assembly/util/idofd.ts +1 -2
  73. package/assembly/util/isSpace.ts +1 -2
  74. package/assembly/util/itoa-fast.ts +9 -15
  75. package/assembly/util/nextPowerOf2.ts +1 -2
  76. package/assembly/util/parsefloat-fast.ts +4 -7
  77. package/assembly/util/ptrToStr.ts +1 -2
  78. package/assembly/util/scanValueEnd.ts +1 -2
  79. package/assembly/util/scanValueEndSimd.ts +198 -0
  80. package/assembly/util/scanValueEndSwar.ts +184 -0
  81. package/assembly/util/scientific.ts +8 -14
  82. package/assembly/util/simd-int.ts +4 -8
  83. package/assembly/util/snp.ts +2 -7
  84. package/assembly/util/stringScan.ts +2 -4
  85. package/assembly/util/swar-int.ts +8 -16
  86. package/assembly/util/swar.ts +2 -4
  87. package/lib/as-bs.ts +57 -42
  88. package/package.json +27 -10
  89. package/transform/lib/builder.d.ts +0 -1
  90. package/transform/lib/builder.js +0 -1
  91. package/transform/lib/index.d.ts +0 -1
  92. package/transform/lib/index.js +617 -326
  93. package/transform/lib/linkers/alias.d.ts +0 -1
  94. package/transform/lib/linkers/alias.js +0 -1
  95. package/transform/lib/linkers/custom.d.ts +0 -1
  96. package/transform/lib/linkers/custom.js +0 -1
  97. package/transform/lib/linkers/imports.d.ts +0 -1
  98. package/transform/lib/linkers/imports.js +0 -1
  99. package/transform/lib/types.d.ts +4 -2
  100. package/transform/lib/types.js +5 -1
  101. package/transform/lib/util.d.ts +0 -1
  102. package/transform/lib/util.js +0 -1
  103. package/transform/lib/visitor.d.ts +0 -1
  104. package/transform/lib/visitor.js +0 -1
  105. package/assembly/util/dragonbox-cache.ts +0 -445
  106. package/assembly/util/dragonbox.ts +0 -660
  107. package/transform/lib/builder.d.ts.map +0 -1
  108. package/transform/lib/builder.js.map +0 -1
  109. package/transform/lib/index.d.ts.map +0 -1
  110. package/transform/lib/index.js.map +0 -1
  111. package/transform/lib/linkers/alias.d.ts.map +0 -1
  112. package/transform/lib/linkers/alias.js.map +0 -1
  113. package/transform/lib/linkers/custom.d.ts.map +0 -1
  114. package/transform/lib/linkers/custom.js.map +0 -1
  115. package/transform/lib/linkers/imports.d.ts.map +0 -1
  116. package/transform/lib/linkers/imports.js.map +0 -1
  117. package/transform/lib/types.d.ts.map +0 -1
  118. package/transform/lib/types.js.map +0 -1
  119. package/transform/lib/util.d.ts.map +0 -1
  120. package/transform/lib/util.js.map +0 -1
  121. package/transform/lib/visitor.d.ts.map +0 -1
  122. package/transform/lib/visitor.js.map +0 -1
@@ -301,10 +301,135 @@ 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
+ const __lazyValInits = new Map();
314
+ for (let i = node.members.length - 1; i >= 0; i--) {
315
+ const fd = node.members[i];
316
+ if (fd.kind !== NodeKind.FieldDeclaration ||
317
+ fd.is(32) ||
318
+ fd.is(512) ||
319
+ fd.is(1024) ||
320
+ !fd.type)
321
+ continue;
322
+ const written = toString(fd.type).trim();
323
+ const decos = fd.decorators;
324
+ const hasDeco = (name) => decos?.some((d) => d.name.text === name) ??
325
+ false;
326
+ let inner = lazyWrapperInner(fd.type);
327
+ if (inner === null) {
328
+ if (hasDeco("lazy")) {
329
+ inner = written;
330
+ }
331
+ else if (lazyMode !== "none" &&
332
+ !hasDeco("eager") &&
333
+ !hasDeco("omit")) {
334
+ if (lazyMode === "all")
335
+ inner = written;
336
+ else if (lazyAutoCost(this.resolveType(written, source), source, this.parser) >= LAZY_AUTO_THRESHOLD)
337
+ inner = written;
338
+ }
339
+ }
340
+ if (inner === null)
341
+ continue;
342
+ if (hasCustomSerde)
343
+ throwError("Lazy fields (@lazy / JSON.Lazy<T> / @json({ lazy })) are not supported " +
344
+ "on a class with a custom @serializer/@deserializer - the custom methods " +
345
+ "bypass the generated (de)serializer, so the deferred slot is never filled. " +
346
+ "Remove the lazy marker or the custom (de)serializer.", fd.range);
347
+ const fname = fd.name.text;
348
+ const key = JSON.stringify(fname);
349
+ const T = inner;
350
+ const baseT = stripNull(T);
351
+ const storesScalar = isPrimitive(baseT) || isEnum(baseT, source, this.parser);
352
+ const valueType = storesScalar || baseT != T ? T : `${T} | null`;
353
+ const valueDefault = isBoolean(baseT)
354
+ ? "false"
355
+ : storesScalar
356
+ ? "0"
357
+ : "null";
358
+ const fdInit = fd.initializer;
359
+ const fieldDefault = fdInit ? toString(fdInit) : null;
360
+ const refDefault = fieldDefault != null
361
+ ? fieldDefault
362
+ : !storesScalar && baseT == T && !baseT.startsWith("StaticArray<")
363
+ ? baseT == "string" || baseT == "String"
364
+ ? '""'
365
+ : `new ${baseT}()`
366
+ : null;
367
+ __hasLazy = true;
368
+ const omitIfDeco = decos?.find((d) => d.name.text === "omitif");
369
+ lazyInner.set("__" + fname + "_lz", {
370
+ inner: T,
371
+ valueType,
372
+ omitNull: hasDeco("omitnull"),
373
+ omitIf: omitIfDeco?.args?.[0] ?? null,
374
+ });
375
+ const packScalar = baseT === "i8" ||
376
+ baseT === "u8" ||
377
+ baseT === "i16" ||
378
+ baseT === "u16" ||
379
+ baseT === "i32" ||
380
+ baseT === "u32" ||
381
+ baseT === "bool" ||
382
+ baseT === "boolean" ||
383
+ baseT === "f32";
384
+ const encVal = (v) => baseT === "f32"
385
+ ? `(<u64>reinterpret<u32>(${v}))`
386
+ : `(<u64><u32>(${v}))`;
387
+ const decSlot = (lz) => baseT === "f32"
388
+ ? `reinterpret<f32>(<u32>(${lz}))`
389
+ : `(<${T}>(<u32>(${lz})))`;
390
+ const lowered = (packScalar
391
+ ? [
392
+ `@alias(${key}) private __${fname}_lz: u64 = ${fieldDefault != null
393
+ ? `(((<u64>0xffffffff) << 32) | ${encVal(`<${T}>(${fieldDefault})`)})`
394
+ : "0"};`,
395
+ `get ${fname}(): ${T} {\n` +
396
+ ` const __lz = this.__${fname}_lz;\n` +
397
+ ` if ((__lz >>> 32) == 0xffffffff) return ${decSlot("__lz")};\n` +
398
+ ` if (__lz != 0) {\n` +
399
+ ` const __v = JSON.__deserialize<${T}>(<usize>(__lz >>> 32), <usize>(<u32>__lz));\n` +
400
+ ` this.__${fname}_lz = ((<u64>0xffffffff) << 32) | ${encVal("__v")};\n` +
401
+ ` return __v;\n` +
402
+ ` }\n` +
403
+ ` return ${valueDefault};\n}`,
404
+ `set ${fname}(value: ${T}) {\n` +
405
+ ` this.__${fname}_lz = ((<u64>0xffffffff) << 32) | ${encVal("value")};\n}`,
406
+ ]
407
+ : [
408
+ `@alias(${key}) private __${fname}_lz: u64 = ${refDefault != null ? "u64.MAX_VALUE" : "0"};`,
409
+ `private __${fname}_val: ${valueType} = ${refDefault ?? valueDefault};`,
410
+ `get ${fname}(): ${T} {\n` +
411
+ ` const __lz = this.__${fname}_lz;\n` +
412
+ ` if (__lz != 0 && __lz != u64.MAX_VALUE) {\n` +
413
+ ` this.__${fname}_val = JSON.__deserialize<${T}>(<usize>(__lz >>> 32), <usize>(<u32>__lz));\n` +
414
+ ` this.__${fname}_lz = u64.MAX_VALUE;\n` +
415
+ ` }\n` +
416
+ ` return this.__${fname}_val as ${T};\n}`,
417
+ `set ${fname}(value: ${T}) {\n` +
418
+ ` this.__${fname}_val = value;\n` +
419
+ ` this.__${fname}_lz = u64.MAX_VALUE;\n}`,
420
+ ]).map((src) => SimpleParser.parseClassMember(src, node));
421
+ node.members.splice(i, 1, ...lowered);
422
+ if (!packScalar && refDefault != null) {
423
+ __lazyValInits.set(`__${fname}_lz`, ` store<${valueType}>(changetype<usize>(this), ${refDefault}, offsetof<this>(${JSON.stringify(`__${fname}_val`)}));\n`);
424
+ }
425
+ }
426
+ if (__hasLazy) {
427
+ node.members.push(SimpleParser.parseClassMember(`private __src: string = "";`, node), SimpleParser.parseClassMember(`__SET_SRC(s: string): void { this.__src = s; }`, node));
428
+ }
304
429
  const members = [
305
430
  ...node.members.filter((v) => v.kind === NodeKind.FieldDeclaration &&
306
431
  !v.is(32) &&
307
- !v.is(512) &&
432
+ (!v.is(512) || lazyInner.has(v.name.text)) &&
308
433
  !v.is(1024) &&
309
434
  !v.decorators?.some((decorator) => decorator.name.text === "omit")),
310
435
  ];
@@ -455,7 +580,7 @@ export class JSONTransform extends Visitor {
455
580
  else if (isString(type) || isPrimitive(type)) {
456
581
  return types;
457
582
  }
458
- else if (["JSON.Box", "JSON.Obj", "JSON.Value", "JSON.Raw"].includes(type)) {
583
+ else if (["JSON.Box", "JSON.Obj", "JSON.Arr", "JSON.Value", "JSON.Raw"].includes(type)) {
459
584
  return types;
460
585
  }
461
586
  else if (node.isGeneric &&
@@ -549,12 +674,11 @@ export class JSONTransform extends Visitor {
549
674
  this.schemas.get(source.internalPath).push(schema);
550
675
  this.schema = schema;
551
676
  this.visitedClasses.add(fullClassPath);
552
- const codegenMode = getCodegenMode(this.program);
553
- const requestedFastPath = USE_FAST_PATH && codegenMode !== JSONMode.NAIVE;
677
+ const requestedFastPath = USE_FAST_PATH;
554
678
  let SERIALIZE = "__SERIALIZE(ptr: usize): void {\n";
555
- let INITIALIZE = "@inline __INITIALIZE(): this {\n";
679
+ let INITIALIZE = " __INITIALIZE(): this {\n";
556
680
  let DESERIALIZE = "__DESERIALIZE_SLOW<__JSON_T>(srcStart: usize, srcEnd: usize, out: __JSON_T): usize {\n";
557
- let DESERIALIZE_FAST = "@inline __DESERIALIZE_FAST<__JSON_T>(srcStart: usize, srcEnd: usize, out: __JSON_T): usize {\n";
681
+ let DESERIALIZE_FAST = "__DESERIALIZE_FAST<__JSON_T>(srcStart: usize, srcEnd: usize, out: __JSON_T): usize {\n";
558
682
  let DESERIALIZE_CUSTOM = "";
559
683
  let SERIALIZE_CUSTOM = "";
560
684
  if (DEBUG > 0)
@@ -660,12 +784,9 @@ export class JSONTransform extends Visitor {
660
784
  if (!deserializer.decorators.some((v) => v.name.text == "inline")) {
661
785
  deserializer.decorators.push(Node.createDecorator(Node.createIdentifierExpression("inline", deserializer.range), null, deserializer.range));
662
786
  }
787
+ DESERIALIZE_CUSTOM += " __DESERIALIZE_CUSTOM(data: string): this {\n";
663
788
  DESERIALIZE_CUSTOM +=
664
- " @inline __DESERIALIZE_CUSTOM(data: string): this {\n";
665
- DESERIALIZE_CUSTOM +=
666
- " return inline.always(this." +
667
- deserializer.name.text +
668
- "(data));\n";
789
+ " return this." + deserializer.name.text + "(data);\n";
669
790
  DESERIALIZE_CUSTOM += " }\n";
670
791
  }
671
792
  if (!members.length && !deserializers.length && !serializers.length) {
@@ -689,6 +810,19 @@ export class JSONTransform extends Visitor {
689
810
  mem.node = member;
690
811
  mem.byteSize = estimatedSerializedByteSize(mem.type, source, this.parser);
691
812
  mem.custom = schema.deps.some((dep) => dep?.name == stripNull(type) && dep.custom);
813
+ const lzInner = lazyInner.get(name.text);
814
+ if (lzInner !== undefined) {
815
+ mem.flags.set(PropertyFlags.Lazy, null);
816
+ mem.lazyInner = lzInner.inner;
817
+ if (lzInner.omitNull) {
818
+ mem.flags.set(PropertyFlags.OmitNull, null);
819
+ this.schema.static = false;
820
+ }
821
+ if (lzInner.omitIf) {
822
+ mem.flags.set(PropertyFlags.OmitIf, lzInner.omitIf);
823
+ this.schema.static = false;
824
+ }
825
+ }
692
826
  this.schema.byteSize += mem.byteSize;
693
827
  if (member.decorators) {
694
828
  for (const decorator of member.decorators) {
@@ -717,6 +851,10 @@ export class JSONTransform extends Visitor {
717
851
  this.schema.static = false;
718
852
  break;
719
853
  }
854
+ case "optional": {
855
+ mem.flags.set(PropertyFlags.Optional, null);
856
+ break;
857
+ }
720
858
  case "omitnull": {
721
859
  if (isPrimitive(type)) {
722
860
  throwError("@omitnull cannot be used on primitive types!", member.range);
@@ -733,11 +871,12 @@ export class JSONTransform extends Visitor {
733
871
  }
734
872
  this.schema.members.push(mem);
735
873
  }
736
- if (!this.schema.static)
737
- this.schema.members = sortMembers(this.schema.members);
874
+ this.schema.members = sortMembers(this.schema.members);
738
875
  const hasOmitIfMembers = this.schema.members.some((v) => v.flags.has(PropertyFlags.OmitIf));
739
876
  const hasOmitNullMembers = this.schema.members.some((v) => v.flags.has(PropertyFlags.OmitNull));
740
- const hasOptionalMembers = hasOmitIfMembers || hasOmitNullMembers;
877
+ const hasExplicitOptionalMembers = this.schema.members.some((v) => v.flags.has(PropertyFlags.Optional));
878
+ const hasOptionalMembers = hasOmitIfMembers || hasOmitNullMembers || hasExplicitOptionalMembers;
879
+ const hasLazyMembers = this.schema.members.some((v) => v.flags.has(PropertyFlags.Lazy));
741
880
  const supportsFastOptionalPath = requestedFastPath && hasOptionalMembers;
742
881
  const hasTypeParams = !!node.typeParameters && node.typeParameters.length > 0;
743
882
  const useFastPath = requestedFastPath &&
@@ -748,6 +887,9 @@ export class JSONTransform extends Visitor {
748
887
  if (this.schema.members.some((v) => v.flags.has(PropertyFlags.OmitNull))) {
749
888
  SERIALIZE += indent + "let block: usize = 0;\n";
750
889
  }
890
+ if (hasOptionalMembers) {
891
+ SERIALIZE += indent + "let wrote = false;\n";
892
+ }
751
893
  this.schema.byteSize += 2;
752
894
  SERIALIZE += indent + "store<u16>(bs.offset, 123, 0); // {\n";
753
895
  SERIALIZE += indent + "bs.offset += 2;\n";
@@ -755,18 +897,69 @@ export class JSONTransform extends Visitor {
755
897
  const isPure = this.schema.static;
756
898
  let isRegular = isPure;
757
899
  let isFirst = true;
900
+ const serValue = (member, realName) => {
901
+ if (!member.flags.has(PropertyFlags.Lazy))
902
+ return getSerializeCall(member.type, realName);
903
+ const T = member.lazyInner;
904
+ const baseName = realName.slice(0, -3);
905
+ const baseT = stripNull(T);
906
+ const packScalar = baseT === "i8" ||
907
+ baseT === "u8" ||
908
+ baseT === "i16" ||
909
+ baseT === "u16" ||
910
+ baseT === "i32" ||
911
+ baseT === "u32" ||
912
+ baseT === "bool" ||
913
+ baseT === "boolean" ||
914
+ baseT === "f32";
915
+ if (packScalar) {
916
+ const dec = baseT === "f32"
917
+ ? `reinterpret<f32>(<u32>(__s))`
918
+ : `(<${T}>(<u32>(__s)))`;
919
+ const def = baseT === "bool" || baseT === "boolean" ? "false" : "0";
920
+ return (`{\n` +
921
+ ` const __s = this.${realName};\n` +
922
+ ` if ((__s >>> 32) == 0xffffffff) {\n` +
923
+ ` JSON.__serialize<${T}>(${dec});\n` +
924
+ ` } else if (__s != 0) {\n` +
925
+ ` const __hi = <usize>(__s >>> 32);\n` +
926
+ ` const __len = (<usize>(<u32>__s)) - __hi;\n` +
927
+ ` bs.ensureSize(<u32>__len);\n` +
928
+ ` memory.copy(bs.offset, __hi, __len);\n` +
929
+ ` bs.offset += __len;\n` +
930
+ ` } else {\n` +
931
+ ` JSON.__serialize<${T}>(${def});\n` +
932
+ ` }\n` +
933
+ `}\n`);
934
+ }
935
+ return (`{\n` +
936
+ ` const __s = this.${realName};\n` +
937
+ ` if (__s == u64.MAX_VALUE) {\n` +
938
+ ` JSON.__serialize<${T}>(this.${baseName}_val as ${T});\n` +
939
+ ` } else if (__s != 0) {\n` +
940
+ ` const __hi = <usize>(__s >>> 32);\n` +
941
+ ` const __len = (<usize>(<u32>__s)) - __hi;\n` +
942
+ ` bs.ensureSize(<u32>__len);\n` +
943
+ ` memory.copy(bs.offset, __hi, __len);\n` +
944
+ ` bs.offset += __len;\n` +
945
+ ` } else {\n` +
946
+ (isPrimitive(baseT)
947
+ ? ` JSON.__serialize<${T}>(0);\n`
948
+ : ` bs.ensureSize(8);\n` +
949
+ ` store<u64>(bs.offset, 0x006c006c0075006e);\n` +
950
+ ` bs.offset += 8;\n`) +
951
+ ` }\n` +
952
+ `}\n`);
953
+ };
758
954
  for (let i = 0; i < this.schema.members.length; i++) {
759
955
  const member = this.schema.members[i];
760
956
  const aliasName = JSON.stringify(member.alias || member.name);
761
957
  const realName = member.name;
762
- const isLast = i == this.schema.members.length - 1;
763
958
  if (member.value) {
764
- if (member.value != "null" &&
765
- member.value != "0" &&
766
- member.value != "0.0" &&
767
- member.value != "false") {
768
- INITIALIZE += ` store<${member.type}>(changetype<usize>(this), ${member.value}, offsetof<this>(${JSON.stringify(member.name)}));\n`;
769
- }
959
+ INITIALIZE += ` store<${member.type}>(changetype<usize>(this), ${member.value}, offsetof<this>(${JSON.stringify(member.name)}));\n`;
960
+ const __valInit = __lazyValInits.get(member.name);
961
+ if (__valInit)
962
+ INITIALIZE += __valInit;
770
963
  }
771
964
  else if (member.generic) {
772
965
  INITIALIZE += ` if (isManaged<nonnull<${member.type}>>() || isReference<nonnull<${member.type}>>()) {\n`;
@@ -793,6 +986,9 @@ export class JSONTransform extends Visitor {
793
986
  INITIALIZE += ` store<${member.type}>(changetype<usize>(this), "", offsetof<this>(${JSON.stringify(member.name)}));\n`;
794
987
  }
795
988
  }
989
+ else {
990
+ INITIALIZE += ` store<${member.type}>(changetype<usize>(this), null, offsetof<this>(${JSON.stringify(member.name)}));\n`;
991
+ }
796
992
  const SIMD_ENABLED = this.program.options.hasFeature(16);
797
993
  if (!isRegular &&
798
994
  !member.flags.has(PropertyFlags.OmitIf) &&
@@ -801,40 +997,69 @@ export class JSONTransform extends Visitor {
801
997
  if (isRegular && isPure) {
802
998
  const keyPart = (isFirst ? "{" : ",") + aliasName + ":";
803
999
  this.schema.byteSize += keyPart.length << 1;
1000
+ if (hasLazyMembers)
1001
+ SERIALIZE += indent + `bs.ensureSize(${keyPart.length << 1});\n`;
804
1002
  SERIALIZE += this.getStores(keyPart, SIMD_ENABLED)
805
1003
  .map((v) => indent + v + "\n")
806
1004
  .join("");
807
- SERIALIZE += indent + getSerializeCall(member.type, realName);
1005
+ SERIALIZE += indent + serValue(member, realName);
808
1006
  if (isFirst)
809
1007
  isFirst = false;
810
1008
  }
811
1009
  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);
1010
+ if (isFirst && hasOptionalMembers) {
1011
+ const keyPart = aliasName + ":";
1012
+ this.schema.byteSize += 2 + (keyPart.length << 1);
1013
+ SERIALIZE +=
1014
+ indent +
1015
+ "if (wrote) { store<u16>(bs.offset, 44, 0); bs.offset += 2; } // ,\n";
1016
+ if (hasLazyMembers)
1017
+ SERIALIZE += indent + `bs.ensureSize(${keyPart.length << 1});\n`;
1018
+ SERIALIZE += this.getStores(keyPart, SIMD_ENABLED)
1019
+ .map((v) => indent + v + "\n")
1020
+ .join("");
1021
+ SERIALIZE += indent + serValue(member, realName);
1022
+ }
1023
+ else {
1024
+ const keyPart = (isFirst ? "" : ",") + aliasName + ":";
1025
+ this.schema.byteSize += keyPart.length << 1;
1026
+ if (hasLazyMembers)
1027
+ SERIALIZE += indent + `bs.ensureSize(${keyPart.length << 1});\n`;
1028
+ SERIALIZE += this.getStores(keyPart, SIMD_ENABLED)
1029
+ .map((v) => indent + v + "\n")
1030
+ .join("");
1031
+ SERIALIZE += indent + serValue(member, realName);
1032
+ }
818
1033
  if (isFirst)
819
1034
  isFirst = false;
820
1035
  }
821
1036
  else {
822
1037
  if (member.flags.has(PropertyFlags.OmitNull)) {
823
- SERIALIZE +=
824
- indent +
825
- `if ((block = load<usize>(ptr, offsetof<this>(${JSON.stringify(realName)}))) !== 0) {\n`;
1038
+ let omitNullCond;
1039
+ if (member.flags.has(PropertyFlags.Lazy)) {
1040
+ const base = realName.slice(0, -3);
1041
+ omitNullCond =
1042
+ `!JSON.__lazyIsNull(` +
1043
+ `load<usize>(ptr, offsetof<this>(${JSON.stringify(base + "_val")})), ` +
1044
+ `load<u64>(ptr, offsetof<this>(${JSON.stringify(realName)})))`;
1045
+ }
1046
+ else {
1047
+ omitNullCond = `(block = load<usize>(ptr, offsetof<this>(${JSON.stringify(realName)}))) !== 0`;
1048
+ }
1049
+ SERIALIZE += indent + `if (${omitNullCond}) {\n`;
826
1050
  indentInc();
827
1051
  const keyPart = aliasName + ":";
828
- this.schema.byteSize += keyPart.length << 1;
1052
+ this.schema.byteSize += 2 + (keyPart.length << 1);
1053
+ SERIALIZE +=
1054
+ indent +
1055
+ "if (wrote) { store<u16>(bs.offset, 44, 0); bs.offset += 2; } // ,\n";
1056
+ if (hasLazyMembers)
1057
+ SERIALIZE += indent + `bs.ensureSize(${keyPart.length << 1});\n`;
829
1058
  SERIALIZE += this.getStores(keyPart, SIMD_ENABLED)
830
1059
  .map((v) => indent + v + "\n")
831
1060
  .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
- }
1061
+ SERIALIZE += indent + serValue(member, realName);
1062
+ SERIALIZE += indent + "wrote = true;\n";
838
1063
  indentDec();
839
1064
  this.schema.byteSize += 2;
840
1065
  SERIALIZE += indent + `}\n`;
@@ -860,15 +1085,15 @@ export class JSONTransform extends Visitor {
860
1085
  SERIALIZE += indent + `if (!(${rendered})) {\n`;
861
1086
  }
862
1087
  indentInc();
1088
+ this.schema.byteSize += 2;
1089
+ SERIALIZE +=
1090
+ indent +
1091
+ "if (wrote) { store<u16>(bs.offset, 44, 0); bs.offset += 2; } // ,\n";
863
1092
  SERIALIZE += this.getStores(aliasName + ":", SIMD_ENABLED)
864
1093
  .map((v) => indent + v + "\n")
865
1094
  .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
- }
1095
+ SERIALIZE += indent + serValue(member, realName);
1096
+ SERIALIZE += indent + "wrote = true;\n";
872
1097
  indentDec();
873
1098
  SERIALIZE += indent + `}\n`;
874
1099
  }
@@ -906,12 +1131,29 @@ export class JSONTransform extends Visitor {
906
1131
  type.startsWith("JSON.Box<") ||
907
1132
  isEnum(type, this.sources.get(this.schema.node.range.source), this.parser))
908
1133
  sortedMembers.number.push(member);
909
- else if (isArray(type))
1134
+ else if (isArray(type) || type == "JSON.Arr" || type == "Arr")
910
1135
  sortedMembers.array.push(member);
911
1136
  else
912
1137
  sortedMembers.object.push(member);
913
1138
  }
914
1139
  }
1140
+ const lazyMembers = this.schema.members.filter((member) => member.flags.has(PropertyFlags.Lazy));
1141
+ const withLazyMembers = (members) => {
1142
+ if (!lazyMembers.length)
1143
+ return members;
1144
+ const out = members.slice();
1145
+ for (const member of lazyMembers) {
1146
+ if (!out.includes(member))
1147
+ out.push(member);
1148
+ }
1149
+ return out;
1150
+ };
1151
+ const slowStringMembers = withLazyMembers(sortedMembers.string);
1152
+ const slowNumberMembers = withLazyMembers(sortedMembers.number);
1153
+ const slowObjectMembers = withLazyMembers(sortedMembers.object);
1154
+ const slowArrayMembers = withLazyMembers(sortedMembers.array);
1155
+ const slowBooleanMembers = withLazyMembers(sortedMembers.boolean);
1156
+ const slowNullMembers = withLazyMembers(sortedMembers.null);
915
1157
  const getComparisions = (data, ptr, operator) => {
916
1158
  const dataBytes = data.length << 1;
917
1159
  let offset = 0;
@@ -952,6 +1194,17 @@ export class JSONTransform extends Visitor {
952
1194
  const resolvedSchema = this.getSchema(resolvedType);
953
1195
  const fieldOffset = `offsetof<this>(${JSON.stringify(member.name)})`;
954
1196
  const valuePtr = keyOffset ? `${srcPtr} + ${keyOffset}` : srcPtr;
1197
+ if (member.flags.has(PropertyFlags.Lazy)) {
1198
+ const lazyInner = member.lazyInner;
1199
+ out.push("{");
1200
+ out.push(` const valueStart = JSON.Util.skipWhitespace(${valuePtr}, srcEnd);`);
1201
+ out.push(` const valueEnd = JSON.Util.scanValueEnd<${lazyInner}>(valueStart, srcEnd);`);
1202
+ out.push(" if (!valueEnd) break;");
1203
+ out.push(` store<u64>(${outPtr}, ((<u64>valueStart) << 32) | (<u64>(<u32>valueEnd)), ${fieldOffset});`);
1204
+ out.push(` ${srcPtr} = valueEnd;`);
1205
+ out.push("}");
1206
+ return out;
1207
+ }
955
1208
  if (INTEGER_TYPES.includes(resolvedType)) {
956
1209
  const helper = SIGNED_INTEGER_TYPES.includes(resolvedType)
957
1210
  ? "__deserializeIntegerField"
@@ -1099,9 +1352,18 @@ export class JSONTransform extends Visitor {
1099
1352
  out.push(` if (changetype<usize>(value) == 0) {`);
1100
1353
  out.push(` value = changetype<${resolvedType}>(__new(offsetof<nonnull<${resolvedType}>>(), idof<nonnull<${resolvedType}>>()));`);
1101
1354
  out.push(` store<${resolvedType}>(${outPtr}, value, ${fieldOffset});`);
1355
+ out.push(` changetype<nonnull<${resolvedType}>>(value).__INITIALIZE();`);
1102
1356
  out.push(" }");
1103
- out.push(` ${srcPtr} = changetype<nonnull<${resolvedType}>>(value).__DESERIALIZE_FAST<${resolvedType}>(${valuePtr}, srcEnd, value);`);
1104
- out.push(` if (!${srcPtr}) break;`);
1357
+ out.push(` const __fe = changetype<nonnull<${resolvedType}>>(value).__DESERIALIZE_FAST<${resolvedType}>(${valuePtr}, srcEnd, value);`);
1358
+ out.push(` if (__fe) {`);
1359
+ out.push(` ${srcPtr} = __fe;`);
1360
+ out.push(` } else {`);
1361
+ out.push(` const __ve = JSON.Util.scanValueEnd<${resolvedType}>(${valuePtr}, srcEnd);`);
1362
+ out.push(` if (!__ve) break;`);
1363
+ out.push(` changetype<nonnull<${resolvedType}>>(value).__INITIALIZE();`);
1364
+ out.push(` changetype<nonnull<${resolvedType}>>(value).__DESERIALIZE_SLOW<${resolvedType}>(${valuePtr}, __ve, value);`);
1365
+ out.push(` ${srcPtr} = __ve;`);
1366
+ out.push(` }`);
1105
1367
  if (member.node.type.isNullable) {
1106
1368
  out.push(" }");
1107
1369
  }
@@ -1121,7 +1383,7 @@ export class JSONTransform extends Visitor {
1121
1383
  out.push(` store<${resolvedType}>(${outPtr}, value, ${fieldOffset});`);
1122
1384
  out.push(" }");
1123
1385
  out.push(` const valueStart = ${valuePtr};`);
1124
- out.push(` const valueEnd = JSON.Util.scanValueEnd(valueStart, srcEnd);`);
1386
+ out.push(` const valueEnd = JSON.Util.scanValueEnd<${resolvedType}>(valueStart, srcEnd);`);
1125
1387
  out.push(" if (!valueEnd) break;");
1126
1388
  if (fastPath) {
1127
1389
  out.push(` ${srcPtr} = changetype<nonnull<${resolvedType}>>(value).__DESERIALIZE_FAST<${resolvedType}>(valueStart, valueEnd, value);`);
@@ -1216,13 +1478,24 @@ export class JSONTransform extends Visitor {
1216
1478
  out.push(" if (changetype<usize>(item) == 0) {");
1217
1479
  out.push(` item = changetype<${valueType}>(__new(offsetof<nonnull<${valueType}>>(), idof<nonnull<${valueType}>>()));`);
1218
1480
  out.push(" unchecked((value[index] = item));");
1481
+ out.push(` changetype<nonnull<${valueType}>>(item).__INITIALIZE();`);
1219
1482
  out.push(" }");
1220
1483
  out.push(" } else {");
1221
1484
  out.push(` item = changetype<${valueType}>(__new(offsetof<nonnull<${valueType}>>(), idof<nonnull<${valueType}>>()));`);
1222
1485
  out.push(" value.push(item);");
1486
+ out.push(` changetype<nonnull<${valueType}>>(item).__INITIALIZE();`);
1223
1487
  out.push(" }");
1224
- out.push(` ${srcPtr} = changetype<nonnull<${valueType}>>(item).__DESERIALIZE_FAST<${valueType}>(${srcPtr}, srcEnd, item);`);
1225
- out.push(` if (!${srcPtr}) break;`);
1488
+ out.push(` const __es = ${srcPtr};`);
1489
+ out.push(` const __ee = changetype<nonnull<${valueType}>>(item).__DESERIALIZE_FAST<${valueType}>(${srcPtr}, srcEnd, item);`);
1490
+ out.push(` if (__ee) {`);
1491
+ out.push(` ${srcPtr} = __ee;`);
1492
+ out.push(` } else {`);
1493
+ out.push(` const __ve = JSON.Util.scanValueEnd<${valueType}>(__es, srcEnd);`);
1494
+ out.push(` if (!__ve) break;`);
1495
+ out.push(` changetype<nonnull<${valueType}>>(item).__INITIALIZE();`);
1496
+ out.push(` changetype<nonnull<${valueType}>>(item).__DESERIALIZE_SLOW<${valueType}>(__es, __ve, item);`);
1497
+ out.push(` ${srcPtr} = __ve;`);
1498
+ out.push(` }`);
1226
1499
  out.push(" index++;");
1227
1500
  out.push(` ${srcPtr} = JSON.Util.skipWhitespace(${srcPtr}, srcEnd);`);
1228
1501
  out.push(` const code = load<u16>(${srcPtr});`);
@@ -1243,7 +1516,7 @@ export class JSONTransform extends Visitor {
1243
1516
  out.push("}");
1244
1517
  return out;
1245
1518
  }
1246
- out.push(` ${srcPtr} = __deserializeArrayField_SWAR<${resolvedType}>(${valuePtr}, srcEnd, ${outPtr}, ${fieldOffset});`);
1519
+ out.push(` ${srcPtr} = __deserializeArrayField_SWAR<nonnull<${resolvedType}>>(${valuePtr}, srcEnd, ${outPtr}, ${fieldOffset});`);
1247
1520
  out.push(` if (!${srcPtr}) break;`);
1248
1521
  if (member.node.type.isNullable) {
1249
1522
  out.push(" }");
@@ -1264,6 +1537,7 @@ export class JSONTransform extends Visitor {
1264
1537
  }
1265
1538
  else if (resolvedType == "JSON.Value" ||
1266
1539
  resolvedType == "JSON.Obj" ||
1540
+ resolvedType == "JSON.Arr" ||
1267
1541
  isEnum(resolvedType, this.sources.get(this.schema.node.range.source), this.parser)) {
1268
1542
  out.push("break;");
1269
1543
  }
@@ -1273,6 +1547,29 @@ export class JSONTransform extends Visitor {
1273
1547
  return out;
1274
1548
  };
1275
1549
  indent = " ";
1550
+ const FAST_CHUNK_SIZE = 32;
1551
+ const fastChunkMethods = [];
1552
+ let fastChunkId = 0;
1553
+ const chunkFastBlocks = (blocks, tag, callIndent) => {
1554
+ if (blocks.length <= FAST_CHUNK_SIZE)
1555
+ return blocks.join("");
1556
+ let calls = "";
1557
+ for (let c = 0; c < blocks.length; c += FAST_CHUNK_SIZE) {
1558
+ const name = `__DESERIALIZE_FAST_${tag}_${fastChunkId++}`;
1559
+ const body = blocks
1560
+ .slice(c, c + FAST_CHUNK_SIZE)
1561
+ .join("")
1562
+ .replace(/\bbreak;/g, "return 0;");
1563
+ fastChunkMethods.push(`${name}(srcStart: usize, srcEnd: usize, dst: usize): usize {\n${body}\n return srcStart;\n}`);
1564
+ calls +=
1565
+ `${callIndent}srcStart = this.${name}(srcStart, srcEnd, dst);\n` +
1566
+ `${callIndent}if (srcStart == 0) break;\n`;
1567
+ }
1568
+ return calls;
1569
+ };
1570
+ const chunkFastBlocksOptional = (blocks, _tag, _callIndent, _needsKp) => {
1571
+ return blocks.join("");
1572
+ };
1276
1573
  DESERIALIZE_FAST += indent + "const start = srcStart;\n";
1277
1574
  DESERIALIZE_FAST += indent + "const dst = changetype<usize>(out);\n";
1278
1575
  DESERIALIZE_FAST += indent + "do {\n";
@@ -1282,6 +1579,7 @@ export class JSONTransform extends Visitor {
1282
1579
  indent + "if (load<u16>(srcStart) !== 0x7b) break; // {\n";
1283
1580
  DESERIALIZE_FAST += indent + "srcStart += 2;\n";
1284
1581
  DESERIALIZE_FAST += indent + "let seenAny = false;\n\n";
1582
+ const t1opt = [];
1285
1583
  for (let i = 0; i < this.schema.members.length; i++) {
1286
1584
  const member = this.schema.members[i];
1287
1585
  const key = JSON.stringify(member.alias || member.name);
@@ -1298,89 +1596,92 @@ export class JSONTransform extends Visitor {
1298
1596
  const isOptional = member.flags.has(PropertyFlags.OmitNull) ||
1299
1597
  member.flags.has(PropertyFlags.OmitIf);
1300
1598
  if (!deserializerFirst.length || !deserializerNext.length) {
1301
- DESERIALIZE_FAST += indent + "break;\n\n";
1599
+ t1opt.push(indent + "break;\n\n");
1302
1600
  continue;
1303
1601
  }
1304
- DESERIALIZE_FAST += indent + "if (!seenAny) {\n";
1602
+ let blk = indent + "if (!seenAny) {\n";
1305
1603
  indent += " ";
1306
- DESERIALIZE_FAST +=
1604
+ blk +=
1307
1605
  indent +
1308
1606
  `if ( // ${firstKeySection}\n${(indent += " ")}${getComparisions(firstKeySection, "srcStart", "!=").join("\n" + indent + "|| ")}\n${(indent = indent.slice(0, -2))}) {\n`;
1309
1607
  indent += " ";
1310
1608
  if (isOptional) {
1311
- DESERIALIZE_FAST += indent + "// optional @omitnull field omitted\n";
1609
+ blk += indent + "// optional @omitnull field omitted\n";
1312
1610
  }
1313
1611
  else {
1314
- DESERIALIZE_FAST += indent + "break;\n";
1612
+ blk += indent + "break;\n";
1315
1613
  }
1316
1614
  indent = indent.slice(0, -2);
1317
- DESERIALIZE_FAST += indent + "} else {\n";
1615
+ blk += indent + "} else {\n";
1318
1616
  indent += " ";
1319
1617
  if (!inlineStringValue)
1320
- DESERIALIZE_FAST += indent + `srcStart += ${firstKeyOffset};\n`;
1321
- DESERIALIZE_FAST +=
1618
+ blk += indent + `srcStart += ${firstKeyOffset};\n`;
1619
+ blk +=
1322
1620
  indent +
1323
1621
  `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";
1622
+ blk += indent + deserializerFirst.join("\n" + indent) + "\n";
1623
+ blk += indent + "seenAny = true;\n";
1327
1624
  indent = indent.slice(0, -2);
1328
- DESERIALIZE_FAST += indent + "}\n";
1625
+ blk += indent + "}\n";
1329
1626
  indent = indent.slice(0, -2);
1330
- DESERIALIZE_FAST += indent + "} else {\n";
1627
+ blk += indent + "} else {\n";
1331
1628
  indent += " ";
1332
- DESERIALIZE_FAST +=
1629
+ blk +=
1333
1630
  indent +
1334
1631
  `if ( // ${nextKeySection}\n${(indent += " ")}${getComparisions(nextKeySection, "srcStart", "!=").join("\n" + indent + "|| ")}\n${(indent = indent.slice(0, -2))}) {\n`;
1335
1632
  indent += " ";
1336
1633
  if (isOptional) {
1337
- DESERIALIZE_FAST += indent + "// optional @omitnull field omitted\n";
1634
+ blk += indent + "// optional @omitnull field omitted\n";
1338
1635
  }
1339
1636
  else {
1340
- DESERIALIZE_FAST += indent + "break;\n";
1637
+ blk += indent + "break;\n";
1341
1638
  }
1342
1639
  indent = indent.slice(0, -2);
1343
- DESERIALIZE_FAST += indent + "} else {\n";
1640
+ blk += indent + "} else {\n";
1344
1641
  indent += " ";
1345
1642
  if (!inlineStringValue)
1346
- DESERIALIZE_FAST += indent + `srcStart += ${nextKeyOffset};\n`;
1347
- DESERIALIZE_FAST +=
1643
+ blk += indent + `srcStart += ${nextKeyOffset};\n`;
1644
+ blk +=
1348
1645
  indent +
1349
1646
  `if (JSON.Util.isSpace(load<u16>(${inlineStringValue ? `srcStart + ${nextKeyOffset}` : "srcStart"}))) break;\n`;
1350
- DESERIALIZE_FAST +=
1351
- indent + deserializerNext.join("\n" + indent) + "\n";
1647
+ blk += indent + deserializerNext.join("\n" + indent) + "\n";
1352
1648
  indent = indent.slice(0, -2);
1353
- DESERIALIZE_FAST += indent + "}\n";
1649
+ blk += indent + "}\n";
1354
1650
  indent = indent.slice(0, -2);
1355
- DESERIALIZE_FAST += indent + "}\n\n";
1651
+ blk += indent + "}\n\n";
1652
+ t1opt.push(blk);
1356
1653
  }
1654
+ DESERIALIZE_FAST += chunkFastBlocksOptional(t1opt, "T1O", indent, false);
1357
1655
  }
1358
1656
  else {
1657
+ const t1blocks = [];
1359
1658
  for (let i = 0; i < this.schema.members.length; i++) {
1360
1659
  const member = this.schema.members[i];
1361
1660
  const key = JSON.stringify(member.alias || member.name);
1362
1661
  if (key.length <= 2)
1363
1662
  throw new Error("Key cannot be empty!");
1364
1663
  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`;
1664
+ let blk = indent +
1665
+ `if ( // ${keySection}\n${(indent += " ")}${getComparisions(keySection, "srcStart", "!=").join("\n" + indent + "|| ")}\n${(indent = indent.slice(0, -2))}) break;\n`;
1368
1666
  const keyOffset = keySection.length << 1;
1369
1667
  const resolvedType = stripNull(member.type);
1370
1668
  const inlineStringValue = ["string", "String"].includes(resolvedType);
1371
1669
  if (!inlineStringValue) {
1372
- DESERIALIZE_FAST += indent + `srcStart += ${keyOffset};\n\n`;
1670
+ blk += indent + `srcStart += ${keyOffset};\n\n`;
1373
1671
  }
1374
1672
  const deserializer = getDeserializer(member.type, "srcStart", "dst", member, inlineStringValue ? keyOffset : 0, true);
1375
1673
  if (!deserializer.length) {
1376
- DESERIALIZE_FAST += indent + "break;\n\n";
1674
+ blk += indent + "break;\n\n";
1675
+ t1blocks.push(blk);
1377
1676
  continue;
1378
1677
  }
1379
- DESERIALIZE_FAST +=
1678
+ blk +=
1380
1679
  indent +
1381
1680
  `if (JSON.Util.isSpace(load<u16>(${inlineStringValue ? `srcStart + ${keyOffset}` : "srcStart"}))) break;\n`;
1382
- DESERIALIZE_FAST += indent + deserializer.join("\n" + indent) + "\n\n";
1681
+ blk += indent + deserializer.join("\n" + indent) + "\n\n";
1682
+ t1blocks.push(blk);
1383
1683
  }
1684
+ DESERIALIZE_FAST += chunkFastBlocks(t1blocks, "T1", indent);
1384
1685
  }
1385
1686
  DESERIALIZE_FAST +=
1386
1687
  indent + "if (load<u16>(srcStart) !== 0x7d) break; // }\n";
@@ -1399,31 +1700,32 @@ export class JSONTransform extends Visitor {
1399
1700
  DESERIALIZE_FAST += skip;
1400
1701
  DESERIALIZE_FAST += i2 + "if (load<u16>(srcStart) != 0x7b) break; // {\n";
1401
1702
  DESERIALIZE_FAST += i2 + "srcStart += 2;\n";
1703
+ const t2blocks = [];
1402
1704
  for (let i = 0; i < this.schema.members.length; i++) {
1403
1705
  const member = this.schema.members[i];
1404
1706
  const key = JSON.stringify(member.alias || member.name);
1405
1707
  const keyBytes = key.length << 1;
1406
- DESERIALIZE_FAST += "\n";
1407
- DESERIALIZE_FAST += skip;
1408
- DESERIALIZE_FAST +=
1708
+ let blk = "\n";
1709
+ blk += skip;
1710
+ blk +=
1409
1711
  i2 +
1410
1712
  `if ( // ${key}\n${i2} ` +
1411
1713
  getComparisions(key, "srcStart", "!=").join("\n" + i2 + " || ") +
1412
1714
  `\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";
1715
+ blk += i2 + `srcStart += ${keyBytes};\n`;
1716
+ blk += skip;
1717
+ blk += i2 + "if (load<u16>(srcStart) != 0x3a) break; // :\n";
1718
+ blk += i2 + "srcStart += 2;\n";
1719
+ blk += skip;
1720
+ blk += i2 + tier2Desers[i].join("\n" + i2) + "\n";
1420
1721
  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";
1722
+ blk += skip;
1723
+ blk += i2 + "if (load<u16>(srcStart) != 0x2c) break; // ,\n";
1724
+ blk += i2 + "srcStart += 2;\n";
1425
1725
  }
1726
+ t2blocks.push(blk);
1426
1727
  }
1728
+ DESERIALIZE_FAST += chunkFastBlocks(t2blocks, "T2", i2);
1427
1729
  DESERIALIZE_FAST += "\n";
1428
1730
  DESERIALIZE_FAST += skip;
1429
1731
  DESERIALIZE_FAST += i2 + "if (load<u16>(srcStart) != 0x7d) break; // }\n";
@@ -1445,33 +1747,34 @@ export class JSONTransform extends Visitor {
1445
1747
  DESERIALIZE_FAST += i2 + "let kp: usize = 0;\n";
1446
1748
  if (multi)
1447
1749
  DESERIALIZE_FAST += i2 + "let seenAny = false;\n";
1750
+ const t2opt = [];
1448
1751
  for (let i = 0; i < this.schema.members.length; i++) {
1449
1752
  const member = this.schema.members[i];
1450
1753
  const key = JSON.stringify(member.alias || member.name);
1451
1754
  const keyBytes = key.length << 1;
1452
- DESERIALIZE_FAST += "\n";
1453
- DESERIALIZE_FAST +=
1454
- i2 + "kp = JSON.Util.skipWhitespace(srcStart, srcEnd);\n";
1755
+ let blk = "\n";
1756
+ blk += i2 + "kp = JSON.Util.skipWhitespace(srcStart, srcEnd);\n";
1455
1757
  if (multi && i > 0) {
1456
- DESERIALIZE_FAST +=
1758
+ blk +=
1457
1759
  i2 +
1458
1760
  "if (seenAny && load<u16>(kp) == 0x2c) kp = JSON.Util.skipWhitespace(kp + 2, srcEnd);\n";
1459
1761
  }
1460
- DESERIALIZE_FAST +=
1762
+ blk +=
1461
1763
  i2 +
1462
1764
  `if ( // ${key}\n${i2} ` +
1463
1765
  getComparisions(key, "kp", "==").join("\n" + i2 + " && ") +
1464
1766
  `\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";
1767
+ blk += i3 + `kp += ${keyBytes};\n`;
1768
+ blk += i3 + "kp = JSON.Util.skipWhitespace(kp, srcEnd);\n";
1769
+ blk += i3 + "if (load<u16>(kp) != 0x3a) break; // :\n";
1770
+ blk += i3 + "srcStart = JSON.Util.skipWhitespace(kp + 2, srcEnd);\n";
1771
+ blk += i3 + tier2Desers[i].join("\n" + i3) + "\n";
1471
1772
  if (multi)
1472
- DESERIALIZE_FAST += i3 + "seenAny = true;\n";
1473
- DESERIALIZE_FAST += i2 + "}\n";
1773
+ blk += i3 + "seenAny = true;\n";
1774
+ blk += i2 + "}\n";
1775
+ t2opt.push(blk);
1474
1776
  }
1777
+ DESERIALIZE_FAST += chunkFastBlocksOptional(t2opt, "T2O", i2, true);
1475
1778
  DESERIALIZE_FAST += "\n";
1476
1779
  DESERIALIZE_FAST +=
1477
1780
  i2 + "srcStart = JSON.Util.skipWhitespace(srcStart, srcEnd);\n";
@@ -1498,7 +1801,7 @@ export class JSONTransform extends Visitor {
1498
1801
  DESERIALIZE += indent + " let keyStart: usize = 0;\n";
1499
1802
  DESERIALIZE += indent + " let keyEnd: usize = 0;\n";
1500
1803
  DESERIALIZE += indent + " let isKey = false;\n";
1501
- if (!STRICT || sortedMembers.object.length || sortedMembers.array.length)
1804
+ if (!STRICT || slowObjectMembers.length || slowArrayMembers.length)
1502
1805
  DESERIALIZE += indent + " let depth: i32 = 0;\n";
1503
1806
  DESERIALIZE += indent + " let lastIndex: usize = 0;\n\n";
1504
1807
  DESERIALIZE +=
@@ -1643,8 +1946,37 @@ export class JSONTransform extends Visitor {
1643
1946
  DESERIALIZE += toMemCDecl(Math.max(...members.map((m) => (m.alias || m.name).length << 1)), " ");
1644
1947
  }
1645
1948
  };
1949
+ const getLazyRangeStore = (member, valueStart, valueEnd, prefix) => {
1950
+ return (prefix +
1951
+ `store<u64>(changetype<usize>(out), ((<u64>${valueStart}) << 32) | (<u64>(<u32>${valueEnd})), offsetof<this>(${JSON.stringify(member.name)}));\n`);
1952
+ };
1953
+ const getSlowValueStore = (member, valueStart, valueEnd, prefix) => {
1954
+ if (member.flags.has(PropertyFlags.Lazy))
1955
+ return getLazyRangeStore(member, valueStart, valueEnd, prefix);
1956
+ return (prefix +
1957
+ `store<${member.type}>(changetype<usize>(out), JSON.__deserialize<${member.type}>(${valueStart}, ${valueEnd}), offsetof<this>(${JSON.stringify(member.name)}));\n`);
1958
+ };
1959
+ const getSlowBooleanStore = (member, value, valueStart, valueEnd, prefix) => {
1960
+ if (member.flags.has(PropertyFlags.Lazy))
1961
+ return getLazyRangeStore(member, valueStart, valueEnd, prefix);
1962
+ if (member.type.startsWith("JSON.Box<bool") ||
1963
+ member.type.startsWith("JSON.Box<boolean") ||
1964
+ member.type.startsWith("Box<bool") ||
1965
+ member.type.startsWith("Box<boolean")) {
1966
+ return (prefix +
1967
+ `store<${member.type}>(changetype<usize>(out), changetype<${member.type}>(JSON.Box.from<bool>(${value})), offsetof<this>(${JSON.stringify(member.name)}));\n`);
1968
+ }
1969
+ return (prefix +
1970
+ `store<boolean>(changetype<usize>(out), ${value}, offsetof<this>(${JSON.stringify(member.name)}));\n`);
1971
+ };
1972
+ const getSlowNullStore = (member, valueStart, valueEnd, prefix) => {
1973
+ if (member.flags.has(PropertyFlags.Lazy))
1974
+ return getLazyRangeStore(member, valueStart, valueEnd, prefix);
1975
+ return (prefix +
1976
+ `store<usize>(changetype<usize>(out), 0, offsetof<this>(${JSON.stringify(member.name)}));\n`);
1977
+ };
1646
1978
  let mbElse = " ";
1647
- if (!STRICT || sortedMembers.string.length) {
1979
+ if (!STRICT || slowStringMembers.length) {
1648
1980
  DESERIALIZE += mbElse + "if (code == 34) {\n";
1649
1981
  DESERIALIZE += " lastIndex = srcStart;\n";
1650
1982
  DESERIALIZE += " srcStart += 2;\n";
@@ -1657,7 +1989,7 @@ export class JSONTransform extends Visitor {
1657
1989
  ' console.log("Value (string, ' +
1658
1990
  ++id +
1659
1991
  '): " + JSON.Util.ptrToStr(lastIndex, srcStart + 2));';
1660
- generateGroups(sortedMembers.string, (group) => {
1992
+ generateGroups(slowStringMembers, (group) => {
1661
1993
  generateConsts(group);
1662
1994
  const first = group[0];
1663
1995
  const fName = first.alias || first.name;
@@ -1669,15 +2001,7 @@ export class JSONTransform extends Visitor {
1669
2001
  ") { // " +
1670
2002
  fName +
1671
2003
  "\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";
2004
+ DESERIALIZE += getSlowValueStore(first, "lastIndex", "srcStart + 2", indent + " ");
1681
2005
  DESERIALIZE += indent + " srcStart += 4;\n";
1682
2006
  DESERIALIZE += indent + " keyStart = 0;\n";
1683
2007
  DESERIALIZE += indent + " break;\n";
@@ -1693,15 +2017,7 @@ export class JSONTransform extends Visitor {
1693
2017
  ") { // " +
1694
2018
  memName +
1695
2019
  "\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";
2020
+ DESERIALIZE += getSlowValueStore(mem, "lastIndex", "srcStart + 2", indent + " ");
1705
2021
  DESERIALIZE += indent + " srcStart += 4;\n";
1706
2022
  DESERIALIZE += indent + " keyStart = 0;\n";
1707
2023
  DESERIALIZE += indent + " break;\n";
@@ -1728,7 +2044,7 @@ export class JSONTransform extends Visitor {
1728
2044
  DESERIALIZE += " }\n";
1729
2045
  mbElse = " else ";
1730
2046
  }
1731
- if (!STRICT || sortedMembers.number.length) {
2047
+ if (!STRICT || slowNumberMembers.length) {
1732
2048
  DESERIALIZE += mbElse + "if (code - 48 <= 9 || code == 45) {\n";
1733
2049
  DESERIALIZE += " lastIndex = srcStart;\n";
1734
2050
  DESERIALIZE += " srcStart += 2;\n";
@@ -1741,7 +2057,7 @@ export class JSONTransform extends Visitor {
1741
2057
  ' console.log("Value (number, ' +
1742
2058
  ++id +
1743
2059
  '): " + JSON.Util.ptrToStr(lastIndex, srcStart));';
1744
- generateGroups(sortedMembers.number, (group) => {
2060
+ generateGroups(slowNumberMembers, (group) => {
1745
2061
  generateConsts(group);
1746
2062
  const first = group[0];
1747
2063
  const fName = first.alias || first.name;
@@ -1759,15 +2075,7 @@ export class JSONTransform extends Visitor {
1759
2075
  ") { // " +
1760
2076
  fName +
1761
2077
  "\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";
2078
+ DESERIALIZE += getSlowValueStore(first, "lastIndex", "srcStart", indent + " ");
1771
2079
  DESERIALIZE += indent + " srcStart += 2;\n";
1772
2080
  DESERIALIZE += indent + " keyStart = 0;\n";
1773
2081
  DESERIALIZE += indent + " break;\n";
@@ -1789,15 +2097,7 @@ export class JSONTransform extends Visitor {
1789
2097
  ") { // " +
1790
2098
  memName +
1791
2099
  "\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";
2100
+ DESERIALIZE += getSlowValueStore(mem, "lastIndex", "srcStart", indent + " ");
1801
2101
  DESERIALIZE += indent + " srcStart += 2;\n";
1802
2102
  DESERIALIZE += indent + " keyStart = 0;\n";
1803
2103
  DESERIALIZE += indent + " break;\n";
@@ -1824,7 +2124,7 @@ export class JSONTransform extends Visitor {
1824
2124
  DESERIALIZE += " }";
1825
2125
  mbElse = " else ";
1826
2126
  }
1827
- if (!STRICT || sortedMembers.object.length) {
2127
+ if (!STRICT || slowObjectMembers.length) {
1828
2128
  DESERIALIZE += mbElse + "if (code == 123) {\n";
1829
2129
  DESERIALIZE += " lastIndex = srcStart;\n";
1830
2130
  DESERIALIZE += " depth++;\n";
@@ -1844,7 +2144,7 @@ export class JSONTransform extends Visitor {
1844
2144
  ++id +
1845
2145
  '): " + JSON.Util.ptrToStr(lastIndex, srcStart));';
1846
2146
  indent = " ";
1847
- generateGroups(sortedMembers.object, (group) => {
2147
+ generateGroups(slowObjectMembers, (group) => {
1848
2148
  generateConsts(group);
1849
2149
  const first = group[0];
1850
2150
  const fName = first.alias || first.name;
@@ -1855,15 +2155,7 @@ export class JSONTransform extends Visitor {
1855
2155
  ") { // " +
1856
2156
  fName +
1857
2157
  "\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";
2158
+ DESERIALIZE += getSlowValueStore(first, "lastIndex", "srcStart", indent + " ");
1867
2159
  DESERIALIZE += indent + " keyStart = 0;\n";
1868
2160
  DESERIALIZE += indent + " break;\n";
1869
2161
  DESERIALIZE += indent + " }";
@@ -1877,15 +2169,7 @@ export class JSONTransform extends Visitor {
1877
2169
  ") { // " +
1878
2170
  memName +
1879
2171
  "\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";
2172
+ DESERIALIZE += getSlowValueStore(mem, "lastIndex", "srcStart", indent + " ");
1889
2173
  DESERIALIZE += indent + " keyStart = 0;\n";
1890
2174
  DESERIALIZE += indent + " break;\n";
1891
2175
  DESERIALIZE += indent + " }";
@@ -1912,7 +2196,7 @@ export class JSONTransform extends Visitor {
1912
2196
  DESERIALIZE += " }";
1913
2197
  mbElse = " else ";
1914
2198
  }
1915
- if (!STRICT || sortedMembers.array.length) {
2199
+ if (!STRICT || slowArrayMembers.length) {
1916
2200
  DESERIALIZE += mbElse + "if (code == 91) {\n";
1917
2201
  DESERIALIZE += " lastIndex = srcStart;\n";
1918
2202
  DESERIALIZE += " depth++;\n";
@@ -1932,7 +2216,7 @@ export class JSONTransform extends Visitor {
1932
2216
  ++id +
1933
2217
  '): " + JSON.Util.ptrToStr(lastIndex, srcStart));';
1934
2218
  indent = " ";
1935
- generateGroups(sortedMembers.array, (group) => {
2219
+ generateGroups(slowArrayMembers, (group) => {
1936
2220
  generateConsts(group);
1937
2221
  const first = group[0];
1938
2222
  const fName = first.alias || first.name;
@@ -1944,15 +2228,7 @@ export class JSONTransform extends Visitor {
1944
2228
  ") { // " +
1945
2229
  fName +
1946
2230
  "\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";
2231
+ DESERIALIZE += getSlowValueStore(first, "lastIndex", "srcStart", indent + " ");
1956
2232
  DESERIALIZE += indent + " keyStart = 0;\n";
1957
2233
  DESERIALIZE += indent + " break;\n";
1958
2234
  DESERIALIZE += indent + " }";
@@ -1967,15 +2243,7 @@ export class JSONTransform extends Visitor {
1967
2243
  ") { // " +
1968
2244
  memName +
1969
2245
  "\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";
2246
+ DESERIALIZE += getSlowValueStore(mem, "lastIndex", "srcStart", indent + " ");
1979
2247
  DESERIALIZE += indent + " keyStart = 0;\n";
1980
2248
  DESERIALIZE += indent + " break;\n";
1981
2249
  DESERIALIZE += indent + " }";
@@ -2002,7 +2270,7 @@ export class JSONTransform extends Visitor {
2002
2270
  DESERIALIZE += " }";
2003
2271
  mbElse = " else ";
2004
2272
  }
2005
- if (!STRICT || sortedMembers.boolean.length) {
2273
+ if (!STRICT || slowBooleanMembers.length) {
2006
2274
  DESERIALIZE += mbElse + "if (code == 116) {\n";
2007
2275
  DESERIALIZE +=
2008
2276
  " if (load<u64>(srcStart) == 28429475166421108) {\n";
@@ -2012,7 +2280,7 @@ export class JSONTransform extends Visitor {
2012
2280
  ' console.log("Value (bool, ' +
2013
2281
  ++id +
2014
2282
  '): " + JSON.Util.ptrToStr(lastIndex, srcStart - 8));';
2015
- generateGroups(sortedMembers.boolean, (group) => {
2283
+ generateGroups(slowBooleanMembers, (group) => {
2016
2284
  generateConsts(group);
2017
2285
  const first = group[0];
2018
2286
  const fName = first.alias || first.name;
@@ -2024,27 +2292,7 @@ export class JSONTransform extends Visitor {
2024
2292
  ") { // " +
2025
2293
  fName +
2026
2294
  "\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
- }
2295
+ DESERIALIZE += getSlowBooleanStore(first, "true", "srcStart - 8", "srcStart", indent + " ");
2048
2296
  DESERIALIZE += indent + " srcStart += 2;\n";
2049
2297
  DESERIALIZE += indent + " keyStart = 0;\n";
2050
2298
  DESERIALIZE += indent + " break;\n";
@@ -2060,27 +2308,7 @@ export class JSONTransform extends Visitor {
2060
2308
  ") { // " +
2061
2309
  memName +
2062
2310
  "\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
- }
2311
+ DESERIALIZE += getSlowBooleanStore(mem, "true", "srcStart - 8", "srcStart", indent + " ");
2084
2312
  DESERIALIZE += indent + " srcStart += 2;\n";
2085
2313
  DESERIALIZE += indent + " keyStart = 0;\n";
2086
2314
  DESERIALIZE += indent + " break;\n";
@@ -2116,7 +2344,7 @@ export class JSONTransform extends Visitor {
2116
2344
  ' console.log("Value (bool, ' +
2117
2345
  ++id +
2118
2346
  '): " + JSON.Util.ptrToStr(lastIndex, srcStart - 10));';
2119
- generateGroups(sortedMembers.boolean, (group) => {
2347
+ generateGroups(slowBooleanMembers, (group) => {
2120
2348
  generateConsts(group);
2121
2349
  const first = group[0];
2122
2350
  const fName = first.alias || first.name;
@@ -2128,27 +2356,7 @@ export class JSONTransform extends Visitor {
2128
2356
  ") { // " +
2129
2357
  fName +
2130
2358
  "\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
- }
2359
+ DESERIALIZE += getSlowBooleanStore(first, "false", "srcStart - 10", "srcStart", indent + " ");
2152
2360
  DESERIALIZE += indent + " srcStart += 2;\n";
2153
2361
  DESERIALIZE += indent + " keyStart = 0;\n";
2154
2362
  DESERIALIZE += indent + " break;\n";
@@ -2164,27 +2372,7 @@ export class JSONTransform extends Visitor {
2164
2372
  ") { // " +
2165
2373
  memName +
2166
2374
  "\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
- }
2375
+ DESERIALIZE += getSlowBooleanStore(mem, "false", "srcStart - 10", "srcStart", indent + " ");
2188
2376
  DESERIALIZE += indent + " srcStart += 2;\n";
2189
2377
  DESERIALIZE += indent + " keyStart = 0;\n";
2190
2378
  DESERIALIZE += indent + " break;\n";
@@ -2209,7 +2397,7 @@ export class JSONTransform extends Visitor {
2209
2397
  DESERIALIZE += "\n }";
2210
2398
  mbElse = " else ";
2211
2399
  }
2212
- if (!STRICT || sortedMembers.null.length) {
2400
+ if (!STRICT || slowNullMembers.length) {
2213
2401
  DESERIALIZE += mbElse + "if (code == 110) {\n";
2214
2402
  DESERIALIZE +=
2215
2403
  " if (load<u64>(srcStart) == 30399761348886638) {\n";
@@ -2219,7 +2407,7 @@ export class JSONTransform extends Visitor {
2219
2407
  ' console.log("Value (null, ' +
2220
2408
  ++id +
2221
2409
  '): " + JSON.Util.ptrToStr(lastIndex, srcStart - 8));';
2222
- generateGroups(sortedMembers.null, (group) => {
2410
+ generateGroups(slowNullMembers, (group) => {
2223
2411
  generateConsts(group);
2224
2412
  const first = group[0];
2225
2413
  const fName = first.alias || first.name;
@@ -2231,11 +2419,7 @@ export class JSONTransform extends Visitor {
2231
2419
  ") { // " +
2232
2420
  fName +
2233
2421
  "\n";
2234
- DESERIALIZE +=
2235
- indent +
2236
- " store<usize>(changetype<usize>(out), 0, offsetof<this>(" +
2237
- JSON.stringify(first.name) +
2238
- "));\n";
2422
+ DESERIALIZE += getSlowNullStore(first, "srcStart - 8", "srcStart", indent + " ");
2239
2423
  DESERIALIZE += indent + " srcStart += 2;\n";
2240
2424
  DESERIALIZE += indent + " keyStart = 0;\n";
2241
2425
  DESERIALIZE += indent + " break;\n";
@@ -2251,11 +2435,7 @@ export class JSONTransform extends Visitor {
2251
2435
  ") { // " +
2252
2436
  memName +
2253
2437
  "\n";
2254
- DESERIALIZE +=
2255
- indent +
2256
- " store<usize>(changetype<usize>(out), 0, offsetof<this>(" +
2257
- JSON.stringify(mem.name) +
2258
- "));\n";
2438
+ DESERIALIZE += getSlowNullStore(mem, "srcStart - 8", "srcStart", indent + " ");
2259
2439
  DESERIALIZE += indent + " srcStart += 2;\n";
2260
2440
  DESERIALIZE += indent + " keyStart = 0;\n";
2261
2441
  DESERIALIZE += indent + " break;\n";
@@ -2308,6 +2488,11 @@ export class JSONTransform extends Visitor {
2308
2488
  console.log(INITIALIZE);
2309
2489
  console.log(DESERIALIZE_CUSTOM || DESERIALIZE);
2310
2490
  }
2491
+ const WIDE_STRUCT_FIELD_LIMIT = 32;
2492
+ if (this.schema.members.length > WIDE_STRUCT_FIELD_LIMIT) {
2493
+ INITIALIZE = INITIALIZE.replace(/^@inline /, "");
2494
+ DESERIALIZE_FAST = DESERIALIZE_FAST.replace(/^@inline /, "");
2495
+ }
2311
2496
  const SERIALIZE_METHOD = SimpleParser.parseClassMember(SERIALIZE_CUSTOM || SERIALIZE, node);
2312
2497
  const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node);
2313
2498
  const DESERIALIZE_CUSTOM_METHOD = DESERIALIZE_CUSTOM
@@ -2334,6 +2519,13 @@ export class JSONTransform extends Visitor {
2334
2519
  DESERIALIZE_FAST_METHOD &&
2335
2520
  !node.members.find((v) => v.name.text == "__DESERIALIZE_FAST"))
2336
2521
  node.members.push(DESERIALIZE_FAST_METHOD);
2522
+ if (useFastPath && !DESERIALIZE_CUSTOM) {
2523
+ for (const chunk of fastChunkMethods) {
2524
+ const chunkMethod = SimpleParser.parseClassMember(chunk, node);
2525
+ if (!node.members.find((v) => v.name.text == chunkMethod.name.text))
2526
+ node.members.push(chunkMethod);
2527
+ }
2528
+ }
2337
2529
  super.visitClassDeclaration(node);
2338
2530
  }
2339
2531
  getSchema(name) {
@@ -2343,9 +2535,9 @@ export class JSONTransform extends Visitor {
2343
2535
  .find((s) => s.name == name) || null);
2344
2536
  }
2345
2537
  generateEmptyMethods(node) {
2346
- const SERIALIZE_EMPTY = "@inline __SERIALIZE(ptr: usize): void {\n bs.proposeSize(4);\n store<u32>(bs.offset, 8192123);\n bs.offset += 4;\n}";
2347
- const INITIALIZE_EMPTY = "@inline __INITIALIZE(): this {\n return this;\n}";
2348
- const DESERIALIZE_SLOW_EMPTY = "@inline __DESERIALIZE_SLOW<__JSON_T>(srcStart: usize, srcEnd: usize, out: __JSON_T): usize {\n return srcEnd;\n}";
2538
+ const SERIALIZE_EMPTY = "__SERIALIZE(ptr: usize): void {\n bs.proposeSize(4);\n store<u32>(bs.offset, 8192123);\n bs.offset += 4;\n}";
2539
+ const INITIALIZE_EMPTY = "__INITIALIZE(): this {\n return this;\n}";
2540
+ const DESERIALIZE_SLOW_EMPTY = "__DESERIALIZE_SLOW<__JSON_T>(srcStart: usize, srcEnd: usize, out: __JSON_T): usize {\n return srcEnd;\n}";
2349
2541
  if (DEBUG > 0) {
2350
2542
  console.log(SERIALIZE_EMPTY);
2351
2543
  console.log(INITIALIZE_EMPTY);
@@ -2521,9 +2713,11 @@ export class JSONTransform extends Visitor {
2521
2713
  "Date",
2522
2714
  "JSON.Value",
2523
2715
  "JSON.Obj",
2716
+ "JSON.Arr",
2524
2717
  "JSON.Raw",
2525
2718
  "Value",
2526
2719
  "Obj",
2720
+ "Arr",
2527
2721
  "Raw",
2528
2722
  ...this.schemas
2529
2723
  .get(this.schema.node.range.source.internalPath)
@@ -2552,25 +2746,8 @@ var JSONMode;
2552
2746
  JSONMode[JSONMode["NAIVE"] = 2] = "NAIVE";
2553
2747
  })(JSONMode || (JSONMode = {}));
2554
2748
  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
- }
2749
+ let MODE_TEXT = "SWAR";
2750
+ const STAGES = process.env["JSON_STAGES"] !== undefined;
2574
2751
  export default class Transformer extends Transform {
2575
2752
  afterInitialize(program) {
2576
2753
  if (program.options.hasFeature(16))
@@ -2591,6 +2768,21 @@ export default class Transformer extends Transform {
2591
2768
  }
2592
2769
  }
2593
2770
  }
2771
+ switch (MODE) {
2772
+ case JSONMode.SWAR:
2773
+ MODE_TEXT = "SWAR";
2774
+ break;
2775
+ case JSONMode.SIMD:
2776
+ MODE_TEXT = "SIMD";
2777
+ break;
2778
+ case JSONMode.NAIVE:
2779
+ MODE_TEXT = "NAIVE";
2780
+ break;
2781
+ }
2782
+ if (STAGES)
2783
+ console.log("[transform]: Finished initializing transformer in " +
2784
+ MODE_TEXT +
2785
+ " mode");
2594
2786
  program.registerConstantInteger("JSON_MODE", Type.i32, i64_new(MODE));
2595
2787
  if (JSON_CACHE_CONFIG.enabled) {
2596
2788
  program.registerConstantInteger("JSON_CACHE", Type.bool, i64_one);
@@ -2599,6 +2791,8 @@ export default class Transformer extends Transform {
2599
2791
  }
2600
2792
  afterParse(parser) {
2601
2793
  const transformer = new JSONTransform();
2794
+ if (STAGES)
2795
+ console.log("[transform]: Walking AST and generating schemas");
2602
2796
  const sources = parser.sources
2603
2797
  .filter((source) => {
2604
2798
  const p = source.internalPath;
@@ -2648,22 +2842,17 @@ export default class Transformer extends Transform {
2648
2842
  writeFileSync(path.join(process.cwd(), this.baseDir, removeExtension(source.normalizedPath) + ".tmp.ts"), toString(source));
2649
2843
  }
2650
2844
  }
2651
- }
2652
- }
2653
- function sortMembers(members) {
2654
- return members.sort((a, b) => {
2655
- const aMove = a.flags.has(PropertyFlags.OmitIf) || a.flags.has(PropertyFlags.OmitNull);
2656
- const bMove = b.flags.has(PropertyFlags.OmitIf) || b.flags.has(PropertyFlags.OmitNull);
2657
- if (aMove && !bMove) {
2658
- return -1;
2659
- }
2660
- else if (!aMove && bMove) {
2661
- return 1;
2662
- }
2663
- else {
2664
- return 0;
2845
+ for (const source of parser.sources) {
2846
+ const p = source.internalPath;
2847
+ if (p === "assembly/index" || p.endsWith("/json-as/assembly/index")) {
2848
+ source.sourceKind = 2;
2849
+ }
2665
2850
  }
2666
- });
2851
+ if (STAGES)
2852
+ console.log("[transform]: Finished generating " +
2853
+ transformer.schemas.size +
2854
+ " schemas");
2855
+ }
2667
2856
  }
2668
2857
  function toU16(data, offset = 0) {
2669
2858
  return data.charCodeAt(offset + 0);
@@ -2808,6 +2997,92 @@ function sizeof(type) {
2808
2997
  else
2809
2998
  return 0;
2810
2999
  }
3000
+ function classLazyMode(node) {
3001
+ const dec = node.decorators?.find((d) => {
3002
+ const n = d.name.text;
3003
+ return n === "json" || n === "serializable";
3004
+ });
3005
+ if (!dec || !dec.args || dec.args.length === 0)
3006
+ return "none";
3007
+ const arg = dec.args[0];
3008
+ if (arg.kind !== NodeKind.Literal ||
3009
+ arg.literalKind !== 6)
3010
+ return "none";
3011
+ const obj = arg;
3012
+ for (let i = 0; i < obj.names.length; i++) {
3013
+ if (obj.names[i].text !== "lazy")
3014
+ continue;
3015
+ const v = obj.values[i];
3016
+ if (v.kind === NodeKind.Literal &&
3017
+ v.literalKind === 2) {
3018
+ const s = v.value;
3019
+ if (s === "none" || s === "auto" || s === "all")
3020
+ return s;
3021
+ }
3022
+ throwError(`@json lazy must be "none", "auto", or "all"`, v.range);
3023
+ }
3024
+ return "none";
3025
+ }
3026
+ const LAZY_AUTO_THRESHOLD = 10;
3027
+ function lazyTypeCost(type, source, parser) {
3028
+ const base = stripNull(type);
3029
+ if (isPrimitive(base) || isBoolean(base) || isEnum(base, source, parser))
3030
+ return 1;
3031
+ if (base === "Date")
3032
+ return 4;
3033
+ if (isString(base))
3034
+ return 10;
3035
+ if (base === "JSON.Value" ||
3036
+ base === "Value" ||
3037
+ base === "JSON.Obj" ||
3038
+ base === "Obj" ||
3039
+ base === "JSON.Arr" ||
3040
+ base === "Arr" ||
3041
+ base === "JSON.Raw" ||
3042
+ base === "Raw")
3043
+ return 15;
3044
+ return 20;
3045
+ }
3046
+ function lazyAutoCost(type, source, parser) {
3047
+ const direct = lazyTypeCost(type, source, parser);
3048
+ if (direct < 20)
3049
+ return direct;
3050
+ const decl = source.getClass(stripNull(type));
3051
+ if (!decl)
3052
+ return 20;
3053
+ let sum = 0;
3054
+ for (let i = 0; i < decl.members.length; i++) {
3055
+ const m = decl.members[i];
3056
+ if (m.kind !== NodeKind.FieldDeclaration)
3057
+ continue;
3058
+ const fd = m;
3059
+ if (fd.is(32) ||
3060
+ fd.is(512) ||
3061
+ fd.is(1024) ||
3062
+ !fd.type)
3063
+ continue;
3064
+ sum += lazyTypeCost(toString(fd.type), source, parser);
3065
+ if (sum >= LAZY_AUTO_THRESHOLD)
3066
+ return sum;
3067
+ }
3068
+ return sum;
3069
+ }
3070
+ function lazyWrapperInner(typeNode) {
3071
+ if (!typeNode || typeNode.kind !== NodeKind.NamedType)
3072
+ return null;
3073
+ const named = typeNode;
3074
+ let seg = named.name;
3075
+ while (seg.next)
3076
+ seg = seg.next;
3077
+ if (seg.identifier.text !== "Lazy")
3078
+ return null;
3079
+ if (!named.typeArguments || named.typeArguments.length !== 1)
3080
+ return null;
3081
+ let inner = toString(named.typeArguments[0]).trim();
3082
+ if (named.isNullable && !inner.endsWith("null"))
3083
+ inner += " | null";
3084
+ return inner;
3085
+ }
2811
3086
  function estimatedSerializedByteSize(type, source, parser) {
2812
3087
  const trimmed = type.trim();
2813
3088
  const baseType = stripNull(trimmed);
@@ -2828,6 +3103,8 @@ function estimatedSerializedByteSize(type, source, parser) {
2828
3103
  }
2829
3104
  else if (baseType == "JSON.Obj" ||
2830
3105
  baseType == "Obj" ||
3106
+ baseType == "JSON.Arr" ||
3107
+ baseType == "Arr" ||
2831
3108
  baseType == "JSON.Raw" ||
2832
3109
  baseType == "Raw" ||
2833
3110
  baseType == "JSON.Value" ||
@@ -2886,6 +3163,21 @@ export function stripNull(type) {
2886
3163
  }
2887
3164
  return type;
2888
3165
  }
3166
+ function sortMembers(members) {
3167
+ return members.sort((a, b) => {
3168
+ const aMove = a.flags.has(PropertyFlags.OmitIf) || a.flags.has(PropertyFlags.OmitNull);
3169
+ const bMove = b.flags.has(PropertyFlags.OmitIf) || b.flags.has(PropertyFlags.OmitNull);
3170
+ if (aMove && !bMove) {
3171
+ return -1;
3172
+ }
3173
+ else if (!aMove && bMove) {
3174
+ return 1;
3175
+ }
3176
+ else {
3177
+ return 0;
3178
+ }
3179
+ });
3180
+ }
2889
3181
  function getComparison(data) {
2890
3182
  switch (data.length << 1) {
2891
3183
  case 2: {
@@ -2905,4 +3197,3 @@ function getComparison(data) {
2905
3197
  }
2906
3198
  }
2907
3199
  }
2908
- //# sourceMappingURL=index.js.map