From be59e088a23c8b43ba78fc7ec029a5fc90a83de5 Mon Sep 17 00:00:00 2001 From: Pavel Shirshov Date: Wed, 18 Dec 2024 17:26:16 +0000 Subject: [PATCH] codec parameters --- .../baboon-runtime/cs/BaboonRuntimeShared.cs | 53 +++++++- .../csharp/CSBaboonTranslator.scala | 2 + .../csharp/CSCodecTestsTranslator.scala | 74 +++++----- .../csharp/CSNSJsonCodecGenerator.scala | 88 ++++++------ .../csharp/CSUEBACodecGenerator.scala | 126 +++++++++--------- 5 files changed, 193 insertions(+), 150 deletions(-) diff --git a/src/main/resources/baboon-runtime/cs/BaboonRuntimeShared.cs b/src/main/resources/baboon-runtime/cs/BaboonRuntimeShared.cs index 0501305..9b12233 100644 --- a/src/main/resources/baboon-runtime/cs/BaboonRuntimeShared.cs +++ b/src/main/resources/baboon-runtime/cs/BaboonRuntimeShared.cs @@ -1,3 +1,9 @@ +#nullable enable + +#pragma warning disable 612,618 + +using System.Linq; + using System.Collections.Generic; using System.IO; using Newtonsoft.Json.Linq; @@ -52,7 +58,7 @@ public TTo Convert(TCtx? context, AbstractBaboonConversions conversions, T { if (TypeId() != bgr.BaboonTypeIdentifier()) { - throw new ArgumentException($"Provided instance is {bgr.BaboonTypeIdentifier()} but must be {TypeId()}"); + throw new ArgumentException($"Produced instance is {bgr.BaboonTypeIdentifier()} but must be {TypeId()}"); } } @@ -65,7 +71,7 @@ public TTo Convert(TCtx? context, AbstractBaboonConversions conversions, T { if (from is not TFrom fr) { - throw new Exception($"Can't use IBaboonGeneratedConversion interface when from is not of type {typeof(TFrom).FullName}"); + throw new Exception($"Can't use IBaboonGeneratedConversion interface when 'from' is not of type {typeof(TFrom).FullName}"); } var res = Convert(context, conversions, fr); @@ -97,23 +103,56 @@ public interface IBaboonCodecData { public String BaboonTypeIdentifier(); } + public class BaboonCodecContext { + public BaboonCodecContext(bool useIndexes) + { + UseIndexes = useIndexes; + } + + public Boolean UseIndexes { get; } + + public static BaboonCodecContext Indexed { get; } = new BaboonCodecContext(true); + public static BaboonCodecContext Compact { get; } = new BaboonCodecContext(false); + public static BaboonCodecContext Default { get; } = Compact; + + } + public interface IBaboonCodec : IBaboonCodecData {} public interface IBaboonValueCodec : IBaboonCodec { - TWire Encode(T instance); - T Decode(TWire wire); + // json codec should always ignore context + TWire Encode(BaboonCodecContext ctx, T instance); + T Decode(BaboonCodecContext ctx, TWire wire); } public interface IBaboonJsonCodec : IBaboonValueCodec {} public interface IBaboonStreamCodec : IBaboonCodec { - void Encode(TOut writer, T instance); - T Decode(TIn wire); + void Encode(BaboonCodecContext ctx, TOut writer, T instance); + T Decode(BaboonCodecContext ctx, TIn wire); } - public interface IBaboonBinCodec : IBaboonStreamCodec {} + public interface IBaboonBinCodec : IBaboonStreamCodec + { + void EncodeMessage(BaboonCodecContext ctx, BinaryWriter writer, T instance) + { + var header = 0b0000000; + if (ctx.UseIndexes) + { + header |= 0b0000001; + } + Encode(ctx, writer, instance); + } + + T DecodeMessage(BinaryReader wire) + { + var header = wire.ReadByte(); + var ctx = new BaboonCodecContext((header & 0b0000001) != 0); + return Decode(ctx, wire); + } + } public interface IBaboonTypeCodecs { public String Id { get; } diff --git a/src/main/scala/io/septimalmind/baboon/translator/csharp/CSBaboonTranslator.scala b/src/main/scala/io/septimalmind/baboon/translator/csharp/CSBaboonTranslator.scala index a30f310..a17a24f 100644 --- a/src/main/scala/io/septimalmind/baboon/translator/csharp/CSBaboonTranslator.scala +++ b/src/main/scala/io/septimalmind/baboon/translator/csharp/CSBaboonTranslator.scala @@ -426,6 +426,8 @@ object CSBaboonTranslator { // Baboon codec types val iBaboonCodecData: CSType = CSType(baboonRtPkg, "IBaboonCodecData", fq = false) + val baboonCodecContext: CSType = + CSType(baboonRtPkg, "BaboonCodecContext", fq = false) val iBaboonCodec: CSType = CSType(baboonRtPkg, "IBaboonCodec", fq = false) val iBaboonValueCodec: CSType = diff --git a/src/main/scala/io/septimalmind/baboon/translator/csharp/CSCodecTestsTranslator.scala b/src/main/scala/io/septimalmind/baboon/translator/csharp/CSCodecTestsTranslator.scala index dbb7b0a..0986cf3 100644 --- a/src/main/scala/io/septimalmind/baboon/translator/csharp/CSCodecTestsTranslator.scala +++ b/src/main/scala/io/septimalmind/baboon/translator/csharp/CSCodecTestsTranslator.scala @@ -21,14 +21,14 @@ object CSCodecTestsTranslator { typeTranslator: CSTypeTranslator, logger: BLogger, enquiries: BaboonEnquiries, - compilerOptions: CompilerOptions - ) extends CSCodecTestsTranslator { + compilerOptions: CompilerOptions) + extends CSCodecTestsTranslator { override def translate(definition: DomainMember.User, csRef: CSValue.CSType, srcRef: CSValue.CSType, domain: Domain, evo: BaboonEvolution, - ): Option[TextTree[CSValue]] = { + ): Option[TextTree[CSValue]] = { val codecTestName = definition.id.owner match { case Owner.Toplevel => srcRef.name @@ -47,17 +47,19 @@ object CSCodecTestsTranslator { case d if enquiries.isRecursiveTypedef(d, domain) => None case d if d.defn.isInstanceOf[Typedef.NonDataTypedef] => None case _ => + val init = fieldsInitialization(definition, srcRef, domain, evo) val testClass = q"""[$nunitTestFixture] |public class $testClassName |{ | #nullable disable - | ${testFields(definition, srcRef, domain, evo)} + | ${testFields(definition, srcRef, domain, evo).shift(2).trim} + | private $baboonCodecContext context = $baboonCodecContext.Default; | | [$nunitOneTimeSetUp] | public void Setup() | { - | ${fieldsInitialization(definition, srcRef, domain, evo)} + | ${init.shift(4).trim} | } | | ${tests(definition, srcRef, domain, evo)} @@ -89,11 +91,11 @@ object CSCodecTestsTranslator { } private def fieldsInitialization( - definition: DomainMember.User, - srcRef: CSValue.CSType, - domain: Domain, - evolution: BaboonEvolution - ): TextTree[CSValue] = { + definition: DomainMember.User, + srcRef: CSValue.CSType, + domain: Domain, + evolution: BaboonEvolution + ): TextTree[CSValue] = { definition.defn match { case adt: Typedef.Adt => adt @@ -120,7 +122,7 @@ object CSCodecTestsTranslator { srcRef: CSValue.CSType, domain: Domain, evo: BaboonEvolution, - ): TextTree[CSValue] = { + ): TextTree[CSValue] = { codecs .map { case jsonCodec: CSNSJsonCodecGenerator => @@ -128,12 +130,12 @@ object CSCodecTestsTranslator { |public void jsonCodecTest() |{ | ${jsonCodecAssertions( - jsonCodec, - definition, - srcRef, - domain, - evo - ).shift(4).trim} + jsonCodec, + definition, + srcRef, + domain, + evo + ).shift(4).trim} |} |""".stripMargin case uebaCodec: CSUEBACodecGenerator => @@ -141,12 +143,12 @@ object CSCodecTestsTranslator { |public void uebaCodecTest() |{ | ${uebaCodecAssertions( - uebaCodec, - definition, - srcRef, - domain, - evo - ).shift(4).trim} + uebaCodec, + definition, + srcRef, + domain, + evo + ).shift(4).trim} |} |""".stripMargin case unknown => @@ -166,7 +168,7 @@ object CSCodecTestsTranslator { srcRef: CSValue.CSType, domain: Domain, evo: BaboonEvolution, - ): TextTree[CSValue] = { + ): TextTree[CSValue] = { definition.defn match { case adt: Typedef.Adt => adt @@ -178,22 +180,20 @@ object CSCodecTestsTranslator { val fieldName = member.name.name.toLowerCase val serialized = s"${fieldName}_json" val decoded = s"${fieldName}_decoded" - q"""var $serialized = $codecName.Instance.Encode($fieldName); - |var $decoded = $codecName.Instance.Decode($serialized); + q"""var $serialized = $codecName.Instance.Encode(this.context, $fieldName); + |var $decoded = $codecName.Instance.Decode(this.context, $serialized); |Assert.AreEqual($fieldName, $decoded); |""".stripMargin } .toList .join("\n") - .shift(6) - .trim case _ => val codecName = codec.codecName(srcRef) val fieldName = srcRef.name.toLowerCase val serialized = s"${fieldName}_json" val decoded = s"${fieldName}_decoded" - q"""var $serialized = $codecName.Instance.Encode($fieldName); - |var $decoded = $codecName.Instance.Decode($serialized); + q"""var $serialized = $codecName.Instance.Encode(this.context, $fieldName); + |var $decoded = $codecName.Instance.Decode(this.context, $serialized); |Assert.AreEqual($fieldName, $decoded); |""".stripMargin } @@ -204,7 +204,7 @@ object CSCodecTestsTranslator { srcRef: CSValue.CSType, domain: Domain, evo: BaboonEvolution, - ): TextTree[CSValue] = { + ): TextTree[CSValue] = { definition.defn match { case adt: Typedef.Adt => adt @@ -222,21 +222,19 @@ object CSCodecTestsTranslator { |{ | using ($binaryWriter binaryWriter = new $binaryWriter(writeMemoryStream)) | { - | $codecName.Instance.Encode(binaryWriter, $fieldName); + | $codecName.Instance.Encode(this.context, binaryWriter, $fieldName); | } | writeMemoryStream.Flush(); | var $serialized = writeMemoryStream.GetBuffer(); | var $readStream = new MemoryStream($serialized); | var $binaryReader = new BinaryReader($readStream); - | var $decoded = $codecName.Instance.Decode($binaryReader); + | var $decoded = $codecName.Instance.Decode(this.context, $binaryReader); | Assert.AreEqual($fieldName, $decoded); |} |""".stripMargin } .toList .join("\n") - .shift(4) - .trim case _ => val codecName = codec.codecName(srcRef) val fieldName = srcRef.name.toLowerCase @@ -246,17 +244,17 @@ object CSCodecTestsTranslator { |{ | using ($binaryWriter binaryWriter = new $binaryWriter(writeMemoryStream)) | { - | $codecName.Instance.Encode(binaryWriter, $fieldName); + | $codecName.Instance.Encode(this.context, binaryWriter, $fieldName); | } | writeMemoryStream.Flush(); | | var $serialized = writeMemoryStream.GetBuffer(); | var readMemoryStream = new MemoryStream($serialized); | var binaryReader = new BinaryReader(readMemoryStream); - | var $decoded = $codecName.Instance.Decode(binaryReader); + | var $decoded = $codecName.Instance.Decode(this.context, binaryReader); | Assert.AreEqual($fieldName, $decoded); |} - |""".stripMargin.shift(2).trim + |""".stripMargin } } } diff --git a/src/main/scala/io/septimalmind/baboon/translator/csharp/CSNSJsonCodecGenerator.scala b/src/main/scala/io/septimalmind/baboon/translator/csharp/CSNSJsonCodecGenerator.scala index 5ec18ff..5b0b2ae 100644 --- a/src/main/scala/io/septimalmind/baboon/translator/csharp/CSNSJsonCodecGenerator.scala +++ b/src/main/scala/io/septimalmind/baboon/translator/csharp/CSNSJsonCodecGenerator.scala @@ -10,13 +10,13 @@ import izumi.fundamentals.platform.strings.TextTree.* class CSNSJsonCodecGenerator(trans: CSTypeTranslator, tools: CSDefnTools, compilerOptions: CompilerOptions) - extends CSCodecTranslator { + extends CSCodecTranslator { override def translate(defn: DomainMember.User, csRef: CSValue.CSType, srcRef: CSValue.CSType, domain: Domain, evo: BaboonEvolution, - ): Option[TextTree[CSValue]] = { + ): Option[TextTree[CSValue]] = { val version = domain.version (defn.defn match { @@ -39,14 +39,14 @@ class CSNSJsonCodecGenerator(trans: CSTypeTranslator, | ${enc.shift(4).trim} |} | - |return LazyInstance.Value.Encode(value);""".stripMargin + |return LazyInstance.Value.Encode(ctx, value);""".stripMargin val insulatedDec = q"""if (this == LazyInstance.Value) |{ | ${dec.shift(4).trim} |} | - |return LazyInstance.Value.Decode(wire);""".stripMargin + |return LazyInstance.Value.Decode(ctx, wire);""".stripMargin genCodec( defn, @@ -69,32 +69,34 @@ class CSNSJsonCodecGenerator(trans: CSTypeTranslator, dec: TextTree[CSValue], addExtensions: Boolean, evo: BaboonEvolution, - ): TextTree[CSValue] = { + ): TextTree[CSValue] = { val iName = q"$iBaboonJsonCodec<$name>" - val baseMethods = List(q"""public virtual $nsJToken Encode($name value) - |{ - | ${enc.shift(4).trim} - |} - | - |public virtual $name Decode($nsJToken wire) - |{ - | ${dec.shift(4).trim} - |}""".stripMargin) + val baseMethods = List( + q"""public virtual $nsJToken Encode($baboonCodecContext ctx, $name value) + |{ + | ${enc.shift(4).trim} + |} + | + |public virtual $name Decode($baboonCodecContext ctx, $nsJToken wire) + |{ + | ${dec.shift(4).trim} + |}""".stripMargin + ) val (parents, methods) = defn.defn match { case _: Typedef.Enum => (List(q"$iBaboonJsonCodec<$name>"), baseMethods) case _ => val extensions = List( - q"""public virtual $nsJToken Encode($iBaboonGenerated value) + q"""public virtual $nsJToken Encode($baboonCodecContext ctx, $iBaboonGenerated value) |{ | if (value is not $name dvalue) | throw new Exception("Expected to have ${name.name} type"); - | return Encode(dvalue); + | return Encode(ctx, dvalue); |}""".stripMargin, - q"""$iBaboonGenerated IBaboonValueCodec<$iBaboonGenerated, $nsJToken>.Decode($nsJToken wire) + q"""$iBaboonGenerated IBaboonValueCodec<$iBaboonGenerated, $nsJToken>.Decode($baboonCodecContext ctx, $nsJToken wire) |{ - | return Decode(wire); + | return Decode(ctx, wire); |}""".stripMargin ) @@ -127,10 +129,10 @@ class CSNSJsonCodecGenerator(trans: CSTypeTranslator, | ${methods.join("\n\n").shift(4).trim} | | ${tools - .makeMeta(defn, version, evo, isCodec = true) - .join("\n") - .shift(4) - .trim} + .makeMeta(defn, version, evo, isCodec = true) + .join("\n") + .shift(4) + .trim} | | internal static $csLazy<$iName> LazyInstance = new $csLazy<$iName>(() => new $cName()); | @@ -141,8 +143,8 @@ class CSNSJsonCodecGenerator(trans: CSTypeTranslator, } private def genForeignBodies( - name: CSValue.CSType - ): (TextTree[Nothing], TextTree[Nothing]) = { + name: CSValue.CSType + ): (TextTree[Nothing], TextTree[Nothing]) = { ( q"""throw new ArgumentException($$"${name.name} is a foreign type");""", q"""throw new ArgumentException($$"${name.name} is a foreign type");""" @@ -150,23 +152,23 @@ class CSNSJsonCodecGenerator(trans: CSTypeTranslator, } private def wrapAdtBranchEncoder( - branchName: String, - tree: TextTree[CSValue] - ): TextTree[CSValue] = { + branchName: String, + tree: TextTree[CSValue] + ): TextTree[CSValue] = { q"""new $nsJObject(new $nsJProperty("$branchName", $tree))""" } private def genAdtBodies(name: CSValue.CSType, a: Typedef.Adt, domain: Domain, - ): (TextTree[CSValue], TextTree[Nothing]) = { + ): (TextTree[CSValue], TextTree[Nothing]) = { val branches = a.dataMembers(domain).map { m => val branchNs = q"${trans.adtNsName(a.id)}" val branchName = m.name.name val fqBranch = q"$branchNs.$branchName" val routedBranchEncoder = - q"${fqBranch}_JsonCodec.Instance.Encode(($fqBranch)value)" + q"${fqBranch}_JsonCodec.Instance.Encode(ctx, ($fqBranch)value)" val branchEncoder = if (compilerOptions.csWrappedAdtBranchCodecs) { routedBranchEncoder @@ -185,7 +187,7 @@ class CSNSJsonCodecGenerator(trans: CSTypeTranslator, | return $branchEncoder; |}""".stripMargin, q"""if (head.Name == "$branchName") |{ - | return ${fqBranch}_JsonCodec.Instance.Decode($branchValue); + | return ${fqBranch}_JsonCodec.Instance.Decode(ctx, $branchValue); |}""".stripMargin) } @@ -207,8 +209,8 @@ class CSNSJsonCodecGenerator(trans: CSTypeTranslator, } private def genEnumBodies( - name: CSValue.CSType - ): (TextTree[CSValue.CSType], TextTree[CSValue.CSType]) = { + name: CSValue.CSType + ): (TextTree[CSValue.CSType], TextTree[CSValue.CSType]) = { ( q"return $nsJValue.CreateString(value.ToString());", q"""var asStr = wire.Value()?.ToLower().Trim('"'); @@ -231,7 +233,7 @@ class CSNSJsonCodecGenerator(trans: CSTypeTranslator, domain: Domain, d: Typedef.Dto, evo: BaboonEvolution, - ): (TextTree[CSValue], TextTree[CSValue]) = { + ): (TextTree[CSValue], TextTree[CSValue]) = { val fields = d.fields.map { f => val fieldRef = q"value.${f.name.name.capitalize}" val enc = mkEncoder(f.tpe, domain, fieldRef, evo) @@ -294,7 +296,7 @@ class CSNSJsonCodecGenerator(trans: CSTypeTranslator, case _: Typedef.Enum | _: Typedef.Foreign => val targetTpe = trans.toCsTypeRefNoDeref(uid, domain, evo) - q"""${targetTpe}_JsonCodec.Instance.Encode($ref).ToString($nsFormatting.None)""" + q"""${targetTpe}_JsonCodec.Instance.Encode(ctx, $ref).ToString($nsFormatting.None)""" case o => throw new RuntimeException( s"BUG: Unexpected key usertype: $o" @@ -319,7 +321,7 @@ class CSNSJsonCodecGenerator(trans: CSTypeTranslator, q"new $nsJValue($ref)" case u: TypeId.User => val targetTpe = codecName(trans.toCsTypeRefNoDeref(u, domain, evo)) - q"""$targetTpe.Instance.Encode($ref)""" + q"""$targetTpe.Instance.Encode(ctx, $ref)""" } case c: TypeRef.Constructor => c.id match { @@ -348,7 +350,7 @@ class CSNSJsonCodecGenerator(trans: CSTypeTranslator, domain: Domain, ref: TextTree[CSValue], evo: BaboonEvolution, - ): TextTree[CSValue] = { + ): TextTree[CSValue] = { def mkReader(bs: TypeId.BuiltinScalar): TextTree[CSValue] = { val fref = q"$ref!" bs match { @@ -428,7 +430,7 @@ class CSNSJsonCodecGenerator(trans: CSTypeTranslator, case _: Typedef.Enum | _: Typedef.Foreign => val targetTpe = trans.toCsTypeRefNoDeref(uid, domain, evo) - q"""${targetTpe}_JsonCodec.Instance.Decode(new $nsJValue($ref!))""" + q"""${targetTpe}_JsonCodec.Instance.Decode(ctx, new $nsJValue($ref!))""" case o => throw new RuntimeException( s"BUG: Unexpected key usertype: $o" @@ -449,17 +451,17 @@ class CSNSJsonCodecGenerator(trans: CSTypeTranslator, mkReader(bs) case u: TypeId.User => val targetTpe = trans.toCsTypeRefNoDeref(u, domain, evo) - q"""${targetTpe}_JsonCodec.Instance.Decode($ref!)""" + q"""${targetTpe}_JsonCodec.Instance.Decode(ctx, $ref!)""" } case TypeRef.Constructor(id, args) => id match { case TypeId.Builtins.opt if trans.isCSValueType(args.head, domain) => q"""$BaboonTools.ReadNullableValueType($ref, t => ${mkDecoder( - args.head, - domain, - q"t", - evo - )})""".stripMargin + args.head, + domain, + q"t", + evo + )})""".stripMargin case TypeId.Builtins.opt => q"""$BaboonTools.ReadNullableReferentialType($ref, t => ${mkDecoder( diff --git a/src/main/scala/io/septimalmind/baboon/translator/csharp/CSUEBACodecGenerator.scala b/src/main/scala/io/septimalmind/baboon/translator/csharp/CSUEBACodecGenerator.scala index 9d939ad..c9326f4 100644 --- a/src/main/scala/io/septimalmind/baboon/translator/csharp/CSUEBACodecGenerator.scala +++ b/src/main/scala/io/septimalmind/baboon/translator/csharp/CSUEBACodecGenerator.scala @@ -10,7 +10,7 @@ import izumi.fundamentals.platform.strings.TextTree.* class CSUEBACodecGenerator(trans: CSTypeTranslator, tools: CSDefnTools, options: CompilerOptions) - extends CSCodecTranslator { + extends CSCodecTranslator { override def translate(defn: DomainMember.User, csRef: CSValue.CSType, srcRef: CSValue.CSType, @@ -41,14 +41,14 @@ class CSUEBACodecGenerator(trans: CSTypeTranslator, |} |#pragma warning disable CS0162 | - |LazyInstance.Value.Encode(writer, value);""".stripMargin + |LazyInstance.Value.Encode(ctx, writer, value);""".stripMargin val insulatedDec = q"""if (this == LazyInstance.Value) |{ | ${dec.shift(4).trim} |} | - |return LazyInstance.Value.Decode(wire);""".stripMargin + |return LazyInstance.Value.Decode(ctx, wire);""".stripMargin val branchDecoder = defn.defn match { case d: Typedef.Dto => @@ -71,29 +71,28 @@ class CSUEBACodecGenerator(trans: CSTypeTranslator, } } - private def genCodec( - defn: DomainMember.User, - name: CSValue.CSType, - srcRef: CSValue.CSType, - version: Version, - enc: TextTree[CSValue], - dec: TextTree[CSValue], - addExtensions: Boolean, - branchDecoder: Option[TextTree[CSValue]], - evo: BaboonEvolution, - ): TextTree[CSValue] = { + private def genCodec(defn: DomainMember.User, + name: CSValue.CSType, + srcRef: CSValue.CSType, + version: Version, + enc: TextTree[CSValue], + dec: TextTree[CSValue], + addExtensions: Boolean, + branchDecoder: Option[TextTree[CSValue]], + evo: BaboonEvolution, + ): TextTree[CSValue] = { val iName = q"$iBaboonBinCodec<$name>" val baseMethods = List( - q"""public virtual void Encode($binaryWriter writer, $name value) + q"""public virtual void Encode($baboonCodecContext ctx, $binaryWriter writer, $name value) |{ | ${enc.shift(4).trim} |} - |public virtual $name Decode($binaryReader wire) { + |public virtual $name Decode($baboonCodecContext ctx, $binaryReader wire) { | ${dec.shift(4).trim} |}""".stripMargin ) ++ branchDecoder.map { body => - q"""internal $name DecodeBranch($binaryReader wire) { + q"""internal $name DecodeBranch($baboonCodecContext ctx, $binaryReader wire) { | ${body.shift(4).trim} |}""".stripMargin }.toList @@ -103,15 +102,15 @@ class CSUEBACodecGenerator(trans: CSTypeTranslator, (List(q"$iBaboonBinCodec<$name>"), baseMethods) case _ => val extensions = List( - q"""public virtual void Encode($binaryWriter writer, $iBaboonGenerated value) + q"""public virtual void Encode($baboonCodecContext ctx,$binaryWriter writer, $iBaboonGenerated value) |{ | if (value is not $name dvalue) | throw new Exception("Expected to have ${name.name} type"); - | Encode(writer, dvalue); + | Encode(ctx, writer, dvalue); |}""".stripMargin, - q"""$iBaboonGenerated $iBaboonStreamCodec<$iBaboonGenerated, $binaryWriter, $binaryReader>.Decode($binaryReader wire) + q"""$iBaboonGenerated $iBaboonStreamCodec<$iBaboonGenerated, $binaryWriter, $binaryReader>.Decode($baboonCodecContext ctx, $binaryReader wire) |{ - | return Decode(wire); + | return Decode(ctx, wire); |}""".stripMargin ) @@ -144,10 +143,10 @@ class CSUEBACodecGenerator(trans: CSTypeTranslator, | ${methods.join("\n\n").shift(4).trim} | | ${tools - .makeMeta(defn, version, evo, isCodec = true) - .join("\n") - .shift(4) - .trim} + .makeMeta(defn, version, evo, isCodec = true) + .join("\n") + .shift(4) + .trim} | | internal static $csLazy<$iName> LazyInstance = new $csLazy<$iName>(() => new $cName()); | @@ -167,7 +166,7 @@ class CSUEBACodecGenerator(trans: CSTypeTranslator, domain: Domain, a: Typedef.Adt, evo: BaboonEvolution, - ) = { + ) = { val branches = a.dataMembers(domain).zipWithIndex.toList.map { case (m, idx) => val branchNs = q"${trans.adtNsName(a.id)}" @@ -180,17 +179,17 @@ class CSUEBACodecGenerator(trans: CSTypeTranslator, val castedName = branchName.toLowerCase val encBody = if (options.csWrappedAdtBranchCodecs) { - q"""$cName.Instance.Encode(writer, $castedName);""" + q"""$cName.Instance.Encode(ctx, writer, $castedName);""" } else { q"""writer.Write((byte)${idx.toString}); - |$cName.Instance.Encode(writer, $castedName); + |$cName.Instance.Encode(ctx, writer, $castedName); """.stripMargin } val decBody = if (options.csWrappedAdtBranchCodecs) { - q"""return (($cName)$cName.Instance).DecodeBranch(wire);""" + q"""return (($cName)$cName.Instance).DecodeBranch(ctx, wire);""" } else { - q"""return $cName.Instance.Decode(wire);""" + q"""return $cName.Instance.Decode(ctx, wire);""" } (q"""if (value is $fqBranch $castedName) @@ -241,11 +240,11 @@ class CSUEBACodecGenerator(trans: CSTypeTranslator, } private def genBranchDecoder( - name: CSValue.CSType, - domain: Domain, - d: Typedef.Dto, - evo: BaboonEvolution - ): Option[TextTree[CSValue]] = { + name: CSValue.CSType, + domain: Domain, + d: Typedef.Dto, + evo: BaboonEvolution + ): Option[TextTree[CSValue]] = { d.id.owner match { case Owner.Adt(_) if options.csWrappedAdtBranchCodecs => @@ -264,8 +263,8 @@ class CSUEBACodecGenerator(trans: CSTypeTranslator, val fenc = q"""${fields - .map(_._1) - .join(";\n")};""".stripMargin + .map(_._1) + .join(";\n")};""".stripMargin val fdec = dtoDec(name, fields) @@ -298,7 +297,7 @@ class CSUEBACodecGenerator(trans: CSTypeTranslator, q"""byte marker = wire.ReadByte(); |${CSBaboonTranslator.debug}.Assert(marker == ${idx.toString}); - |return DecodeBranch(wire);""".stripMargin + |return DecodeBranch(ctx, wire);""".stripMargin case _ => fdec } @@ -365,24 +364,24 @@ class CSUEBACodecGenerator(trans: CSTypeTranslator, } case u: TypeId.User => val targetTpe = codecName(trans.toCsTypeRefNoDeref(u, domain, evo)) - q"""$targetTpe.Instance.Decode(wire)""" + q"""$targetTpe.Instance.Decode(ctx, wire)""" } case c: TypeRef.Constructor => c.id match { case TypeId.Builtins.opt - if trans.isCSValueType(c.args.head, domain) => + if trans.isCSValueType(c.args.head, domain) => q"""$BaboonTools.ReadNullableValueType(wire.ReadByte() == 0, () => ${mkDecoder( - c.args.head, - domain, - evo - )})""".stripMargin + c.args.head, + domain, + evo + )})""".stripMargin case TypeId.Builtins.opt => q"""(wire.ReadByte() == 0 ? null : ${mkDecoder( - c.args.head, - domain, - evo - )})""".stripMargin + c.args.head, + domain, + evo + )})""".stripMargin case TypeId.Builtins.map => val keyRef = c.args.head @@ -421,7 +420,7 @@ class CSUEBACodecGenerator(trans: CSTypeTranslator, domain: Domain, ref: TextTree[CSValue], evo: BaboonEvolution, - ): TextTree[CSValue] = { + ): TextTree[CSValue] = { tpe match { case TypeRef.Scalar(id) => id match { @@ -462,7 +461,7 @@ class CSUEBACodecGenerator(trans: CSTypeTranslator, } case u: TypeId.User => val targetTpe = codecName(trans.toCsTypeRefNoDeref(u, domain, evo)) - q"""$targetTpe.Instance.Encode(writer, $ref)""" + q"""$targetTpe.Instance.Encode(ctx, writer, $ref)""" } case c: TypeRef.Constructor => c.id match { @@ -474,22 +473,22 @@ class CSUEBACodecGenerator(trans: CSTypeTranslator, |{ | writer.Write((byte)1); | ${mkEncoder( - c.args.head, - domain, - trans.deNull(c.args.head, domain, ref), - evo - ).shift(4).trim}; + c.args.head, + domain, + trans.deNull(c.args.head, domain, ref), + evo + ).shift(4).trim}; |}""".stripMargin case TypeId.Builtins.map => q"""writer.Write($ref.Count()); |foreach (var kv in $ref) |{ | ${mkEncoder(c.args.head, domain, q"kv.Key", evo) - .shift(4) - .trim}; + .shift(4) + .trim}; | ${mkEncoder(c.args.last, domain, q"kv.Value", evo) - .shift(4) - .trim}; + .shift(4) + .trim}; |}""".stripMargin case TypeId.Builtins.lst => q"""writer.Write($ref.Count()); @@ -527,11 +526,14 @@ class CSUEBACodecGenerator(trans: CSTypeTranslator, CodecMeta(member) } - def codecInterfaceProperty(): TextTree[CSValue] = q"public $iBaboonCodecData Ueba { get; }"; + def codecInterfaceProperty(): TextTree[CSValue] = + q"public $iBaboonCodecData Ueba { get; }"; - def codecImplProperty(): TextTree[CSValue] = q"public $iBaboonCodecData Ueba => LazyUeba.Value;"; + def codecImplProperty(): TextTree[CSValue] = + q"public $iBaboonCodecData Ueba => LazyUeba.Value;"; - def codecGenericImplField(): TextTree[CSValue] = q"Lazy<$iBaboonBinCodec> LazyUeba"; + def codecGenericImplField(): TextTree[CSValue] = + q"Lazy<$iBaboonBinCodec> LazyUeba"; def codecImplField(): TextTree[CSValue] = q"Lazy<$iBaboonCodecData> LazyUeba"; }