json-as 1.3.1 → 1.3.3

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 (55) hide show
  1. package/CHANGELOG.md +9 -26
  2. package/README.md +43 -19
  3. package/assembly/deserialize/index/arbitrary.ts +1 -1
  4. package/assembly/deserialize/index/array.ts +6 -1
  5. package/assembly/deserialize/index/float.ts +1 -1
  6. package/assembly/deserialize/index/integer.ts +1 -1
  7. package/assembly/deserialize/index/unsigned.ts +1 -1
  8. package/assembly/deserialize/simd/string.ts +17 -13
  9. package/assembly/deserialize/simple/arbitrary.ts +1 -1
  10. package/assembly/deserialize/simple/array/generic.ts +42 -0
  11. package/assembly/deserialize/simple/array.ts +8 -1
  12. package/assembly/deserialize/{float.ts → simple/float.ts} +22 -2
  13. package/assembly/deserialize/{integer.ts → simple/integer.ts} +3 -2
  14. package/assembly/deserialize/simple/map.ts +62 -12
  15. package/assembly/deserialize/simple/object.ts +1 -1
  16. package/assembly/deserialize/simple/set.ts +119 -134
  17. package/assembly/deserialize/simple/staticarray.ts +13 -1
  18. package/assembly/deserialize/simple/string.ts +15 -10
  19. package/assembly/deserialize/simple/struct.ts +9 -157
  20. package/assembly/deserialize/simple/typedarray.ts +1 -1
  21. package/assembly/deserialize/{unsigned.ts → simple/unsigned.ts} +3 -2
  22. package/assembly/deserialize/swar/array/array.ts +42 -7
  23. package/assembly/deserialize/swar/array/bool.ts +6 -2
  24. package/assembly/deserialize/swar/array/float.ts +7 -3
  25. package/assembly/deserialize/swar/array/generic.ts +41 -0
  26. package/assembly/deserialize/swar/array/integer.ts +8 -4
  27. package/assembly/deserialize/swar/array/object.ts +21 -4
  28. package/assembly/deserialize/swar/array/shared.ts +19 -4
  29. package/assembly/deserialize/swar/array/string.ts +6 -2
  30. package/assembly/deserialize/swar/array/struct.ts +21 -4
  31. package/assembly/deserialize/swar/array.ts +57 -2
  32. package/assembly/deserialize/swar/string.ts +248 -372
  33. package/assembly/index.d.ts +1 -0
  34. package/assembly/index.ts +77 -19
  35. package/assembly/serialize/index/arbitrary.ts +3 -3
  36. package/assembly/serialize/index/float.ts +1 -1
  37. package/assembly/serialize/index/object.ts +1 -5
  38. package/assembly/serialize/simd/string.ts +4 -5
  39. package/assembly/serialize/simple/arbitrary.ts +3 -3
  40. package/assembly/serialize/simple/array.ts +18 -6
  41. package/assembly/serialize/simple/float.ts +20 -4
  42. package/assembly/serialize/simple/map.ts +10 -27
  43. package/assembly/serialize/simple/object.ts +1 -5
  44. package/assembly/serialize/simple/set.ts +3 -4
  45. package/assembly/serialize/simple/staticarray.ts +4 -3
  46. package/assembly/serialize/simple/typedarray.ts +9 -7
  47. package/assembly/serialize/swar/string.ts +0 -1
  48. package/assembly/tsconfig.json +1 -0
  49. package/assembly/util/dragonbox-cache.ts +4 -0
  50. package/assembly/util/dragonbox.ts +624 -0
  51. package/lib/as-bs.ts +35 -24
  52. package/package.json +26 -18
  53. package/transform/lib/index.d.ts.map +1 -1
  54. package/transform/lib/index.js +508 -148
  55. package/transform/lib/index.js.map +1 -1
@@ -13,7 +13,59 @@ const WRITE = process.env["JSON_WRITE"]?.trim();
13
13
  const rawValue = process.env["JSON_DEBUG"]?.trim();
14
14
  const DEBUG = rawValue === "true" ? 1 : rawValue === "false" || rawValue === "" ? 0 : isNaN(Number(rawValue)) ? 0 : Number(rawValue);
15
15
  const STRICT = process.env["JSON_STRICT"] && process.env["JSON_STRICT"] == "true";
16
- const USE_FAST_PATH = process.env["JSON_USE_FAST_PATH"]?.trim() === "1";
16
+ const DEFAULT_JSON_CACHE_BYTES = 1 << 20;
17
+ function envFlagDefaultTrue(value) {
18
+ if (!value)
19
+ return true;
20
+ switch (value.trim().toLowerCase()) {
21
+ case "0":
22
+ case "false":
23
+ case "off":
24
+ case "no":
25
+ return false;
26
+ default:
27
+ return true;
28
+ }
29
+ }
30
+ const USE_FAST_PATH = envFlagDefaultTrue(process.env["JSON_USE_FAST_PATH"]);
31
+ const THROW_FAST_PATH = process.env["JSON_FAST_PATH_THROW"]?.trim() === "1";
32
+ function parseJSONCacheConfig(value) {
33
+ if (!value)
34
+ return { enabled: false, bytes: 0 };
35
+ const raw = value.trim();
36
+ if (!raw)
37
+ return { enabled: false, bytes: 0 };
38
+ const lower = raw.toLowerCase();
39
+ if (lower === "false" || lower === "off" || lower === "no" || lower === "none" || lower === "0") {
40
+ return { enabled: false, bytes: 0 };
41
+ }
42
+ if (lower === "true" || lower === "on" || lower === "yes") {
43
+ return { enabled: true, bytes: DEFAULT_JSON_CACHE_BYTES };
44
+ }
45
+ const match = /^(\d+)\s*([kKmMgG]?[bB])?$/.exec(raw);
46
+ if (!match) {
47
+ throw new Error(`Invalid JSON_CACHE value '${value}'. Expected true/false or <int>[kb|mb|gb|KB|MB|GB].`);
48
+ }
49
+ const amount = Number(match[1]);
50
+ const suffix = match[2] || "B";
51
+ if (!Number.isFinite(amount)) {
52
+ throw new Error(`Invalid JSON_CACHE value '${value}'.`);
53
+ }
54
+ const unit = suffix[0];
55
+ const scale = unit == "k" || unit == "K" ? 1_000 : unit == "m" || unit == "M" ? 1_000_000 : unit == "g" || unit == "G" ? 1_000_000_000 : 1;
56
+ let bytes = amount * scale;
57
+ if (suffix.endsWith("b")) {
58
+ bytes = Math.ceil(bytes / 8);
59
+ }
60
+ if (bytes <= 0) {
61
+ return { enabled: false, bytes: 0 };
62
+ }
63
+ if (bytes > 0xffff_ffff) {
64
+ throw new Error(`JSON_CACHE value '${value}' is too large (max 4GB).`);
65
+ }
66
+ return { enabled: true, bytes: Math.floor(bytes) };
67
+ }
68
+ const JSON_CACHE_CONFIG = parseJSONCacheConfig(process.env["JSON_CACHE"]);
17
69
  function needsReferenceLoad(type) {
18
70
  return type == "ArrayBuffer" || type == "Int8Array" || type == "Uint8Array" || type == "Uint8ClampedArray" || type == "Int16Array" || type == "Uint16Array" || type == "Int32Array" || type == "Uint32Array" || type == "Int64Array" || type == "Uint64Array" || type == "Float32Array" || type == "Float64Array";
19
71
  }
