Skip to content

Commit 53780f9

Browse files
committed
Fix SizedCodec.size marco code when handling IgnoreTransientDefaultMarker
1 parent b19248f commit 53780f9

File tree

2 files changed

+79
-24
lines changed

2 files changed

+79
-24
lines changed

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,30 @@ object CustomWrapper extends HasApplyUnapplyCodec[CustomWrapper] {
2525
def unapply(cw: CustomWrapper): Opt[String] = Opt(cw.a)
2626
}
2727

28+
case class RecordWithOpts(
29+
@optionalParam abc: Opt[String] = Opt.Empty,
30+
@transientDefault flag: Opt[Boolean] = Opt.Empty,
31+
b: Int = 42,
32+
)
33+
object RecordWithOpts extends HasApplyUnapplyCodec[RecordWithOpts]
34+
35+
case class SingleFieldRecordWithOpts(@optionalParam abc: Opt[String] = Opt.Empty)
36+
object SingleFieldRecordWithOpts extends HasApplyUnapplyCodec[SingleFieldRecordWithOpts]
37+
38+
case class SingleFieldRecordWithTD(@transientDefault abc: String = "abc")
39+
object SingleFieldRecordWithTD extends HasApplyUnapplyCodec[SingleFieldRecordWithTD]
40+
2841
class ObjectSizeTest extends AnyFunSuite {
2942
test("computing object size") {
3043
assert(RecordWithDefaults.codec.size(RecordWithDefaults()) == 2)
3144
assert(RecordWithDefaults.codec.size(RecordWithDefaults("fuu")) == 3)
45+
assert(RecordWithOpts.codec.size(RecordWithOpts("abc".opt)) == 2)
46+
assert(RecordWithOpts.codec.size(RecordWithOpts("abc".opt, true.opt)) == 3)
47+
assert(RecordWithOpts.codec.size(RecordWithOpts()) == 1)
48+
assert(SingleFieldRecordWithOpts.codec.size(SingleFieldRecordWithOpts()) == 0)
49+
assert(SingleFieldRecordWithOpts.codec.size(SingleFieldRecordWithOpts("abc".opt)) == 1)
50+
assert(SingleFieldRecordWithTD.codec.size(SingleFieldRecordWithTD()) == 0)
51+
assert(SingleFieldRecordWithTD.codec.size(SingleFieldRecordWithTD("haha")) == 1)
3252
assert(CustomRecordWithDefaults.codec.size(CustomRecordWithDefaults()) == 1)
3353
assert(CustomRecordWithDefaults.codec.size(CustomRecordWithDefaults("fuu")) == 2)
3454
assert(CustomWrapper.codec.size(CustomWrapper()) == 0)
@@ -46,6 +66,13 @@ class ObjectSizeTest extends AnyFunSuite {
4666
}
4767
assert(RecordWithDefaults.codec.size(RecordWithDefaults(), defaultIgnoringOutput.opt) == 3)
4868
assert(RecordWithDefaults.codec.size(RecordWithDefaults("fuu"), defaultIgnoringOutput.opt) == 3)
69+
assert(RecordWithOpts.codec.size(RecordWithOpts("abc".opt), defaultIgnoringOutput.opt) == 3)
70+
assert(RecordWithOpts.codec.size(RecordWithOpts("abc".opt, true.opt), defaultIgnoringOutput.opt) == 3)
71+
assert(RecordWithOpts.codec.size(RecordWithOpts(), defaultIgnoringOutput.opt) == 2)
72+
assert(SingleFieldRecordWithOpts.codec.size(SingleFieldRecordWithOpts(), defaultIgnoringOutput.opt) == 0) // @optionalParam field should NOT be counted
73+
assert(SingleFieldRecordWithOpts.codec.size(SingleFieldRecordWithOpts("abc".opt), defaultIgnoringOutput.opt) == 1)
74+
assert(SingleFieldRecordWithTD.codec.size(SingleFieldRecordWithTD(), defaultIgnoringOutput.opt) == 1) // @transientDefault field should be counted
75+
assert(SingleFieldRecordWithTD.codec.size(SingleFieldRecordWithTD("haha"), defaultIgnoringOutput.opt) == 1)
4976
assert(CustomRecordWithDefaults.codec.size(CustomRecordWithDefaults(), defaultIgnoringOutput.opt) == 2)
5077
assert(CustomRecordWithDefaults.codec.size(CustomRecordWithDefaults("fuu"), defaultIgnoringOutput.opt) == 2)
5178
}

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

Lines changed: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -251,38 +251,66 @@ class GenCodecMacros(ctx: blackbox.Context) extends CodecMacroCommons(ctx) with
251251
def anyParamHasTransientDefault: Boolean =
252252
params.exists(isTransientDefault)
253253

254+
def isOptionLike(p: ApplyParam): Boolean =
255+
p.optionLike.nonEmpty
256+
254257
def mayBeTransient(p: ApplyParam): Boolean =
255-
p.optionLike.nonEmpty || isTransientDefault(p)
258+
isOptionLike(p) || isTransientDefault(p)
256259

257260
def transientValue(p: ApplyParam): Tree = p.optionLike match {
258261
case Some(optionLike) => q"${optionLike.reference(Nil)}.none"
259262
case None => p.defaultValue
260263
}
261264

262-
def countTransientFields: Tree =
265+
// assumes usage in in size(value, output) method implementation
266+
def countTransientFields: Tree = {
267+
def checkIgnoreTransientDefaultMarker: Tree =
268+
q"output.isDefined && output.get.customEvent($SerializationPkg.IgnoreTransientDefaultMarker, ())"
269+
270+
def doCount(paramsToCount: List[ApplyParam], accessor: ApplyParam => Tree): Tree =
271+
paramsToCount.foldLeft[Tree](q"0") {
272+
(acc, p) => q"$acc + (if(${accessor(p)} == ${transientValue(p)}) 1 else 0)"
273+
}
274+
275+
def countOnlyOptionLike(accessor: ApplyParam => Tree): Tree =
276+
doCount(params.filter(isOptionLike), accessor)
277+
278+
def countTransient(accessor: ApplyParam => Tree): Tree =
279+
doCount(params.filter(mayBeTransient), accessor)
280+
281+
def countMultipleParams(accessor: ApplyParam => Tree): Tree =
282+
if (anyParamHasTransientDefault)
283+
q"if($checkIgnoreTransientDefaultMarker) ${countOnlyOptionLike(accessor)} else ${countTransient(accessor)}"
284+
else
285+
countTransient(accessor)
286+
287+
def countSingleParam(param: ApplyParam, value: Tree): Tree =
288+
if (isTransientDefault(param))
289+
q"if(!$checkIgnoreTransientDefaultMarker && $value == ${transientValue(param)}) 1 else 0"
290+
else
291+
q"if($value == ${transientValue(param)}) 1 else 0"
292+
263293
if (canUseFields)
264-
params.filter(mayBeTransient).foldLeft[Tree](q"0") {
265-
(acc, p) => q"$acc + (if(value.${p.sym.name} == ${transientValue(p)}) 1 else 0)"
294+
countMultipleParams(p => q"value.${p.sym.name}")
295+
else if (!params.exists(mayBeTransient))
296+
q"0"
297+
else
298+
params match {
299+
case List(p: ApplyParam) =>
300+
q"""
301+
val unapplyRes = $companion.$unapply[..${dtpe.typeArgs}](value)
302+
if(unapplyRes.isEmpty) unapplyFailed else { ${countSingleParam(p, q"unapplyRes.get")} }
303+
"""
304+
case _ =>
305+
q"""
306+
val unapplyRes = $companion.$unapply[..${dtpe.typeArgs}](value)
307+
if(unapplyRes.isEmpty) unapplyFailed else {
308+
val t = unapplyRes.get
309+
${countMultipleParams(p => q"t.${tupleGet(p.idx)}")}
310+
}
311+
"""
266312
}
267-
else if (!params.exists(mayBeTransient)) q"0"
268-
else params match {
269-
case List(p: ApplyParam) =>
270-
q"""
271-
val unapplyRes = $companion.$unapply[..${dtpe.typeArgs}](value)
272-
if(unapplyRes.isEmpty) unapplyFailed else if(unapplyRes.get == ${transientValue(p)}) 1 else 0
273-
"""
274-
case _ =>
275-
val res = params.filter(mayBeTransient).foldLeft[Tree](q"0") {
276-
(acc, p) => q"$acc + (if(t.${tupleGet(p.idx)} == ${transientValue(p)}) 1 else 0)"
277-
}
278-
q"""
279-
val unapplyRes = $companion.$unapply[..${dtpe.typeArgs}](value)
280-
if(unapplyRes.isEmpty) unapplyFailed else {
281-
val t = unapplyRes.get
282-
$res
283-
}
284-
"""
285-
}
313+
}
286314

287315
if (isTransparent(dtpe.typeSymbol)) params match {
288316
case List(p: ApplyParam) =>
@@ -331,7 +359,7 @@ class GenCodecMacros(ctx: blackbox.Context) extends CodecMacroCommons(ctx) with
331359
val res =
332360
q"""
333361
def size(value: $dtpe, output: $OptCls[$SerializationPkg.SequentialOutput]): $IntCls =
334-
${params.size} + ${generated.size} - output.filter(_.customEvent($SerializationPkg.IgnoreTransientDefaultMarker, ())).mapOr($countTransientFields, _ => 0)
362+
${params.size} + ${generated.size} - { $countTransientFields }
335363
"""
336364
List(res)
337365
}

0 commit comments

Comments
 (0)