Skip to content

Commit 765b21b

Browse files
committed
More efficient codec derivation
1 parent 4369564 commit 765b21b

File tree

4 files changed

+705
-717
lines changed

4 files changed

+705
-717
lines changed

jsoniter-scala-macros/shared/src/main/scala-2/com/github/plokhotnyuk/jsoniter_scala/macros/JsonCodecMaker.scala

Lines changed: 30 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -750,8 +750,7 @@ object JsonCodecMaker {
750750
case TypeRef(SingleType(_, enumSymbol), _, _) => enumSymbol
751751
}
752752

753-
val isScala213: Boolean = util.Properties.versionNumberString.startsWith("2.13.")
754-
val rootTpe = weakTypeOf[A].dealias
753+
val isScala213 = util.Properties.versionNumberString.startsWith("2.13.")
755754

756755
def isImmutableArraySeq(tpe: Type): Boolean =
757756
isScala213 && tpe.typeSymbol.fullName == "scala.collection.immutable.ArraySeq"
@@ -762,45 +761,30 @@ object JsonCodecMaker {
762761
def isCollisionProofHashMap(tpe: Type): Boolean =
763762
isScala213 && tpe.typeSymbol.fullName == "scala.collection.mutable.CollisionProofHashMap"
764763

765-
def inferImplicitValue(typeTree: Tree): Tree = c.inferImplicitValue(c.typecheck(typeTree, c.TYPEmode).tpe)
766-
767-
def checkRecursionInTypes(types: List[Type]): Unit =
768-
if (!cfg.allowRecursiveTypes) {
769-
val tpe = types.head
770-
val nestedTypes = types.tail
771-
val recursiveIdx = nestedTypes.indexOf(tpe)
772-
if (recursiveIdx >= 0) {
773-
val recTypes = nestedTypes.take(recursiveIdx + 1).reverse.mkString("'", "', '", "'")
774-
fail(s"Recursive type(s) detected: $recTypes. Please consider using a custom implicitly " +
775-
s"accessible codec for this type to control the level of recursion or turn on the " +
776-
s"'${typeOf[CodecMakerConfig]}.allowRecursiveTypes' for the trusted input that " +
777-
"will not exceed the thread stack size.")
778-
}
779-
}
764+
def summon(typeTree: Tree): Tree = c.inferImplicitValue(c.typecheck(typeTree, c.TYPEmode).tpe)
780765

781-
val inferredKeyCodecs = mutable.Map.empty[Type, Tree]
782-
783-
def findImplicitKeyCodec(types: List[Type]): Tree = {
784-
checkRecursionInTypes(types)
766+
def checkRecursionInTypes(types: List[Type]): Unit = if (!cfg.allowRecursiveTypes) {
785767
val tpe = types.head
786-
if (tpe =:= rootTpe) EmptyTree
787-
else {
788-
inferredKeyCodecs.getOrElseUpdate(tpe,
789-
inferImplicitValue(tq"_root_.com.github.plokhotnyuk.jsoniter_scala.core.JsonKeyCodec[$tpe]"))
768+
val nestedTypes = types.tail
769+
val recursiveIdx = nestedTypes.indexOf(tpe)
770+
if (recursiveIdx >= 0) {
771+
val recTypes = nestedTypes.take(recursiveIdx + 1).reverse.mkString("'", "', '", "'")
772+
fail(s"Recursive type(s) detected: $recTypes. Please consider using a custom implicitly accessible codec for " +
773+
s"this type to control the level of recursion or turn on the '${typeOf[CodecMakerConfig]}.allowRecursiveTypes' " +
774+
"for the trusted input that will not exceed the thread stack size.")
790775
}
791776
}
792777

793-
val inferredValueCodecs = mutable.Map.empty[Type, Tree]
778+
val rootTpe = weakTypeOf[A].dealias
779+
val inferredKeyCodecs = mutable.Map[Type, Tree]((rootTpe, EmptyTree))
794780

795-
def findImplicitValueCodec(types: List[Type]): Tree = {
796-
checkRecursionInTypes(types)
797-
val tpe = types.head
798-
if (tpe =:= rootTpe) EmptyTree
799-
else {
800-
inferredValueCodecs.getOrElseUpdate(tpe,
801-
inferImplicitValue(tq"_root_.com.github.plokhotnyuk.jsoniter_scala.core.JsonValueCodec[$tpe]"))
802-
}
803-
}
781+
def findImplicitKeyCodec(tpe: Type): Tree =
782+
inferredKeyCodecs.getOrElseUpdate(tpe, summon(tq"com.github.plokhotnyuk.jsoniter_scala.core.JsonKeyCodec[$tpe]"))
783+
784+
val inferredValueCodecs = mutable.Map[Type, Tree]((rootTpe, EmptyTree))
785+
786+
def findImplicitValueCodec(tpe: Type): Tree =
787+
inferredValueCodecs.getOrElseUpdate(tpe, summon(tq"com.github.plokhotnyuk.jsoniter_scala.core.JsonValueCodec[$tpe]"))
804788

805789
val mathContexts = new mutable.LinkedHashMap[Int, (TermName, Tree)]
806790

@@ -990,8 +974,9 @@ object JsonCodecMaker {
990974
}
991975

992976
def genReadKey(types: List[Type]): Tree = {
977+
checkRecursionInTypes(types)
993978
val tpe = types.head
994-
val implKeyCodec = findImplicitKeyCodec(types)
979+
val implKeyCodec = findImplicitKeyCodec(tpe)
995980
if (implKeyCodec.nonEmpty) q"$implKeyCodec.decodeKey(in)"
996981
else if (tpe =:= typeOf[String]) q"in.readKeyAsString()"
997982
else if (tpe =:= definitions.BooleanTpe || tpe =:= typeOf[java.lang.Boolean]) q"in.readKeyAsBoolean()"
@@ -1181,8 +1166,9 @@ object JsonCodecMaker {
11811166

11821167
@tailrec
11831168
def genWriteKey(x: Tree, types: List[Type]): Tree = {
1169+
checkRecursionInTypes(types)
11841170
val tpe = types.head
1185-
val implKeyCodec = findImplicitKeyCodec(types)
1171+
val implKeyCodec = findImplicitKeyCodec(tpe)
11861172
if (implKeyCodec.nonEmpty) q"$implKeyCodec.encodeKey($x, out)"
11871173
else if (tpe =:= typeOf[String] || tpe =:= definitions.BooleanTpe || tpe =:= typeOf[java.lang.Boolean] ||
11881174
tpe =:= definitions.ByteTpe || tpe =:= typeOf[java.lang.Byte] || tpe =:= definitions.CharTpe ||
@@ -1420,8 +1406,9 @@ object JsonCodecMaker {
14201406
}
14211407

14221408
def genNullValue(types: List[Type]): Tree = {
1409+
checkRecursionInTypes(types)
14231410
val tpe = types.head
1424-
val implValueCodec = findImplicitValueCodec(types)
1411+
val implValueCodec = findImplicitValueCodec(tpe)
14251412
if (implValueCodec.nonEmpty) q"$implValueCodec.nullValue"
14261413
else if (tpe =:= typeOf[String]) q"null"
14271414
else if (tpe =:= definitions.BooleanTpe || tpe =:= typeOf[java.lang.Boolean]) q"false"
@@ -1622,10 +1609,11 @@ object JsonCodecMaker {
16221609
else q"x += ${genReadVal(types, genNullValue(types), isStringified, EmptyTree)}"
16231610

16241611
def genReadVal(types: List[Type], default: Tree, isStringified: Boolean, discriminator: Tree): Tree = {
1612+
checkRecursionInTypes(types)
16251613
val tpe = types.head
16261614
lazy val methodKey = MethodKey(tpe, isStringified && (isCollection(tpe) || isOption(tpe, types.tail)), discriminator)
16271615
lazy val decodeMethodName = decodeMethodNames.get(methodKey)
1628-
val implValueCodec = findImplicitValueCodec(types)
1616+
val implValueCodec = findImplicitValueCodec(tpe)
16291617
if (implValueCodec.nonEmpty) q"$implValueCodec.decodeValue(in, $default)"
16301618
else if (tpe =:= typeOf[String]) q"in.readString($default)"
16311619
else if (tpe =:= definitions.BooleanTpe || tpe =:= typeOf[java.lang.Boolean]) {
@@ -2118,10 +2106,11 @@ object JsonCodecMaker {
21182106
}
21192107

21202108
def genWriteVal(m: Tree, types: List[Type], isStringified: Boolean, discriminator: Tree): Tree = {
2109+
checkRecursionInTypes(types)
21212110
val tpe = types.head
21222111
lazy val methodKey = MethodKey(tpe, isStringified && (isCollection(tpe) || isOption(tpe, types.tail)), discriminator)
21232112
lazy val encodeMethodName = encodeMethodNames.get(methodKey)
2124-
val implValueCodec = findImplicitValueCodec(types)
2113+
val implValueCodec = findImplicitValueCodec(tpe)
21252114
if (implValueCodec.nonEmpty) q"$implValueCodec.encodeValue($m, out)"
21262115
else if (tpe =:= typeOf[String]) q"out.writeVal($m)"
21272116
else if (tpe =:= definitions.BooleanTpe || tpe =:= typeOf[java.lang.Boolean] || tpe =:= definitions.ByteTpe ||
@@ -2341,7 +2330,7 @@ object JsonCodecMaker {
23412330
x
23422331
}"""
23432332
if (c.settings.contains("print-codecs") ||
2344-
inferImplicitValue(tq"_root_.com.github.plokhotnyuk.jsoniter_scala.macros.CodecMakerConfig.PrintCodec") != EmptyTree) {
2333+
summon(tq"com.github.plokhotnyuk.jsoniter_scala.macros.CodecMakerConfig.PrintCodec") != EmptyTree) {
23452334
c.info(c.enclosingPosition, s"Generated JSON codec for type '$rootTpe':\n${showCode(codec)}", force = true)
23462335
}
23472336
c.Expr[JsonValueCodec[A]](codec)

0 commit comments

Comments
 (0)