Skip to content

Commit b19248f

Browse files
committed
Optimize macro code when handling IgnoreTransientDefaultMarker
1 parent 37c2a77 commit b19248f

File tree

2 files changed

+67
-29
lines changed

2 files changed

+67
-29
lines changed

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

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ object IgnoreTransientDefaultMarkerTest {
1111
@transientDefault defaultObj: HasDefaults = HasDefaults(),
1212
)
1313
object NestedHasDefaults extends HasGenCodec[NestedHasDefaults]
14+
15+
final case class HasOptParam(
16+
@transientDefault flag: Boolean = false,
17+
@optionalParam str: Opt[String] = Opt.Empty,
18+
)
19+
object HasOptParam extends HasGenCodec[HasOptParam]
1420
}
1521

1622
class IgnoreTransientDefaultMarkerTest extends AbstractCodecTest {
@@ -24,16 +30,31 @@ class IgnoreTransientDefaultMarkerTest extends AbstractCodecTest {
2430
result
2531
}
2632

27-
def createInput(raw: Any): Input = new SimpleValueInput(raw)
33+
def createInput(raw: Any): Input =
34+
CustomMarkersInputWrapper(new SimpleValueInput(raw), IgnoreTransientDefaultMarker)
2835

29-
test("case class with default values") {
36+
test("write case class with default values") {
3037
testWrite(HasDefaults(str = "lol"), Map("str" -> "lol", "int" -> 42))
3138
testWrite(HasDefaults(43, "lol"), Map("int" -> 43, "str" -> "lol"))
3239
testWrite(HasDefaults(str = null), Map("str" -> null, "int" -> 42))
3340
testWrite(HasDefaults(str = "dafuq"), Map("str" -> "dafuq", "int" -> 42))
3441
}
3542

36-
test("nested case class with default values") {
43+
test("read case class with default values") {
44+
testRead(Map("str" -> "lol", "int" -> 42), HasDefaults(str = "lol", int = 42))
45+
testRead(Map("str" -> "lol"), HasDefaults(str = "lol", int = 42))
46+
testRead(Map("int" -> 43, "str" -> "lol"), HasDefaults(int = 43, str = "lol"))
47+
testRead(Map("str" -> null, "int" -> 42), HasDefaults(str = null, int = 42))
48+
testRead(Map("str" -> null), HasDefaults(str = null, int = 42))
49+
testRead(Map(), HasDefaults(str = "dafuq", int = 42))
50+
}
51+
52+
test("write case class with opt values") {
53+
testWrite(HasOptParam(str = "lol".opt), Map("flag" -> false, "str" -> "lol"))
54+
testWrite(HasOptParam(), Map("flag" -> false))
55+
}
56+
57+
test("write nested case class with default values") {
3758
testWrite(
3859
value = NestedHasDefaults(
3960
flag = false,

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

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -172,24 +172,48 @@ class GenCodecMacros(ctx: blackbox.Context) extends CodecMacroCommons(ctx) with
172172
}
173173
}
174174

175-
def writeField(p: ApplyParam, value: Tree): Tree = {
175+
def doWriteField(p: ApplyParam, value: Tree, transientValue: Option[Tree]): Tree = {
176+
val writeArgs = q"output" :: q"${p.idx}" :: value :: transientValue.toList
177+
val writeTargs = if (isOptimizedPrimitive(p)) Nil else List(p.valueType)
178+
q"writeField[..$writeTargs](..$writeArgs)"
179+
}
180+
181+
def writeFieldNoTransientDefault(p: ApplyParam, value: Tree): Tree = {
182+
val transientValue = p.optionLike.map(ol => q"${ol.reference(Nil)}.none")
183+
doWriteField(p, value, transientValue)
184+
}
185+
186+
def writeFieldTransientDefaultPossible(p: ApplyParam, value: Tree): Tree = {
176187
val transientValue =
177188
if (isTransientDefault(p)) Some(p.defaultValue)
178189
else p.optionLike.map(ol => q"${ol.reference(Nil)}.none")
179-
180-
val writeArgsNoTransient = q"output" :: q"${p.idx}" :: List(value)
181-
val writeArgs = writeArgsNoTransient ::: transientValue.toList
182-
val writeTargs = if (isOptimizedPrimitive(p)) Nil else List(p.valueType)
183-
q"""
184-
if (ignoreTransientDefault)
185-
writeField[..$writeTargs](..$writeArgsNoTransient)
186-
else
187-
writeField[..$writeTargs](..$writeArgs)
188-
"""
190+
doWriteField(p, value, transientValue)
189191
}
190192

193+
def writeField(p: ApplyParam, value: Tree, ignoreTransientDefault: Tree): Tree =
194+
if (isTransientDefault(p))
195+
q"""
196+
if ($ignoreTransientDefault) ${writeFieldNoTransientDefault(p, value)}
197+
else ${writeFieldTransientDefaultPossible(p, value)}
198+
"""
199+
else
200+
writeFieldNoTransientDefault(p, value)
201+
191202
def ignoreTransientDefaultCheck: Tree =
192-
q"val ignoreTransientDefault = output.customEvent($SerializationPkg.IgnoreTransientDefaultMarker, ())"
203+
q"output.customEvent($SerializationPkg.IgnoreTransientDefaultMarker, ())"
204+
205+
// when params size is 1
206+
def writeSingle(p: ApplyParam, value: Tree): Tree =
207+
writeField(p, value, ignoreTransientDefaultCheck)
208+
209+
// when params size is greater than 1
210+
def writeMultiple(value: ApplyParam => Tree): Tree =
211+
if (anyParamHasTransientDefault) {
212+
q"""
213+
val ignoreTransientDefault = $ignoreTransientDefaultCheck
214+
..${params.map(p => writeField(p, value(p), q"ignoreTransientDefault"))}
215+
"""
216+
} else q"..${params.map(p => writeFieldNoTransientDefault(p, value(p)))}"
193217

194218
def writeFields: Tree = params match {
195219
case Nil =>
@@ -203,37 +227,30 @@ class GenCodecMacros(ctx: blackbox.Context) extends CodecMacroCommons(ctx) with
203227
"""
204228
case List(p: ApplyParam) =>
205229
if (canUseFields)
206-
q"""
207-
$ignoreTransientDefaultCheck
208-
${writeField(p, q"value.${p.sym.name}")}
209-
"""
230+
q"${writeSingle(p, q"value.${p.sym.name}")}"
210231
else
211232
q"""
212233
val unapplyRes = $companion.$unapply[..${dtpe.typeArgs}](value)
213234
if (unapplyRes.isEmpty) unapplyFailed
214-
else {
215-
$ignoreTransientDefaultCheck
216-
${writeField(p, q"unapplyRes.get")}
217-
}
235+
else ${writeSingle(p, q"unapplyRes.get")}
218236
"""
219237
case _ =>
220238
if (canUseFields)
221-
q"""
222-
$ignoreTransientDefaultCheck
223-
..${params.map(p => writeField(p, q"value.${p.sym.name}"))}
224-
"""
239+
q"${writeMultiple(p => q"value.${p.sym.name}")}"
225240
else
226241
q"""
227242
val unapplyRes = $companion.$unapply[..${dtpe.typeArgs}](value)
228243
if (unapplyRes.isEmpty) unapplyFailed
229244
else {
230245
val t = unapplyRes.get
231-
$ignoreTransientDefaultCheck
232-
..${params.map(p => writeField(p, q"t.${tupleGet(p.idx)}"))}
246+
${writeMultiple(p => q"t.${tupleGet(p.idx)}")}
233247
}
234248
"""
235249
}
236250

251+
def anyParamHasTransientDefault: Boolean =
252+
params.exists(isTransientDefault)
253+
237254
def mayBeTransient(p: ApplyParam): Boolean =
238255
p.optionLike.nonEmpty || isTransientDefault(p)
239256

0 commit comments

Comments
 (0)