@@ -358,7 +410,7 @@ export class JSONTransform extends Visitor {
358
410
  this.schema = schema;
359
411
  this.visitedClasses.add(fullClassPath);
360
412
  const codegenMode = getCodegenMode(this.program);
361
- const useFastPath = USE_FAST_PATH && codegenMode !== JSONMode.NAIVE;
413
+ const requestedFastPath = USE_FAST_PATH && codegenMode !== JSONMode.NAIVE;
362
414
  let SERIALIZE = "__SERIALIZE(ptr: usize): void {\n";
363
415
  let INITIALIZE = "@inline __INITIALIZE(): this {\n";
364
416
  let DESERIALIZE = "__DESERIALIZE_SLOW<__JSON_T>(srcStart: usize, srcEnd: usize, out: __JSON_T): usize {\n";
@@ -486,6 +538,12 @@ export class JSONTransform extends Visitor {
486
538
  }
487
539
  if (!this.schema.static)
488
540
  this.schema.members = sortMembers(this.schema.members);
541
+ const hasOmitIfMembers = this.schema.members.some((v) => v.flags.has(PropertyFlags.OmitIf));
542
+ const hasOmitNullMembers = this.schema.members.some((v) => v.flags.has(PropertyFlags.OmitNull));
543
+ const hasOptionalMembers = hasOmitIfMembers || hasOmitNullMembers;
544
+ const supportsFastOptionalPath = requestedFastPath && hasOptionalMembers;
545
+ const hasTypeParams = !!node.typeParameters && node.typeParameters.length > 0;
546
+ const useFastPath = requestedFastPath && !hasTypeParams && (this.schema.static || supportsFastOptionalPath);
489
547
  indent = " ";
490
548
  if (this.schema.static == false) {
491
549
  if (this.schema.members.some((v) => v.flags.has(PropertyFlags.OmitNull))) {
@@ -503,36 +561,34 @@ export class JSONTransform extends Visitor {
503
561
  const aliasName = JSON.stringify(member.alias || member.name);
504
562
  const realName = member.name;
505
563
  const isLast = i == this.schema.members.length - 1;
506
- if (!useFastPath) {
507
- if (member.value) {
508
- if (member.value != "null" && member.value != "0" && member.value != "0.0" && member.value != "false") {
509
- INITIALIZE += ` store<${member.type}>(changetype<usize>(this), ${member.value}, offsetof<this>(${JSON.stringify(member.name)}));\n`;
510
- }
564
+ if (member.value) {
565
+ if (member.value != "null" && member.value != "0" && member.value != "0.0" && member.value != "false") {
566
+ INITIALIZE += ` store<${member.type}>(changetype<usize>(this), ${member.value}, offsetof<this>(${JSON.stringify(member.name)}));\n`;
567
+ }
568
+ }
569
+ else if (member.generic) {
570
+ INITIALIZE += ` if (isManaged<nonnull<${member.type}>>() || isReference<nonnull<${member.type}>>()) {\n`;
571
+ INITIALIZE += ` store<${member.type}>(changetype<usize>(this), changetype<nonnull<${member.type}>>(__new(offsetof<nonnull<${member.type}>>(), idof<nonnull<${member.type}>>())), offsetof<this>(${JSON.stringify(member.name)}));\n`;
572
+ INITIALIZE += ` if (isDefined(this.${member.name}.__INITIALIZE)) changetype<nonnull<${member.type}>>(this.${member.name}).__INITIALIZE();\n`;
573
+ INITIALIZE += ` }\n`;
574
+ }
575
+ else if (!member.node.type.isNullable) {
576
+ if (this.getSchema(member.type)) {
577
+ INITIALIZE += ` store<${member.type}>(changetype<usize>(this), changetype<nonnull<${member.type}>>(__new(offsetof<nonnull<${member.type}>>(), idof<nonnull<${member.type}>>())).__INITIALIZE(), offsetof<this>(${JSON.stringify(member.name)}));\n`;
511
578
  }
512
- else if (member.generic) {
513
- INITIALIZE += ` if (isManaged<nonnull<${member.type}>>() || isReference<nonnull<${member.type}>>()) {\n`;
514
- INITIALIZE += ` store<${member.type}>(changetype<usize>(this), changetype<nonnull<${member.type}>>(__new(offsetof<nonnull<${member.type}>>(), idof<nonnull<${member.type}>>())), offsetof<this>(${JSON.stringify(member.name)}));\n`;
515
- INITIALIZE += ` if (isDefined(this.${member.name}.__INITIALIZE)) changetype<nonnull<${member.type}>>(this.${member.name}).__INITIALIZE();\n`;
516
- INITIALIZE += ` }\n`;
579
+ else if (member.type.startsWith("Array<")) {
580
+ INITIALIZE += ` store<${member.type}>(changetype<usize>(this), [], offsetof<this>(${JSON.stringify(member.name)}));\n`;
517
581
  }
518
- else if (!member.node.type.isNullable) {
519
- if (this.getSchema(member.type)) {
520
- INITIALIZE += ` store<${member.type}>(changetype<usize>(this), changetype<nonnull<${member.type}>>(__new(offsetof<nonnull<${member.type}>>(), idof<nonnull<${member.type}>>())).__INITIALIZE(), offsetof<this>(${JSON.stringify(member.name)}));\n`;
521
- }
522
- else if (member.type.startsWith("Array<")) {
523
- INITIALIZE += ` store<${member.type}>(changetype<usize>(this), [], offsetof<this>(${JSON.stringify(member.name)}));\n`;
524
- }
525
- else if (member.type.startsWith("Map<")) {
526
- INITIALIZE += ` store<${member.type}>(changetype<usize>(this), new ${member.type}(), offsetof<this>(${JSON.stringify(member.name)}));\n`;
527
- }
528
- else if (member.type.startsWith("Set<")) {
529
- INITIALIZE += ` store<${member.type}>(changetype<usize>(this), new ${member.type}(), offsetof<this>(${JSON.stringify(member.name)}));\n`;
530
- }
531
- else if (member.type.startsWith("StaticArray<")) {
532
- }
533
- else if (member.type == "string" || member.type == "String") {
534
- INITIALIZE += ` store<${member.type}>(changetype<usize>(this), "", offsetof<this>(${JSON.stringify(member.name)}));\n`;
535
- }
582
+ else if (member.type.startsWith("Map<")) {
583
+ INITIALIZE += ` store<${member.type}>(changetype<usize>(this), new ${member.type}(), offsetof<this>(${JSON.stringify(member.name)}));\n`;
584
+ }
585
+ else if (member.type.startsWith("Set<")) {
586
+ INITIALIZE += ` store<${member.type}>(changetype<usize>(this), new ${member.type}(), offsetof<this>(${JSON.stringify(member.name)}));\n`;
587
+ }
588
+ else if (member.type.startsWith("StaticArray<")) {
589
+ }
590
+ else if (member.type == "string" || member.type == "String") {
591
+ INITIALIZE += ` store<${member.type}>(changetype<usize>(this), "", offsetof<this>(${JSON.stringify(member.name)}));\n`;
536
592
  }
537
593
  }
538
594
  const SIMD_ENABLED = this.program.options.hasFeature(16);
@@ -624,8 +680,10 @@ export class JSONTransform extends Visitor {
624
680
  else {
625
681
  if (member.node.type.isNullable)
626
682
  sortedMembers.null.push(member);
627
- if (isString(type) || type == "JSON.Raw")
683
+ if (isString(type) || type == "Date")
628
684
  sortedMembers.string.push(member);
685
+ else if (type == "JSON.Raw")
686
+ sortedMembers.object.push(member);
629
687
  else if (isBoolean(type) || type.startsWith("JSON.Box<bool"))
630
688
  sortedMembers.boolean.push(member);
631
689
  else if (isPrimitive(type) || type.startsWith("JSON.Box<") || isEnum(type, this.sources.get(this.schema.node.range.source), this.parser))
@@ -666,20 +724,19 @@ export class JSONTransform extends Visitor {
666
724
  const INTEGER_TYPES = [...UNSIGNED_INTEGER_TYPES, ...SIGNED_INTEGER_TYPES];
667
725
  const STRING_FIELD_DESERIALIZER = codegenMode === JSONMode.SIMD ? "deserializeStringField_SIMD" : "deserializeStringField_SWAR";
668
726
  const getArrayValueType = (type) => {
669
- if (type.startsWith("Array<") || type.startsWith("StaticArray<")) {
670
- return stripNull(type.slice(type.indexOf("<") + 1, -1).trim());
671
- }
672
- return null;
727
+ if (!type.startsWith("Array<") && !type.startsWith("StaticArray<"))
728
+ return null;
729
+ return stripNull(type.slice(type.indexOf("<") + 1, -1).trim());
673
730
  };
674
- const getDeserializer = (type, srcPtr, outPtr, member, keyOffset = 0) => {
731
+ const getDeserializer = (type, srcPtr, outPtr, member, keyOffset = 0, fastPath = false) => {
675
732
  const out = [];
676
733
  const resolvedType = stripNull(type);
734
+ const resolvedSchema = this.getSchema(resolvedType);
677
735
  const fieldOffset = `offsetof<this>(${JSON.stringify(member.name)})`;
678
- const fieldPtr = `${outPtr} + offsetof<this>(${JSON.stringify(member.name)})`;
679
736
  const valuePtr = keyOffset ? `${srcPtr} + ${keyOffset}` : srcPtr;
680
737
  if (INTEGER_TYPES.includes(resolvedType)) {
681
738
  const helper = SIGNED_INTEGER_TYPES.includes(resolvedType) ? "deserializeIntegerField" : "deserializeUnsignedField";
682
- out.push(`${srcPtr} = ${helper}<${resolvedType}>(${valuePtr}, srcEnd, ${fieldPtr});`);
739
+ out.push(`${srcPtr} = ${helper}<${resolvedType}>(${valuePtr}, srcEnd, ${outPtr}, ${fieldOffset});`);
683
740
  }
684
741
  else if (["string", "String"].includes(resolvedType)) {
685
742
  out.push("{");
@@ -689,27 +746,137 @@ export class JSONTransform extends Visitor {
689
746
  out.push(` ${srcPtr} = ${valuePtr} + 8;`);
690
747
  out.push(" } else {");
691
748
  }
692
- out.push(` ${srcPtr} = ${STRING_FIELD_DESERIALIZER}<${member.type}>(${valuePtr}, srcEnd, ${fieldPtr});`);
749
+ out.push(` ${srcPtr} = ${STRING_FIELD_DESERIALIZER}<${member.type}>(${valuePtr}, srcEnd, ${outPtr} + ${fieldOffset});`);
693
750
  if (member.node.type.isNullable) {
694
751
  out.push(" }");
695
752
  }
696
753
  out.push("}");
697
754
  }
698
- else if (isBoolean(resolvedType)) {
755
+ else if (resolvedType == "Date") {
699
756
  out.push("{");
700
- out.push(` if (load<u64>(${srcPtr}) == 28429475166421108) {`);
701
- out.push(` store<${resolvedType}>(${outPtr}, true, ${fieldOffset});`);
702
- out.push(` ${srcPtr} += 8;`);
703
- out.push(" } else if (load<u64>(" + srcPtr + ") == 32370086184550502 && load<u16>(" + srcPtr + ", 8) == 101) {");
704
- out.push(` store<${resolvedType}>(${outPtr}, false, ${fieldOffset});`);
705
- out.push(` ${srcPtr} += 10;`);
706
- out.push(" } else break;");
757
+ if (member.node.type.isNullable) {
758
+ out.push(` if (load<u64>(${valuePtr}) == 30399761348886638) {`);
759
+ out.push(` store<${member.type}>(${outPtr}, changetype<${member.type}>(0), ${fieldOffset});`);
760
+ out.push(` ${srcPtr} = ${valuePtr} + 8;`);
761
+ out.push(" } else {");
762
+ }
763
+ out.push(` if (load<u16>(${valuePtr}) != 0x22) break;`);
764
+ out.push(` let dateEnd = ${valuePtr} + 2;`);
765
+ out.push(` while (dateEnd < srcEnd) {`);
766
+ out.push(" if (load<u16>(dateEnd) == 0x22 && load<u16>(dateEnd - 2) != 0x5c) break;");
767
+ out.push(" dateEnd += 2;");
768
+ out.push(" }");
769
+ out.push(" if (dateEnd >= srcEnd) break;");
770
+ out.push(` store<${resolvedType}>(${outPtr}, JSON.__deserialize<${resolvedType}>(${valuePtr}, dateEnd + 2), ${fieldOffset});`);
771
+ out.push(` ${srcPtr} = dateEnd + 2;`);
772
+ if (member.node.type.isNullable) {
773
+ out.push(" }");
774
+ }
775
+ out.push("}");
776
+ }
777
+ else if (resolvedType.startsWith("JSON.Box<") || resolvedType.startsWith("Box<")) {
778
+ const innerType = resolvedType.slice(resolvedType.indexOf("<") + 1, -1).trim();
779
+ out.push("{");
780
+ if (member.node.type.isNullable) {
781
+ out.push(` if (load<u64>(${valuePtr}) == 30399761348886638) {`);
782
+ out.push(` store<${member.type}>(${outPtr}, changetype<${member.type}>(0), ${fieldOffset});`);
783
+ out.push(` ${srcPtr} = ${valuePtr} + 8;`);
784
+ out.push(" } else {");
785
+ }
786
+ if (innerType == "bool" || innerType == "boolean") {
787
+ out.push(` if (load<u64>(${valuePtr}) == 28429475166421108) {`);
788
+ out.push(` store<${resolvedType}>(${outPtr}, changetype<${resolvedType}>(JSON.Box.from<${innerType}>(true)), ${fieldOffset});`);
789
+ out.push(` ${srcPtr} = ${valuePtr} + 8;`);
790
+ out.push(" } else if (load<u64>(" + valuePtr + ") == 32370086184550502 && load<u16>(" + valuePtr + ", 8) == 101) {");
791
+ out.push(` store<${resolvedType}>(${outPtr}, changetype<${resolvedType}>(JSON.Box.from<${innerType}>(false)), ${fieldOffset});`);
792
+ out.push(` ${srcPtr} = ${valuePtr} + 10;`);
793
+ out.push(" } else break;");
794
+ }
795
+ else {
796
+ out.push(` let boxEnd = ${valuePtr};`);
797
+ out.push(" while (boxEnd < srcEnd) {");
798
+ out.push(" const code = load<u16>(boxEnd);");
799
+ out.push(" if (code == 0x2c || code == 0x7d) break;");
800
+ out.push(" boxEnd += 2;");
801
+ out.push(" }");
802
+ out.push(` if (boxEnd <= ${valuePtr}) break;`);
803
+ out.push(` store<${resolvedType}>(${outPtr}, changetype<${resolvedType}>(JSON.Box.from<${innerType}>(JSON.__deserialize<${innerType}>(${valuePtr}, boxEnd))), ${fieldOffset});`);
804
+ out.push(` ${srcPtr} = boxEnd;`);
805
+ }
806
+ if (member.node.type.isNullable) {
807
+ out.push(" }");
808
+ }
809
+ out.push("}");
810
+ }
811
+ else if (resolvedType == "JSON.Raw") {
812
+ out.push("{");
813
+ out.push(` const valueStart = ${srcPtr};`);
814
+ out.push(" let depth: i32 = 0;");
815
+ out.push(" let inString = false;");
816
+ out.push(` while (${srcPtr} < srcEnd) {`);
817
+ out.push(` const code = load<u16>(${srcPtr});`);
818
+ out.push(" if (inString) {");
819
+ out.push(` if (code == 0x22 && load<u16>(${srcPtr} - 2) != 0x5c) inString = false;`);
820
+ out.push(` ${srcPtr} += 2;`);
821
+ out.push(" continue;");
822
+ out.push(" }");
823
+ out.push(" if (code == 0x22) {");
824
+ out.push(" inString = true;");
825
+ out.push(` ${srcPtr} += 2;`);
826
+ out.push(" continue;");
827
+ out.push(" }");
828
+ out.push(" if (code == 0x7b || code == 0x5b) {");
829
+ out.push(" depth++;");
830
+ out.push(` ${srcPtr} += 2;`);
831
+ out.push(" continue;");
832
+ out.push(" }");
833
+ out.push(" if (code == 0x7d || code == 0x5d) {");
834
+ out.push(" if (depth == 0) break;");
835
+ out.push(" depth--;");
836
+ out.push(` ${srcPtr} += 2;`);
837
+ out.push(" continue;");
838
+ out.push(" }");
839
+ out.push(" if (code == 0x2c && depth == 0) break;");
840
+ out.push(` ${srcPtr} += 2;`);
841
+ out.push(" }");
842
+ out.push(` if (inString || depth != 0 || ${srcPtr} <= valueStart) break;`);
843
+ out.push(` store<${member.type}>(${outPtr}, JSON.Raw.from(JSON.Util.ptrToStr(valueStart, ${srcPtr})), ${fieldOffset});`);
707
844
  out.push("}");
708
845
  }
846
+ else if (isBoolean(resolvedType)) {
847
+ out.push(`if (load<u64>(${srcPtr}) == 28429475166421108) {`);
848
+ out.push(` store<${resolvedType}>(${outPtr}, true, ${fieldOffset});`);
849
+ out.push(` ${srcPtr} += 8;`);
850
+ out.push("} else if (load<u64>(" + srcPtr + ") == 32370086184550502 && load<u16>(" + srcPtr + ", 8) == 101) {");
851
+ out.push(` store<${resolvedType}>(${outPtr}, false, ${fieldOffset});`);
852
+ out.push(` ${srcPtr} += 10;`);
853
+ out.push("} else break;");
854
+ }
709
855
  else if (FLOAT_TYPES.includes(resolvedType)) {
710
- out.push(`${srcPtr} = deserializeFloatField<${resolvedType}>(${valuePtr}, srcEnd, ${fieldPtr});`);
856
+ out.push(`${srcPtr} = deserializeFloatField<${resolvedType}>(${valuePtr}, srcEnd, ${outPtr}, ${fieldOffset});`);
711
857
  }
712
- else if (this.getSchema(resolvedType)) {
858
+ else if (resolvedSchema && !resolvedSchema.custom) {
859
+ if (fastPath) {
860
+ out.push("{");
861
+ if (member.node.type.isNullable) {
862
+ out.push(` if (load<u64>(${valuePtr}) == 30399761348886638) {`);
863
+ out.push(` store<${resolvedType}>(${outPtr}, changetype<${resolvedType}>(0), ${fieldOffset});`);
864
+ out.push(` ${srcPtr} = ${valuePtr} + 8;`);
865
+ out.push(" } else {");
866
+ }
867
+ out.push(` let value = load<${resolvedType}>(${outPtr}, ${fieldOffset});`);
868
+ out.push(` if (changetype<usize>(value) == 0) {`);
869
+ out.push(` value = changetype<${resolvedType}>(__new(offsetof<nonnull<${resolvedType}>>(), idof<nonnull<${resolvedType}>>()));`);
870
+ out.push(` store<${resolvedType}>(${outPtr}, value, ${fieldOffset});`);
871
+ out.push(" }");
872
+ out.push(` ${srcPtr} = changetype<nonnull<${resolvedType}>>(value).__DESERIALIZE_FAST<${resolvedType}>(${valuePtr}, srcEnd, value);`);
873
+ out.push(` if (!${srcPtr}) break;`);
874
+ if (member.node.type.isNullable) {
875
+ out.push(" }");
876
+ }
877
+ out.push("}");
878
+ return out;
879
+ }
713
880
  out.push("{");
714
881
  if (member.node.type.isNullable) {
715
882
  out.push(` if (load<u64>(${srcPtr}) == 30399761348886638) {`);
@@ -718,11 +885,19 @@ export class JSONTransform extends Visitor {
718
885
  out.push(" } else {");
719
886
  }
720
887
  out.push(` let value = load<${resolvedType}>(${outPtr}, ${fieldOffset});`);
721
- out.push(" if (changetype<usize>(value) == 0) {");
888
+ out.push(` if (changetype<usize>(value) == 0) {`);
722
889
  out.push(` value = changetype<${resolvedType}>(__new(offsetof<nonnull<${resolvedType}>>(), idof<nonnull<${resolvedType}>>()));`);
723
890
  out.push(` store<${resolvedType}>(${outPtr}, value, ${fieldOffset});`);
724
891
  out.push(" }");
725
- out.push(` ${srcPtr} = changetype<nonnull<${resolvedType}>>(value).__DESERIALIZE<${resolvedType}>(${srcPtr}, srcEnd, value);`);
892
+ out.push(` const valueStart = ${valuePtr};`);
893
+ out.push(` const valueEnd = JSON.Util.scanValueEnd(valueStart, srcEnd);`);
894
+ out.push(" if (!valueEnd) break;");
895
+ if (fastPath) {
896
+ out.push(` ${srcPtr} = changetype<nonnull<${resolvedType}>>(value).__DESERIALIZE_FAST<${resolvedType}>(valueStart, valueEnd, value);`);
897
+ }
898
+ else {
899
+ out.push(` ${srcPtr} = changetype<nonnull<${resolvedType}>>(value).__DESERIALIZE_SLOW<${resolvedType}>(valueStart, valueEnd, value);`);
900
+ }
726
901
  if (member.node.type.isNullable) {
727
902
  out.push(" }");
728
903
  }
@@ -730,16 +905,22 @@ export class JSONTransform extends Visitor {
730
905
  }
731
906
  else if (resolvedType.startsWith("Array<")) {
732
907
  const valueType = getArrayValueType(resolvedType);
733
- if (valueType && ["string", "String"].includes(valueType)) {
734
- out.push("{");
735
- out.push(` if (load<u16>(${srcPtr}) != 0x5b) break;`);
908
+ out.push("{");
909
+ if (member.node.type.isNullable) {
910
+ out.push(` if (load<u64>(${valuePtr}) == 30399761348886638) {`);
911
+ out.push(` store<${member.type}>(${outPtr}, changetype<${member.type}>(0), ${fieldOffset});`);
912
+ out.push(` ${srcPtr} = ${valuePtr} + 8;`);
913
+ out.push(" } else {");
914
+ }
915
+ if (fastPath && valueType && ["string", "String"].includes(valueType)) {
916
+ out.push(` if (load<u16>(${valuePtr}) != 0x5b) break;`);
736
917
  out.push(` let value = load<${resolvedType}>(${outPtr}, ${fieldOffset});`);
737
918
  out.push(" if (changetype<usize>(value) == 0) {");
738
- out.push(` value = [];`);
919
+ out.push(` value = instantiate<nonnull<${resolvedType}>>();`);
739
920
  out.push(` store<${resolvedType}>(${outPtr}, value, ${fieldOffset});`);
740
921
  out.push(" }");
741
922
  out.push(" let index = 0;");
742
- out.push(` ${srcPtr} += 2;`);
923
+ out.push(` ${srcPtr} = ${valuePtr} + 2;`);
743
924
  out.push(` if (load<u16>(${srcPtr}) == 0x5d) {`);
744
925
  out.push(" value.length = 0;");
745
926
  out.push(` ${srcPtr} += 2;`);
@@ -759,18 +940,22 @@ export class JSONTransform extends Visitor {
759
940
  out.push(" }");
760
941
  out.push(" break;");
761
942
  out.push(" }");
943
+ if (member.node.type.isNullable) {
944
+ out.push(" }");
945
+ }
762
946
  out.push("}");
947
+ return out;
763
948
  }
764
- else if (valueType && this.getSchema(valueType)) {
765
- out.push("{");
766
- out.push(` if (load<u16>(${srcPtr}) != 0x5b) break;`);
949
+ const valueSchema = valueType ? this.getSchema(valueType) : null;
950
+ if (fastPath && valueType && valueSchema && !valueSchema.custom) {
951
+ out.push(` if (load<u16>(${valuePtr}) != 0x5b) break;`);
767
952
  out.push(` let value = load<${resolvedType}>(${outPtr}, ${fieldOffset});`);
768
953
  out.push(" if (changetype<usize>(value) == 0) {");
769
- out.push(` value = [];`);
954
+ out.push(` value = instantiate<nonnull<${resolvedType}>>();`);
770
955
  out.push(` store<${resolvedType}>(${outPtr}, value, ${fieldOffset});`);
771
956
  out.push(" }");
772
957
  out.push(" let index = 0;");
773
- out.push(` ${srcPtr} += 2;`);
958
+ out.push(` ${srcPtr} = ${valuePtr} + 2;`);
774
959
  out.push(` if (load<u16>(${srcPtr}) == 0x5d) {`);
775
960
  out.push(" value.length = 0;");
776
961
  out.push(` ${srcPtr} += 2;`);
@@ -786,7 +971,8 @@ export class JSONTransform extends Visitor {
786
971
  out.push(` item = changetype<${valueType}>(__new(offsetof<nonnull<${valueType}>>(), idof<nonnull<${valueType}>>()));`);
787
972
  out.push(" value.push(item);");
788
973
  out.push(" }");
789
- out.push(` ${srcPtr} = changetype<nonnull<${valueType}>>(item).__DESERIALIZE<${valueType}>(${srcPtr}, srcEnd, item);`);
974
+ out.push(` ${srcPtr} = changetype<nonnull<${valueType}>>(item).__DESERIALIZE_FAST<${valueType}>(${srcPtr}, srcEnd, item);`);
975
+ out.push(` if (!${srcPtr}) break;`);
790
976
  out.push(" index++;");
791
977
  out.push(` const code = load<u16>(${srcPtr});`);
792
978
  out.push(" if (code == 0x2c) {");
@@ -800,80 +986,183 @@ export class JSONTransform extends Visitor {
800
986
  out.push(" }");
801
987
  out.push(" break;");
802
988
  out.push(" }");
989
+ if (member.node.type.isNullable) {
990
+ out.push(" }");
991
+ }
992
+ out.push("}");
993
+ return out;
994
+ }
995
+ out.push(` let value = load<${resolvedType}>(${outPtr}, ${fieldOffset});`);
996
+ out.push(` if (changetype<usize>(value) == 0) {`);
997
+ out.push(` value = changetype<${resolvedType}>(instantiate<nonnull<${resolvedType}>>());`);
998
+ out.push(` store<${resolvedType}>(${outPtr}, value, ${fieldOffset});`);
999
+ out.push(" }");
1000
+ out.push(` if (load<u16>(${valuePtr}) == 0x5b && load<u16>(${valuePtr}, 2) == 0x5d) {`);
1001
+ out.push(" value.length = 0;");
1002
+ out.push(` ${srcPtr} = ${valuePtr} + 4;`);
1003
+ out.push(" } else {");
1004
+ out.push(` ${srcPtr} = deserializeArrayInto_SWAR<${resolvedType}>(${valuePtr}, srcEnd, value);`);
1005
+ out.push(` if (!${srcPtr}) break;`);
1006
+ out.push(" }");
1007
+ if (member.node.type.isNullable) {
1008
+ out.push(" }");
1009
+ }
1010
+ out.push("}");
1011
+ }
1012
+ else if (resolvedType.startsWith("Map<")) {
1013
+ if (member.node.type.isNullable) {
1014
+ out.push(`${srcPtr} = deserializeMapField<${resolvedType}>(${srcPtr}, srcEnd, ${outPtr}, ${fieldOffset});`);
1015
+ }
1016
+ else if (fastPath) {
1017
+ out.push("{");
1018
+ out.push(` let value = load<${resolvedType}>(${outPtr}, ${fieldOffset});`);
1019
+ out.push(" if (changetype<usize>(value) == 0) {");
1020
+ out.push(` value = new ${resolvedType}();`);
1021
+ out.push(` store<${resolvedType}>(${outPtr}, value, ${fieldOffset});`);
1022
+ out.push(" }");
1023
+ out.push(` ${srcPtr} = deserializeMapInto<${resolvedType}>(${srcPtr}, srcEnd, value);`);
1024
+ out.push("}");
1025
+ }
1026
+ else {
1027
+ out.push(`${srcPtr} = deserializeMapInto<${resolvedType}>(${srcPtr}, srcEnd, load<${resolvedType}>(${outPtr}, ${fieldOffset}));`);
1028
+ }
1029
+ out.push(`if (!${srcPtr}) break;`);
1030
+ }
1031
+ else if (resolvedType.startsWith("Set<")) {
1032
+ if (member.node.type.isNullable) {
1033
+ out.push(`${srcPtr} = deserializeSetField<${resolvedType}>(${srcPtr}, srcEnd, ${outPtr}, ${fieldOffset});`);
1034
+ }
1035
+ else if (fastPath) {
1036
+ out.push("{");
1037
+ out.push(` let value = load<${resolvedType}>(${outPtr}, ${fieldOffset});`);
1038
+ out.push(" if (changetype<usize>(value) == 0) {");
1039
+ out.push(` value = new ${resolvedType}();`);
1040
+ out.push(` store<${resolvedType}>(${outPtr}, value, ${fieldOffset});`);
1041
+ out.push(" }");
1042
+ out.push(` ${srcPtr} = deserializeSetInto<${resolvedType}>(${srcPtr}, srcEnd, value);`);
803
1043
  out.push("}");
804
1044
  }
805
1045
  else {
806
- out.push(`${srcPtr} = deserializeArrayField_SWAR<${resolvedType}>(${srcPtr}, srcEnd, ${fieldPtr});`);
807
- out.push(`if (!${srcPtr}) break;`);
1046
+ out.push(`${srcPtr} = deserializeSetInto<${resolvedType}>(${srcPtr}, srcEnd, load<${resolvedType}>(${outPtr}, ${fieldOffset}));`);
808
1047
  }
1048
+ out.push(`if (!${srcPtr}) break;`);
1049
+ }
1050
+ else if (resolvedType.startsWith("StaticArray<")) {
1051
+ out.push(`${srcPtr} = deserializeStaticArrayField<${resolvedType}>(${srcPtr}, srcEnd, ${outPtr}, ${fieldOffset});`);
1052
+ out.push(`if (!${srcPtr}) break;`);
1053
+ }
1054
+ else if (resolvedType == "JSON.Value" || resolvedType == "JSON.Obj" || isEnum(resolvedType, this.sources.get(this.schema.node.range.source), this.parser)) {
1055
+ out.push("break;");
809
1056
  }
810
1057
  else {
811
- out.push("{");
812
- out.push(` const valueStart = ${srcPtr};`);
813
- out.push(" let depth: i32 = 0;");
814
- out.push(" let inString = false;");
815
- out.push(` while (${srcPtr} < srcEnd) {`);
816
- out.push(` const code = load<u16>(${srcPtr});`);
817
- out.push(" if (inString) {");
818
- out.push(` if (code == 0x22 && load<u16>(${srcPtr} - 2) != 0x5c) inString = false;`);
819
- out.push(` ${srcPtr} += 2;`);
820
- out.push(" continue;");
821
- out.push(" }");
822
- out.push(" if (code == 0x22) {");
823
- out.push(" inString = true;");
824
- out.push(` ${srcPtr} += 2;`);
825
- out.push(" continue;");
826
- out.push(" }");
827
- out.push(" if (code == 0x7b || code == 0x5b) {");
828
- out.push(" depth++;");
829
- out.push(` ${srcPtr} += 2;`);
830
- out.push(" continue;");
831
- out.push(" }");
832
- out.push(" if (code == 0x7d || code == 0x5d) {");
833
- out.push(" if (depth == 0) break;");
834
- out.push(" depth--;");
835
- out.push(` ${srcPtr} += 2;`);
836
- out.push(" continue;");
837
- out.push(" }");
838
- out.push(" if (code == 0x2c && depth == 0) break;");
839
- out.push(` ${srcPtr} += 2;`);
840
- out.push(" }");
841
- out.push(` if (inString || depth != 0 || ${srcPtr} <= valueStart) break;`);
842
- out.push(` store<${resolvedType}>(${outPtr}, JSON.__deserialize<${resolvedType}>(valueStart, ${srcPtr}), ${fieldOffset});`);
843
- out.push("}");
1058
+ out.push("break;");
844
1059
  }
845
1060
  return out;
846
1061
  };
847
1062
  indent = " ";
1063
+ DESERIALIZE_FAST += indent + "const start = srcStart;\n";
848
1064
  DESERIALIZE_FAST += indent + "const dst = changetype<usize>(out);\n";
849
1065
  DESERIALIZE_FAST += indent + "do {\n";
850
1066
  indent += " ";
851
- for (let i = 0; i < this.schema.members.length; i++) {
852
- const member = this.schema.members[i];
853
- const key = JSON.stringify(member.alias || member.name);
854
- if (key.length <= 2)
855
- throw new Error("Key cannot be empty!");
856
- const keySection = (i == 0 ? "{" : ",") + key + ":";
857
- DESERIALIZE_FAST += indent + `if ( // ${keySection}\n${(indent += " ")}${getComparisions(keySection, "srcStart", "!=").join("\n" + indent + "|| ")}\n${(indent = indent.slice(0, -2))}) break;\n`;
858
- const keyOffset = keySection.length << 1;
859
- const resolvedType = stripNull(member.type);
860
- const inlineStringValue = ["string", "String"].includes(resolvedType);
861
- if (!inlineStringValue) {
862
- DESERIALIZE_FAST += indent + `srcStart += ${keyOffset};\n\n`;
863
- }
864
- const deserializer = getDeserializer(member.type, "srcStart", "dst", member, inlineStringValue ? keyOffset : 0);
865
- if (!deserializer.length) {
866
- DESERIALIZE_FAST += indent + "break;\n\n";
867
- continue;
1067
+ if (supportsFastOptionalPath) {
1068
+ DESERIALIZE_FAST += indent + "if (load<u16>(srcStart) !== 0x7b) break; // {\n";
1069
+ DESERIALIZE_FAST += indent + "srcStart += 2;\n";
1070
+ DESERIALIZE_FAST += indent + "let seenAny = false;\n\n";
1071
+ for (let i = 0; i < this.schema.members.length; i++) {
1072
+ const member = this.schema.members[i];
1073
+ const key = JSON.stringify(member.alias || member.name);
1074
+ if (key.length <= 2)
1075
+ throw new Error("Key cannot be empty!");
1076
+ const firstKeySection = key + ":";
1077
+ const nextKeySection = "," + key + ":";
1078
+ const firstKeyOffset = firstKeySection.length << 1;
1079
+ const nextKeyOffset = nextKeySection.length << 1;
1080
+ const resolvedType = stripNull(member.type);
1081
+ const inlineStringValue = ["string", "String"].includes(resolvedType);
1082
+ const deserializerFirst = getDeserializer(member.type, "srcStart", "dst", member, inlineStringValue ? firstKeyOffset : 0, true);
1083
+ const deserializerNext = getDeserializer(member.type, "srcStart", "dst", member, inlineStringValue ? nextKeyOffset : 0, true);
1084
+ const isOptional = member.flags.has(PropertyFlags.OmitNull) || member.flags.has(PropertyFlags.OmitIf);
1085
+ if (!deserializerFirst.length || !deserializerNext.length) {
1086
+ DESERIALIZE_FAST += indent + "break;\n\n";
1087
+ continue;
1088
+ }
1089
+ DESERIALIZE_FAST += indent + "if (!seenAny) {\n";
1090
+ indent += " ";
1091
+ DESERIALIZE_FAST += indent + `if ( // ${firstKeySection}\n${(indent += " ")}${getComparisions(firstKeySection, "srcStart", "!=").join("\n" + indent + "|| ")}\n${(indent = indent.slice(0, -2))}) {\n`;
1092
+ indent += " ";
1093
+ if (isOptional) {
1094
+ DESERIALIZE_FAST += indent + "// optional @omitnull field omitted\n";
1095
+ }
1096
+ else {
1097
+ DESERIALIZE_FAST += indent + "break;\n";
1098
+ }
1099
+ indent = indent.slice(0, -2);
1100
+ DESERIALIZE_FAST += indent + "} else {\n";
1101
+ indent += " ";
1102
+ if (!inlineStringValue)
1103
+ DESERIALIZE_FAST += indent + `srcStart += ${firstKeyOffset};\n`;
1104
+ DESERIALIZE_FAST += indent + deserializerFirst.join("\n" + indent) + "\n";
1105
+ DESERIALIZE_FAST += indent + "seenAny = true;\n";
1106
+ indent = indent.slice(0, -2);
1107
+ DESERIALIZE_FAST += indent + "}\n";
1108
+ indent = indent.slice(0, -2);
1109
+ DESERIALIZE_FAST += indent + "} else {\n";
1110
+ indent += " ";
1111
+ DESERIALIZE_FAST += indent + `if ( // ${nextKeySection}\n${(indent += " ")}${getComparisions(nextKeySection, "srcStart", "!=").join("\n" + indent + "|| ")}\n${(indent = indent.slice(0, -2))}) {\n`;
1112
+ indent += " ";
1113
+ if (isOptional) {
1114
+ DESERIALIZE_FAST += indent + "// optional @omitnull field omitted\n";
1115
+ }
1116
+ else {
1117
+ DESERIALIZE_FAST += indent + "break;\n";
1118
+ }
1119
+ indent = indent.slice(0, -2);
1120
+ DESERIALIZE_FAST += indent + "} else {\n";
1121
+ indent += " ";
1122
+ if (!inlineStringValue)
1123
+ DESERIALIZE_FAST += indent + `srcStart += ${nextKeyOffset};\n`;
1124
+ DESERIALIZE_FAST += indent + deserializerNext.join("\n" + indent) + "\n";
1125
+ indent = indent.slice(0, -2);
1126
+ DESERIALIZE_FAST += indent + "}\n";
1127
+ indent = indent.slice(0, -2);
1128
+ DESERIALIZE_FAST += indent + "}\n\n";
1129
+ }
1130
+ }
1131
+ else {
1132
+ for (let i = 0; i < this.schema.members.length; i++) {
1133
+ const member = this.schema.members[i];
1134
+ const key = JSON.stringify(member.alias || member.name);
1135
+ if (key.length <= 2)
1136
+ throw new Error("Key cannot be empty!");
1137
+ const keySection = (i == 0 ? "{" : ",") + key + ":";
1138
+ DESERIALIZE_FAST += indent + `if ( // ${keySection}\n${(indent += " ")}${getComparisions(keySection, "srcStart", "!=").join("\n" + indent + "|| ")}\n${(indent = indent.slice(0, -2))}) break;\n`;
1139
+ const keyOffset = keySection.length << 1;
1140
+ const resolvedType = stripNull(member.type);
1141
+ const inlineStringValue = ["string", "String"].includes(resolvedType);
1142
+ if (!inlineStringValue) {
1143
+ DESERIALIZE_FAST += indent + `srcStart += ${keyOffset};\n\n`;
1144
+ }
1145
+ const deserializer = getDeserializer(member.type, "srcStart", "dst", member, inlineStringValue ? keyOffset : 0, true);
1146
+ if (!deserializer.length) {
1147
+ DESERIALIZE_FAST += indent + "break;\n\n";
1148
+ continue;
1149
+ }
1150
+ DESERIALIZE_FAST += indent + deserializer.join("\n" + indent) + "\n\n";
868
1151
  }
869
- DESERIALIZE_FAST += indent + deserializer.join("\n" + indent) + "\n\n";
870
1152
  }
871
1153
  DESERIALIZE_FAST += indent + "if (load<u16>(srcStart) !== 0x7d) break; // }\n";
872
1154
  DESERIALIZE_FAST += indent + "srcStart += 2;\n";
873
1155
  DESERIALIZE_FAST += indent + "return srcStart;\n";
874
1156
  indent = indent.slice(0, -2);
875
1157
  DESERIALIZE_FAST += indent + "} while (false);\n\n";
876
- DESERIALIZE_FAST += indent + 'throw new Error("Failed to parse JSON ");';
1158
+ if (THROW_FAST_PATH) {
1159
+ DESERIALIZE_FAST += indent + "const failAt = srcStart ? srcStart : start;\n";
1160
+ DESERIALIZE_FAST += indent + "const failEnd = failAt + 160 < srcEnd ? failAt + 160 : srcEnd;\n";
1161
+ DESERIALIZE_FAST += indent + `throw new Error("Fast path failed for ${this.schema.name} at char offset " + ((failAt - start) >> 1).toString() + " near: " + JSON.Util.ptrToStr(failAt, failEnd));`;
1162
+ }
1163
+ else {
1164
+ DESERIALIZE_FAST += indent + "return 0;";
1165
+ }
877
1166
  indent = indent.slice(0, -2);
878
1167
  DESERIALIZE_FAST += indent + "}";
879
1168
  DESERIALIZE += indent + " let keyStart: usize = 0;\n";
@@ -1107,7 +1396,7 @@ export class JSONTransform extends Visitor {
1107
1396
  generateConsts(group);
1108
1397
  const first = group[0];
1109
1398
  const fName = first.alias || first.name;
1110
- DESERIALIZE += indent + " if (" + (first.generic ? "isDefined(out.__DESERIALIZE) &&" : "") + getComparison(fName) + ") { // " + fName + "\n";
1399
+ DESERIALIZE += indent + " if (" + getComparison(fName) + ") { // " + fName + "\n";
1111
1400
  DESERIALIZE += indent + " store<" + first.type + ">(changetype<usize>(out), JSON.__deserialize<" + first.type + ">(lastIndex, srcStart), offsetof<this>(" + JSON.stringify(first.name) + "));\n";
1112
1401
  DESERIALIZE += indent + " keyStart = 0;\n";
1113
1402
  DESERIALIZE += indent + " break;\n";
@@ -1115,7 +1404,7 @@ export class JSONTransform extends Visitor {
1115
1404
  for (let i = 1; i < group.length; i++) {
1116
1405
  const mem = group[i];
1117
1406
  const memName = mem.alias || mem.name;
1118
- DESERIALIZE += indent + " else if (" + (mem.generic ? "isDefined(out.__DESERIALIZE) &&" : "") + getComparison(memName) + ") { // " + memName + "\n";
1407
+ DESERIALIZE += indent + " else if (" + getComparison(memName) + ") { // " + memName + "\n";
1119
1408
  DESERIALIZE += indent + " store<" + mem.type + ">(changetype<usize>(out), JSON.__deserialize<" + mem.type + ">(lastIndex, srcStart), offsetof<this>(" + JSON.stringify(mem.name) + "));\n";
1120
1409
  DESERIALIZE += indent + " keyStart = 0;\n";
1121
1410
  DESERIALIZE += indent + " break;\n";
@@ -1206,7 +1495,12 @@ export class JSONTransform extends Visitor {
1206
1495
  const first = group[0];
1207
1496
  const fName = first.alias || first.name;
1208
1497
  DESERIALIZE += indent + " if (" + (first.generic ? "isBoolean<" + first.type + ">() && " : "") + getComparison(fName) + ") { // " + fName + "\n";
1209
- DESERIALIZE += indent + " store<boolean>(changetype<usize>(out), true, offsetof<this>(" + JSON.stringify(first.name) + "));\n";
1498
+ if (first.type.startsWith("JSON.Box<bool") || first.type.startsWith("JSON.Box<boolean") || first.type.startsWith("Box<bool") || first.type.startsWith("Box<boolean")) {
1499
+ DESERIALIZE += indent + " store<" + first.type + ">(changetype<usize>(out), changetype<" + first.type + ">(JSON.Box.from<bool>(true)), offsetof<this>(" + JSON.stringify(first.name) + "));\n";
1500
+ }
1501
+ else {
1502
+ DESERIALIZE += indent + " store<boolean>(changetype<usize>(out), true, offsetof<this>(" + JSON.stringify(first.name) + "));\n";
1503
+ }
1210
1504
  DESERIALIZE += indent + " srcStart += 2;\n";
1211
1505
  DESERIALIZE += indent + " keyStart = 0;\n";
1212
1506
  DESERIALIZE += indent + " break;\n";
@@ -1215,7 +1509,12 @@ export class JSONTransform extends Visitor {
1215
1509
  const mem = group[i];
1216
1510
  const memName = mem.alias || mem.name;
1217
1511
  DESERIALIZE += indent + " else if (" + (mem.generic ? "isBoolean<" + mem.type + ">() && " : "") + getComparison(memName) + ") { // " + memName + "\n";
1218
- DESERIALIZE += indent + " store<boolean>(changetype<usize>(out), true, offsetof<this>(" + JSON.stringify(mem.name) + "));\n";
1512
+ if (mem.type.startsWith("JSON.Box<bool") || mem.type.startsWith("JSON.Box<boolean") || mem.type.startsWith("Box<bool") || mem.type.startsWith("Box<boolean")) {
1513
+ DESERIALIZE += indent + " store<" + mem.type + ">(changetype<usize>(out), changetype<" + mem.type + ">(JSON.Box.from<bool>(true)), offsetof<this>(" + JSON.stringify(mem.name) + "));\n";
1514
+ }
1515
+ else {
1516
+ DESERIALIZE += indent + " store<boolean>(changetype<usize>(out), true, offsetof<this>(" + JSON.stringify(mem.name) + "));\n";
1517
+ }
1219
1518
  DESERIALIZE += indent + " srcStart += 2;\n";
1220
1519
  DESERIALIZE += indent + " keyStart = 0;\n";
1221
1520
  DESERIALIZE += indent + " break;\n";
@@ -1250,7 +1549,12 @@ export class JSONTransform extends Visitor {
1250
1549
  const first = group[0];
1251
1550
  const fName = first.alias || first.name;
1252
1551
  DESERIALIZE += indent + " if (" + (first.generic ? "isBoolean<" + first.type + ">() && " : "") + getComparison(fName) + ") { // " + fName + "\n";
1253
- DESERIALIZE += indent + " store<boolean>(changetype<usize>(out), false, offsetof<this>(" + JSON.stringify(first.name) + "));\n";
1552
+ if (first.type.startsWith("JSON.Box<bool") || first.type.startsWith("JSON.Box<boolean") || first.type.startsWith("Box<bool") || first.type.startsWith("Box<boolean")) {
1553
+ DESERIALIZE += indent + " store<" + first.type + ">(changetype<usize>(out), changetype<" + first.type + ">(JSON.Box.from<bool>(false)), offsetof<this>(" + JSON.stringify(first.name) + "));\n";
1554
+ }
1555
+ else {
1556
+ DESERIALIZE += indent + " store<boolean>(changetype<usize>(out), false, offsetof<this>(" + JSON.stringify(first.name) + "));\n";
1557
+ }
1254
1558
  DESERIALIZE += indent + " srcStart += 2;\n";
1255
1559
  DESERIALIZE += indent + " keyStart = 0;\n";
1256
1560
  DESERIALIZE += indent + " break;\n";
@@ -1259,7 +1563,12 @@ export class JSONTransform extends Visitor {
1259
1563
  const mem = group[i];
1260
1564
  const memName = mem.alias || mem.name;
1261
1565
  DESERIALIZE += indent + " else if (" + (mem.generic ? "isBoolean<" + mem.type + ">() && " : "") + getComparison(memName) + ") { // " + memName + "\n";
1262
- DESERIALIZE += indent + " store<boolean>(changetype<usize>(out), false, offsetof<this>(" + JSON.stringify(mem.name) + "));\n";
1566
+ if (mem.type.startsWith("JSON.Box<bool") || mem.type.startsWith("JSON.Box<boolean") || mem.type.startsWith("Box<bool") || mem.type.startsWith("Box<boolean")) {
1567
+ DESERIALIZE += indent + " store<" + mem.type + ">(changetype<usize>(out), changetype<" + mem.type + ">(JSON.Box.from<bool>(false)), offsetof<this>(" + JSON.stringify(mem.name) + "));\n";
1568
+ }
1569
+ else {
1570
+ DESERIALIZE += indent + " store<boolean>(changetype<usize>(out), false, offsetof<this>(" + JSON.stringify(mem.name) + "));\n";
1571
+ }
1263
1572
  DESERIALIZE += indent + " srcStart += 2;\n";
1264
1573
  DESERIALIZE += indent + " keyStart = 0;\n";
1265
1574
  DESERIALIZE += indent + " break;\n";
@@ -1340,30 +1649,26 @@ export class JSONTransform extends Visitor {
1340
1649
  SERIALIZE += indent + "bs.offset += 2;\n";
1341
1650
  SERIALIZE += "}";
1342
1651
  SERIALIZE = SERIALIZE.slice(0, 32) + indent + "bs.proposeSize(" + this.schema.byteSize + ");\n" + SERIALIZE.slice(32);
1343
- if (!useFastPath) {
1344
- INITIALIZE += " return this;\n";
1345
- INITIALIZE += "}";
1346
- }
1652
+ INITIALIZE += " return this;\n";
1653
+ INITIALIZE += "}";
1347
1654
  if (DEBUG > 0) {
1348
1655
  console.log(SERIALIZE_CUSTOM || SERIALIZE);
1349
- if (!useFastPath)
1350
- console.log(INITIALIZE);
1656
+ console.log(INITIALIZE);
1351
1657
  console.log(DESERIALIZE_CUSTOM || DESERIALIZE);
1352
1658
  }
1353
- const DESERIALIZE_DIRECT = useFastPath ? DESERIALIZE_FAST.replace("@inline __DESERIALIZE_FAST<__JSON_T>(srcStart: usize, srcEnd: usize, out: __JSON_T): usize {", "@inline __DESERIALIZE<__JSON_T>(srcStart: usize, srcEnd: usize, out: __JSON_T): usize {") : DESERIALIZE.replace("__DESERIALIZE_SLOW<__JSON_T>", "__DESERIALIZE<__JSON_T>");
1354
1659
  const SERIALIZE_METHOD = SimpleParser.parseClassMember(SERIALIZE_CUSTOM || SERIALIZE, node);
1355
- const INITIALIZE_METHOD = !useFastPath ? SimpleParser.parseClassMember(INITIALIZE, node) : null;
1660
+ const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node);
1356
1661
  const DESERIALIZE_CUSTOM_METHOD = DESERIALIZE_CUSTOM ? SimpleParser.parseClassMember(DESERIALIZE_CUSTOM, node) : null;
1357
- const DESERIALIZE_METHOD = DESERIALIZE_CUSTOM ? null : SimpleParser.parseClassMember(DESERIALIZE_DIRECT, node);
1662
+ const DESERIALIZE_SLOW_METHOD = SimpleParser.parseClassMember(DESERIALIZE, node);
1358
1663
  const DESERIALIZE_FAST_METHOD = useFastPath ? SimpleParser.parseClassMember(DESERIALIZE_FAST, node) : null;
1359
1664
  if (!node.members.find((v) => v.name.text == "__SERIALIZE"))
1360
1665
  node.members.push(SERIALIZE_METHOD);
1361
- if (!useFastPath && INITIALIZE_METHOD && !node.members.find((v) => v.name.text == "__INITIALIZE"))
1666
+ if (INITIALIZE_METHOD && !node.members.find((v) => v.name.text == "__INITIALIZE"))
1362
1667
  node.members.push(INITIALIZE_METHOD);
1363
1668
  if (DESERIALIZE_CUSTOM_METHOD && !node.members.find((v) => v.name.text == "__DESERIALIZE_CUSTOM"))
1364
1669
  node.members.push(DESERIALIZE_CUSTOM_METHOD);
1365
- if (DESERIALIZE_METHOD && !node.members.find((v) => v.name.text == "__DESERIALIZE"))
1366
- node.members.push(DESERIALIZE_METHOD);
1670
+ if (!DESERIALIZE_CUSTOM && DESERIALIZE_SLOW_METHOD && !node.members.find((v) => v.name.text == "__DESERIALIZE_SLOW"))
1671
+ node.members.push(DESERIALIZE_SLOW_METHOD);
1367
1672
  if (!DESERIALIZE_CUSTOM && useFastPath && DESERIALIZE_FAST_METHOD && !node.members.find((v) => v.name.text == "__DESERIALIZE_FAST"))
1368
1673
  node.members.push(DESERIALIZE_FAST_METHOD);
1369
1674
  super.visitClassDeclaration(node);
@@ -1375,23 +1680,21 @@ export class JSONTransform extends Visitor {
1375
1680
  generateEmptyMethods(node) {
1376
1681
  const SERIALIZE_EMPTY = "@inline __SERIALIZE(ptr: usize): void {\n bs.proposeSize(4);\n store<u32>(bs.offset, 8192123);\n bs.offset += 4;\n}";
1377
1682
  const INITIALIZE_EMPTY = "@inline __INITIALIZE(): this {\n return this;\n}";
1378
- const DESERIALIZE_EMPTY = "@inline __DESERIALIZE<__JSON_T>(srcStart: usize, srcEnd: usize, out: __JSON_T): usize {\n return srcEnd;\n}";
1379
- const useFastPath = USE_FAST_PATH && getCodegenMode(this.program) !== JSONMode.NAIVE;
1683
+ const DESERIALIZE_SLOW_EMPTY = "@inline __DESERIALIZE_SLOW<__JSON_T>(srcStart: usize, srcEnd: usize, out: __JSON_T): usize {\n return srcEnd;\n}";
1380
1684
  if (DEBUG > 0) {
1381
1685
  console.log(SERIALIZE_EMPTY);
1382
- if (!useFastPath)
1383
- console.log(INITIALIZE_EMPTY);
1384
- console.log(DESERIALIZE_EMPTY);
1686
+ console.log(INITIALIZE_EMPTY);
1687
+ console.log(DESERIALIZE_SLOW_EMPTY);
1385
1688
  }
1386
1689
  const SERIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_EMPTY, node);
1387
- const INITIALIZE_METHOD_EMPTY = !useFastPath ? SimpleParser.parseClassMember(INITIALIZE_EMPTY, node) : null;
1388
- const DESERIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(DESERIALIZE_EMPTY, node);
1690
+ const INITIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(INITIALIZE_EMPTY, node);
1691
+ const DESERIALIZE_SLOW_METHOD_EMPTY = SimpleParser.parseClassMember(DESERIALIZE_SLOW_EMPTY, node);
1389
1692
  if (!node.members.find((v) => v.name.text == "__SERIALIZE"))
1390
1693
  node.members.push(SERIALIZE_METHOD_EMPTY);
1391
- if (!useFastPath && INITIALIZE_METHOD_EMPTY && !node.members.find((v) => v.name.text == "__INITIALIZE"))
1694
+ if (INITIALIZE_METHOD_EMPTY && !node.members.find((v) => v.name.text == "__INITIALIZE"))
1392
1695
  node.members.push(INITIALIZE_METHOD_EMPTY);
1393
- if (!node.members.find((v) => v.name.text == "__DESERIALIZE"))
1394
- node.members.push(DESERIALIZE_METHOD_EMPTY);
1696
+ if (!node.members.find((v) => v.name.text == "__DESERIALIZE_SLOW"))
1697
+ node.members.push(DESERIALIZE_SLOW_METHOD_EMPTY);
1395
1698
  }
1396
1699
  visitImportStatement(node) {
1397
1700
  super.visitImportStatement(node);
@@ -1412,14 +1715,28 @@ export class JSONTransform extends Visitor {
1412
1715
  const deserializeIntegerFieldImport = this.imports.find((i) => i.declarations?.find((d) => d.foreignName.text == "deserializeIntegerField" || d.name.text == "deserializeIntegerField"));
1413
1716
  const deserializeUnsignedFieldImport = this.imports.find((i) => i.declarations?.find((d) => d.foreignName.text == "deserializeUnsignedField" || d.name.text == "deserializeUnsignedField"));
1414
1717
  const deserializeFloatFieldImport = this.imports.find((i) => i.declarations?.find((d) => d.foreignName.text == "deserializeFloatField" || d.name.text == "deserializeFloatField"));
1718
+ const scanValueEndImport = this.imports.find((i) => i.declarations?.find((d) => d.foreignName.text == "scanValueEnd" || d.name.text == "scanValueEnd"));
1415
1719
  const deserializeArrayField_SWARImport = this.imports.find((i) => i.declarations?.find((d) => d.foreignName.text == "deserializeArrayField_SWAR" || d.name.text == "deserializeArrayField_SWAR"));
1720
+ const deserializeArrayInto_SWARImport = this.imports.find((i) => i.declarations?.find((d) => d.foreignName.text == "deserializeArrayInto_SWAR" || d.name.text == "deserializeArrayInto_SWAR"));
1721
+ const deserializeMapFieldImport = this.imports.find((i) => i.declarations?.find((d) => d.foreignName.text == "deserializeMapField" || d.name.text == "deserializeMapField"));
1722
+ const deserializeMapIntoImport = this.imports.find((i) => i.declarations?.find((d) => d.foreignName.text == "deserializeMapInto" || d.name.text == "deserializeMapInto"));
1723
+ const deserializeSetFieldImport = this.imports.find((i) => i.declarations?.find((d) => d.foreignName.text == "deserializeSetField" || d.name.text == "deserializeSetField"));
1724
+ const deserializeSetIntoImport = this.imports.find((i) => i.declarations?.find((d) => d.foreignName.text == "deserializeSetInto" || d.name.text == "deserializeSetInto"));
1725
+ const deserializeStaticArrayFieldImport = this.imports.find((i) => i.declarations?.find((d) => d.foreignName.text == "deserializeStaticArrayField" || d.name.text == "deserializeStaticArrayField"));
1416
1726
  const deserializeStringFieldSWARImport = this.imports.find((i) => i.declarations?.find((d) => d.foreignName.text == "deserializeStringField_SWAR" || d.name.text == "deserializeStringField_SWAR"));
1417
1727
  const deserializeStringFieldSIMDImport = this.imports.find((i) => i.declarations?.find((d) => d.foreignName.text == "deserializeStringField_SIMD" || d.name.text == "deserializeStringField_SIMD"));
1418
1728
  const sourceText = readFileSync(fromPath).toString();
1419
1729
  const hasLocalDeserializeIntegerField = /\bdeserializeIntegerField\b/.test(sourceText);
1420
1730
  const hasLocalDeserializeUnsignedField = /\bdeserializeUnsignedField\b/.test(sourceText);
1421
1731
  const hasLocalDeserializeFloatField = /\bdeserializeFloatField\b/.test(sourceText);
1732
+ const hasLocalScanValueEnd = /\bscanValueEnd\b/.test(sourceText);
1422
1733
  const hasLocaldeserializeArrayField_SWAR = /\bdeserializeArrayField_SWAR\b/.test(sourceText);
1734
+ const hasLocaldeserializeArrayInto_SWAR = /\bdeserializeArrayInto_SWAR\b/.test(sourceText);
1735
+ const hasLocaldeserializeMapField = /\bdeserializeMapField\b/.test(sourceText);
1736
+ const hasLocaldeserializeMapInto = /\bdeserializeMapInto\b/.test(sourceText);
1737
+ const hasLocaldeserializeSetField = /\bdeserializeSetField\b/.test(sourceText);
1738
+ const hasLocaldeserializeSetInto = /\bdeserializeSetInto\b/.test(sourceText);
1739
+ const hasLocaldeserializeStaticArrayField = /\bdeserializeStaticArrayField\b/.test(sourceText);
1423
1740
  const hasLocalDeserializeStringFieldSWAR = /\bdeserializeStringField_SWAR\b/.test(sourceText);
1424
1741
  const hasLocalDeserializeStringFieldSIMD = /\bdeserializeStringField_SIMD\b/.test(sourceText);
1425
1742
  let baseRel = path.posix.join(...path.relative(path.dirname(fromPath), path.join(baseDir)).split(path.sep));
@@ -1448,19 +1765,25 @@ export class JSONTransform extends Visitor {
1448
1765
  console.log("Added import: " + toString(replaceNode) + " to " + node.range.source.normalizedPath + "\n");
1449
1766
  }
1450
1767
  if (!deserializeIntegerFieldImport && !hasLocalDeserializeIntegerField) {
1451
- const replaceNode = Node.createImportStatement([Node.createImportDeclaration(Node.createIdentifierExpression("deserializeIntegerField", node.range, false), null, node.range)], Node.createStringLiteralExpression(path.posix.join(baseRel, "assembly", "deserialize", "integer"), node.range), node.range);
1768
+ const replaceNode = Node.createImportStatement([Node.createImportDeclaration(Node.createIdentifierExpression("deserializeIntegerField", node.range, false), null, node.range)], Node.createStringLiteralExpression(path.posix.join(baseRel, "assembly", "deserialize", "simple", "integer"), node.range), node.range);
1452
1769
  node.range.source.statements.unshift(replaceNode);
1453
1770
  if (DEBUG > 0)
1454
1771
  console.log("Added import: " + toString(replaceNode) + " to " + node.range.source.normalizedPath + "\n");
1455
1772
  }
1456
1773
  if (!deserializeUnsignedFieldImport && !hasLocalDeserializeUnsignedField) {
1457
- const replaceNode = Node.createImportStatement([Node.createImportDeclaration(Node.createIdentifierExpression("deserializeUnsignedField", node.range, false), null, node.range)], Node.createStringLiteralExpression(path.posix.join(baseRel, "assembly", "deserialize", "unsigned"), node.range), node.range);
1774
+ const replaceNode = Node.createImportStatement([Node.createImportDeclaration(Node.createIdentifierExpression("deserializeUnsignedField", node.range, false), null, node.range)], Node.createStringLiteralExpression(path.posix.join(baseRel, "assembly", "deserialize", "simple", "unsigned"), node.range), node.range);
1458
1775
  node.range.source.statements.unshift(replaceNode);
1459
1776
  if (DEBUG > 0)
1460
1777
  console.log("Added import: " + toString(replaceNode) + " to " + node.range.source.normalizedPath + "\n");
1461
1778
  }
1462
1779
  if (!deserializeFloatFieldImport && !hasLocalDeserializeFloatField) {
1463
- const replaceNode = Node.createImportStatement([Node.createImportDeclaration(Node.createIdentifierExpression("deserializeFloatField", node.range, false), null, node.range)], Node.createStringLiteralExpression(path.posix.join(baseRel, "assembly", "deserialize", "float"), node.range), node.range);
1780
+ const replaceNode = Node.createImportStatement([Node.createImportDeclaration(Node.createIdentifierExpression("deserializeFloatField", node.range, false), null, node.range)], Node.createStringLiteralExpression(path.posix.join(baseRel, "assembly", "deserialize", "simple", "float"), node.range), node.range);
1781
+ node.range.source.statements.unshift(replaceNode);
1782
+ if (DEBUG > 0)
1783
+ console.log("Added import: " + toString(replaceNode) + " to " + node.range.source.normalizedPath + "\n");
1784
+ }
1785
+ if (!scanValueEndImport && !hasLocalScanValueEnd) {
1786
+ const replaceNode = Node.createImportStatement([Node.createImportDeclaration(Node.createIdentifierExpression("scanValueEnd", node.range, false), null, node.range)], Node.createStringLiteralExpression(path.posix.join(baseRel, "assembly", "deserialize", "swar", "array", "shared"), node.range), node.range);
1464
1787
  node.range.source.statements.unshift(replaceNode);
1465
1788
  if (DEBUG > 0)
1466
1789
  console.log("Added import: " + toString(replaceNode) + " to " + node.range.source.normalizedPath + "\n");
@@ -1471,6 +1794,42 @@ export class JSONTransform extends Visitor {
1471
1794
  if (DEBUG > 0)
1472
1795
  console.log("Added import: " + toString(replaceNode) + " to " + node.range.source.normalizedPath + "\n");
1473
1796
  }
1797
+ if (!deserializeArrayInto_SWARImport && !hasLocaldeserializeArrayInto_SWAR) {
1798
+ const replaceNode = Node.createImportStatement([Node.createImportDeclaration(Node.createIdentifierExpression("deserializeArrayInto_SWAR", node.range, false), null, node.range)], Node.createStringLiteralExpression(path.posix.join(baseRel, "assembly", "deserialize", "swar", "array"), node.range), node.range);
1799
+ node.range.source.statements.unshift(replaceNode);
1800
+ if (DEBUG > 0)
1801
+ console.log("Added import: " + toString(replaceNode) + " to " + node.range.source.normalizedPath + "\n");
1802
+ }
1803
+ if (!deserializeMapFieldImport && !hasLocaldeserializeMapField) {
1804
+ const replaceNode = Node.createImportStatement([Node.createImportDeclaration(Node.createIdentifierExpression("deserializeMapField", node.range, false), null, node.range)], Node.createStringLiteralExpression(path.posix.join(baseRel, "assembly", "deserialize", "simple", "map"), node.range), node.range);
1805
+ node.range.source.statements.unshift(replaceNode);
1806
+ if (DEBUG > 0)
1807
+ console.log("Added import: " + toString(replaceNode) + " to " + node.range.source.normalizedPath + "\n");
1808
+ }
1809
+ if (!deserializeMapIntoImport && !hasLocaldeserializeMapInto) {
1810
+ const replaceNode = Node.createImportStatement([Node.createImportDeclaration(Node.createIdentifierExpression("deserializeMapInto", node.range, false), null, node.range)], Node.createStringLiteralExpression(path.posix.join(baseRel, "assembly", "deserialize", "simple", "map"), node.range), node.range);
1811
+ node.range.source.statements.unshift(replaceNode);
1812
+ if (DEBUG > 0)
1813
+ console.log("Added import: " + toString(replaceNode) + " to " + node.range.source.normalizedPath + "\n");
1814
+ }
1815
+ if (!deserializeSetFieldImport && !hasLocaldeserializeSetField) {
1816
+ const replaceNode = Node.createImportStatement([Node.createImportDeclaration(Node.createIdentifierExpression("deserializeSetField", node.range, false), null, node.range)], Node.createStringLiteralExpression(path.posix.join(baseRel, "assembly", "deserialize", "simple", "set"), node.range), node.range);
1817
+ node.range.source.statements.unshift(replaceNode);
1818
+ if (DEBUG > 0)
1819
+ console.log("Added import: " + toString(replaceNode) + " to " + node.range.source.normalizedPath + "\n");
1820
+ }
1821
+ if (!deserializeSetIntoImport && !hasLocaldeserializeSetInto) {
1822
+ const replaceNode = Node.createImportStatement([Node.createImportDeclaration(Node.createIdentifierExpression("deserializeSetInto", node.range, false), null, node.range)], Node.createStringLiteralExpression(path.posix.join(baseRel, "assembly", "deserialize", "simple", "set"), node.range), node.range);
1823
+ node.range.source.statements.unshift(replaceNode);
1824
+ if (DEBUG > 0)
1825
+ console.log("Added import: " + toString(replaceNode) + " to " + node.range.source.normalizedPath + "\n");
1826
+ }
1827
+ if (!deserializeStaticArrayFieldImport && !hasLocaldeserializeStaticArrayField) {
1828
+ const replaceNode = Node.createImportStatement([Node.createImportDeclaration(Node.createIdentifierExpression("deserializeStaticArrayField", node.range, false), null, node.range)], Node.createStringLiteralExpression(path.posix.join(baseRel, "assembly", "deserialize", "simple", "staticarray"), node.range), node.range);
1829
+ node.range.source.statements.unshift(replaceNode);
1830
+ if (DEBUG > 0)
1831
+ console.log("Added import: " + toString(replaceNode) + " to " + node.range.source.normalizedPath + "\n");
1832
+ }
1474
1833
  const codegenMode = getCodegenMode(this.program);
1475
1834
  if (codegenMode !== JSONMode.SIMD && !deserializeStringFieldSWARImport && !hasLocalDeserializeStringFieldSWAR) {
1476
1835
  const replaceNode = Node.createImportStatement([Node.createImportDeclaration(Node.createIdentifierExpression("deserializeStringField_SWAR", node.range, false), null, node.range)], Node.createStringLiteralExpression(path.posix.join(baseRel, "assembly", "deserialize", "swar", "string"), node.range), node.range);
@@ -1576,8 +1935,9 @@ export default class Transformer extends Transform {
1576
1935
  }
1577
1936
  }
1578
1937
  program.registerConstantInteger("JSON_MODE", Type.i32, i64_new(MODE));
1579
- if (process.env["JSON_CACHE"]?.trim().toLowerCase() === "true" || process.env["JSON_CACHE"]?.trim().toLowerCase() === "1") {
1938
+ if (JSON_CACHE_CONFIG.enabled) {
1580
1939
  program.registerConstantInteger("JSON_CACHE", Type.bool, i64_one);
1940
+ program.registerConstantInteger("JSON_CACHE_SIZE", Type.u32, i64_new(JSON_CACHE_CONFIG.bytes));
1581
1941
  }
1582
1942
  }
1583
1943
  afterParse(parser) {