Skip to content

Commit b83c805

Browse files
committed
Add support of type references + tests for recursive tuple types
1 parent 6d3f88b commit b83c805

File tree

2 files changed

+40
-2
lines changed

2 files changed

+40
-2
lines changed

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

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,16 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
931931
case trTpe: TypeRef if trTpe.isOpaqueAlias => opaqueDealias(trTpe.translucentSuperType.dealias)
932932
case _ => tpe
933933

934+
private def isTypeRef(tpe: TypeRepr): Boolean = tpe match
935+
case trTpe: TypeRef =>
936+
val typeSymbol = trTpe.typeSymbol
937+
typeSymbol.isTypeDef && typeSymbol.isAliasType
938+
case _ => false
939+
940+
private def typeRefDealias(tpe: TypeRepr): TypeRepr = tpe match
941+
case trTpe: TypeRef => trTpe.translucentSuperType.dealias
942+
case _ => tpe
943+
934944
private def isSealedClass(tpe: TypeRepr): Boolean = tpe.typeSymbol.flags.is(Flags.Sealed)
935945

936946
private def hasSealedParent(tpe: TypeRepr): Boolean =
@@ -1395,6 +1405,9 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
13951405
} else if (isOpaque(tpe)) {
13961406
val sTpe = opaqueDealias(tpe)
13971407
sTpe.asType match { case '[s] => '{ ${genReadKey[s](sTpe :: types.tail, in)}.asInstanceOf[T] } }
1408+
} else if (isTypeRef(tpe)) {
1409+
val sTpe = typeRefDealias(tpe)
1410+
sTpe.asType match { case '[s] => '{ ${genReadKey[s](sTpe :: types.tail, in)}.asInstanceOf[T] } }
13981411
} else cannotFindKeyCodecError(tpe)
13991412
}.asInstanceOf[Expr[T]]
14001413

@@ -1618,6 +1631,9 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
16181631
} else if (isOpaque(tpe)) {
16191632
val sTpe = opaqueDealias(tpe)
16201633
sTpe.asType match { case '[s] => genWriteKey('{ $x.asInstanceOf[s] }, sTpe :: types.tail, out) }
1634+
} else if (isTypeRef(tpe)) {
1635+
val sTpe = typeRefDealias(tpe)
1636+
sTpe.asType match { case '[s] => genWriteKey('{ $x.asInstanceOf[s] }, sTpe :: types.tail, out) }
16211637
} else cannotFindKeyCodecError(tpe)
16221638

16231639
private def genWriteConstantKey(name: String, out: Expr[JsonWriter])(using Quotes): Expr[Unit] =
@@ -1928,6 +1944,9 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
19281944
else if (isOpaque(tpe) && !isNamedTuple(tpe)) {
19291945
val sTpe = opaqueDealias(tpe)
19301946
sTpe.asType match { case '[st] => '{ ${genNullValue[st](sTpe :: types.tail)}.asInstanceOf[T] } }
1947+
} else if (isTypeRef(tpe)) {
1948+
val sTpe = typeRefDealias(tpe)
1949+
sTpe.asType match { case '[st] => '{ ${genNullValue[st](sTpe :: types.tail)}.asInstanceOf[T] } }
19311950
} else if (isConstType(tpe)) tpe match { case ConstantType(c) => Literal(c).asExpr }
19321951
else '{ null.asInstanceOf[T] }
19331952
}.asInstanceOf[Expr[T]]
@@ -2370,7 +2389,7 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
23702389
val types1 = tpe1 :: types
23712390
val newArrayOnChange = tpe1 match
23722391
case _: AppliedType => true
2373-
case _ => isValueClass(tpe1) || isOpaque(tpe1)
2392+
case _ => isValueClass(tpe1) || isOpaque(tpe1) || isTypeRef(tpe1)
23742393
tpe1.asType match
23752394
case '[t1] =>
23762395
def growArray(x: Expr[Array[t1]], i: Expr[Int], l: Expr[Int])(using Quotes): Expr[Array[t1]] =
@@ -2782,6 +2801,12 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
27822801
case '[s] =>
27832802
val newDefault = '{ $default.asInstanceOf[s] }.asInstanceOf[Expr[s]]
27842803
'{ ${genReadVal[s](sTpe :: types.tail, newDefault, isStringified, useDiscriminator, in)}.asInstanceOf[T] }
2804+
} else if (isTypeRef(tpe)) {
2805+
val sTpe = typeRefDealias(tpe)
2806+
sTpe.asType match
2807+
case '[s] =>
2808+
val newDefault = '{ $default.asInstanceOf[s] }.asInstanceOf[Expr[s]]
2809+
'{ ${genReadVal[s](sTpe :: types.tail, newDefault, isStringified, useDiscriminator, in)}.asInstanceOf[T] }
27852810
} else if (isConstType(tpe)) genReadConstType(tpe, isStringified, in)
27862811
else cannotFindValueCodecError(tpe)
27872812
}
@@ -3305,6 +3330,11 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
33053330
sTpe.asType match
33063331
case '[s] =>
33073332
genWriteVal[s]('{ $m.asInstanceOf[s] }, sTpe :: types.tail, isStringified, optWriteDiscriminator, out)
3333+
} else if (isTypeRef(tpe)) {
3334+
val sTpe = typeRefDealias(tpe)
3335+
sTpe.asType match
3336+
case '[s] =>
3337+
genWriteVal[s]('{ $m.asInstanceOf[s] }, sTpe :: types.tail, isStringified, optWriteDiscriminator, out)
33083338
} else cannotFindValueCodecError(tpe)
33093339
}
33103340
}.asInstanceOf[Expr[Unit]]

jsoniter-scala-next-tests/shared/src/test/scala-3/com/github/plokhotnyuk/jsoniter_scala/macros/JsonCodecMakerNamedTupleSpec.scala

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,18 @@ class JsonCodecMakerNamedTupleSpec extends VerifyingSpec {
7676
verifySerDeser(make[List[(i: Int, s: String)]], List((i = 1, s = "VVV"), (i = 2, s = "WWW")),
7777
"""[{"i":1,"s":"VVV"},{"i":2,"s":"WWW"}]""")
7878
}
79-
"serialize and deserialize generic and named tuples" in {
79+
"serialize and deserialize complex generic and named tuples" in {
8080
verifySerDeser(make[Tuple.++[(Byte, Short), (Int, Long)]], (1: Byte, 2: Short, 3, 4L), "[1,2,3,4]")
8181
verifySerDeser(make[Tuple.Reverse[(String, Int)]], (1, "VVV"), """[1,"VVV"]""")
8282
verifySerDeser(make[NamedTuple.DropNames[(i: Int, s: String)]], (1, "VVV"), """[1,"VVV"]""")
8383
}
84+
"serialize and deserialize recursive regular and named tuples" in {
85+
type RecursiveTuple = (Int, Option[RecursiveTuple])
86+
type RecursiveNamedTuple = (value: Int, next: Option[RecursiveNamedTuple])
87+
verifySerDeser(make[RecursiveTuple](CodecMakerConfig.withAllowRecursiveTypes(true)),
88+
(1, Some((2, None))), "[1,[2,null]]")
89+
verifySerDeser(make[RecursiveNamedTuple](CodecMakerConfig.withAllowRecursiveTypes(true)),
90+
(value = 1, next = Some((2, None))), """{"value":1,"next":{"value":2}}""")
91+
}
8492
}
8593
}

0 commit comments

Comments
 (0)