Skip to content

Commit 37c2a77

Browse files
committed
Handle com.avsystem.commons.serialization.GenCodec.SizedCodec.size with IgnoreTransientDefaultMarker
1 parent 4276c36 commit 37c2a77

File tree

6 files changed

+68
-15
lines changed

6 files changed

+68
-15
lines changed

core/src/main/scala/com/avsystem/commons/serialization/GenCodec.scala

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -312,11 +312,13 @@ object GenCodec extends RecursiveAutoCodecs with TupleGenCodecs {
312312
}
313313

314314
trait SizedCodec[T] extends GenCodec[T] {
315-
def size(value: T): Int
315+
def size(value: T): Int = size(value, Opt.Empty)
316+
317+
def size(value: T, output: Opt[SequentialOutput]): Int
316318

317319
protected final def declareSizeFor(output: SequentialOutput, value: T): Unit =
318320
if (output.sizePolicy != SizePolicy.Ignored) {
319-
output.declareSize(size(value))
321+
output.declareSize(size(value, output.opt))
320322
}
321323
}
322324

@@ -336,8 +338,8 @@ object GenCodec extends RecursiveAutoCodecs with TupleGenCodecs {
336338
object OOOFieldsObjectCodec {
337339
// this was introduced so that transparent wrapper cases are possible in flat sealed hierarchies
338340
final class Transformed[A, B](val wrapped: OOOFieldsObjectCodec[B], onWrite: A => B, onRead: B => A) extends OOOFieldsObjectCodec[A] {
339-
def size(value: A): Int =
340-
wrapped.size(onWrite(value))
341+
def size(value: A, output: Opt[SequentialOutput]): Int =
342+
wrapped.size(onWrite(value), output)
341343

342344
def readObject(input: ObjectInput, outOfOrderFields: FieldValues): A =
343345
onRead(wrapped.readObject(input, outOfOrderFields))

core/src/main/scala/com/avsystem/commons/serialization/cbor/CborOptimizedCodecs.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ class OOOFieldCborRawKeysCodec[T](stdObjectCodec: OOOFieldsObjectCodec[T], keyCo
8787
stdObjectCodec.writeFields(output, value)
8888
}
8989

90-
def size(value: T): Int = stdObjectCodec.size(value)
90+
def size(value: T, output: Opt[SequentialOutput]): Int = stdObjectCodec.size(value, output)
9191
def nullable: Boolean = stdObjectCodec.nullable
9292
}
9393

core/src/main/scala/com/avsystem/commons/serialization/macroCodecs.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class SingletonCodec[T <: Singleton](
1212
) extends ErrorReportingCodec[T] with OOOFieldsObjectCodec[T] {
1313
final def nullable = true
1414
final def readObject(input: ObjectInput, outOfOrderFields: FieldValues): T = singletonValue
15-
def size(value: T): Int = 0
15+
def size(value: T, output: Opt[SequentialOutput]): Int = 0
1616
def writeFields(output: ObjectOutput, value: T): Unit = ()
1717
}
1818

@@ -109,7 +109,7 @@ abstract class ProductCodec[T <: Product](
109109
nullable: Boolean,
110110
fieldNames: Array[String]
111111
) extends ApplyUnapplyCodec[T](typeRepr, nullable, fieldNames) {
112-
def size(value: T): Int = value.productArity
112+
def size(value: T, output: Opt[SequentialOutput]): Int = value.productArity
113113

114114
final def writeFields(output: ObjectOutput, value: T): Unit = {
115115
val size = value.productArity

core/src/test/scala/com/avsystem/commons/serialization/ObjectSizeTest.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,19 @@ class ObjectSizeTest extends AnyFunSuite {
3434
assert(CustomWrapper.codec.size(CustomWrapper()) == 0)
3535
assert(CustomWrapper.codec.size(CustomWrapper("fuu")) == 1)
3636
}
37+
38+
test("computing object size with custom output") {
39+
val defaultIgnoringOutput = new SequentialOutput {
40+
override def customEvent[T](marker: CustomEventMarker[T], event: T): Boolean =
41+
marker match {
42+
case IgnoreTransientDefaultMarker => true
43+
case _ => super.customEvent(marker, event)
44+
}
45+
override def finish(): Unit = ()
46+
}
47+
assert(RecordWithDefaults.codec.size(RecordWithDefaults(), defaultIgnoringOutput.opt) == 3)
48+
assert(RecordWithDefaults.codec.size(RecordWithDefaults("fuu"), defaultIgnoringOutput.opt) == 3)
49+
assert(CustomRecordWithDefaults.codec.size(CustomRecordWithDefaults(), defaultIgnoringOutput.opt) == 2)
50+
assert(CustomRecordWithDefaults.codec.size(CustomRecordWithDefaults("fuu"), defaultIgnoringOutput.opt) == 2)
51+
}
3752
}

core/src/test/scala/com/avsystem/commons/serialization/cbor/CborInputOutputTest.scala

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,18 @@ case class CustomKeysRecord(
2828
)
2929
object CustomKeysRecord extends HasCborCodec[CustomKeysRecord]
3030

31+
case class CustomKeysRecordWithDefaults(
32+
@transientDefault @cborKey(1) first: Int = 0,
33+
@cborKey(true) second: Boolean,
34+
)
35+
object CustomKeysRecordWithDefaults extends HasCborCodec[CustomKeysRecordWithDefaults]
36+
37+
case class CustomKeysRecordWithNoDefaults(
38+
@cborKey(1) first: Int = 0,
39+
@cborKey(true) second: Boolean,
40+
)
41+
object CustomKeysRecordWithNoDefaults extends HasCborCodec[CustomKeysRecordWithNoDefaults]
42+
3143
@cborDiscriminator(0)
3244
sealed trait GenericSealedTrait[+T]
3345
object GenericSealedTrait extends HasPolyCborCodec[GenericSealedTrait] {
@@ -61,14 +73,22 @@ class CborInputOutputTest extends AnyFunSuite {
6173
keyCodec: CborKeyCodec = CborKeyCodec.Default
6274
)(implicit pos: Position): Unit =
6375
test(s"${pos.lineNumber}: $value") {
64-
val baos = new ByteArrayOutputStream
65-
val output = new CborOutput(new DataOutputStream(baos), keyCodec, SizePolicy.Optional)
66-
GenCodec.write[T](output, value)
67-
val bytes = baos.toByteArray
68-
assert(Bytes(bytes).toString == binary)
69-
assert(RawCbor(bytes).readAs[T](keyCodec) == value)
76+
assertRoundtrip(value, binary, keyCodec)
7077
}
7178

79+
private def assertRoundtrip[T: GenCodec](
80+
value: T,
81+
binary: String,
82+
keyCodec: CborKeyCodec = CborKeyCodec.Default
83+
)(implicit pos: Position): Unit = {
84+
val baos = new ByteArrayOutputStream
85+
val output = new CborOutput(new DataOutputStream(baos), keyCodec, SizePolicy.Optional)
86+
GenCodec.write[T](output, value)
87+
val bytes = baos.toByteArray
88+
assert(Bytes(bytes).toString == binary)
89+
assert(RawCbor(bytes).readAs[T](keyCodec) == value)
90+
}
91+
7292
// binary representation from cbor.me
7393

7494
roundtrip(null, "F6")
@@ -213,6 +233,22 @@ class CborInputOutputTest extends AnyFunSuite {
213233
"""{"first":42,"second":true,"third":"foo","strMap":{"foo":1},"intMap":{"1":"foo"}}""")
214234
}
215235

236+
test("writing with IgnoreTransientDefaultMarker to CBOR output") {
237+
val baos = new ByteArrayOutputStream
238+
val output = CustomMarkersOutputWrapper(
239+
new CborOutput(new DataOutputStream(baos), keyCodec, SizePolicy.Optional),
240+
IgnoreTransientDefaultMarker,
241+
)
242+
val value = CustomKeysRecordWithDefaults(first = 0, second = true)
243+
GenCodec.write(output, value)
244+
val bytes = Bytes(baos.toByteArray)
245+
assert(bytes.toString == "A20100F5F5")
246+
assert(RawCbor(bytes.bytes).readAs[CustomKeysRecordWithDefaults](keyCodec) == value)
247+
248+
// should be the same as model with @transientDefault and serialization ignoring it
249+
assertRoundtrip(CustomKeysRecordWithNoDefaults(first = 0, second = true), "A20100F5F5")
250+
}
251+
216252
test("chunked text string") {
217253
assert(CborInput.readRawCbor[String](RawCbor.fromHex("7F626162626162626162FF")) == "ababab")
218254
}

macros/src/main/scala/com/avsystem/commons/macros/serialization/GenCodecMacros.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -313,8 +313,8 @@ class GenCodecMacros(ctx: blackbox.Context) extends CodecMacroCommons(ctx) with
313313
def sizeMethod: List[Tree] = if (useProductCodec) Nil else {
314314
val res =
315315
q"""
316-
def size(value: $dtpe): $IntCls =
317-
${params.size} + ${generated.size} - $countTransientFields
316+
def size(value: $dtpe, output: $OptCls[$SerializationPkg.SequentialOutput]): $IntCls =
317+
${params.size} + ${generated.size} - output.filter(_.customEvent($SerializationPkg.IgnoreTransientDefaultMarker, ())).mapOr($countTransientFields, _ => 0)
318318
"""
319319
List(res)
320320
}

0 commit comments

Comments
 (0)