Skip to content
This repository was archived by the owner on Feb 20, 2019. It is now read-only.

Commit 809db6a

Browse files
committed
Add extendible way to pickle specialized classes
* Reuse code in `RuntimePicklerRegistry` and `sourcegen`. * Create `ClassMapper` to delegate the tasks of checking class equality.
1 parent 00a198d commit 809db6a

File tree

3 files changed

+51
-37
lines changed

3 files changed

+51
-37
lines changed

core/src/main/scala/scala/pickling/generator/sourcegen.scala

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,21 @@ private[pickling] trait SourceGenerator extends Macro with tags.FastTypeTagMacro
7070
}
7171
}
7272

73+
val classMapper = q"$picklingPath.util.ClassMapper"
7374
val unrecognizedClass = q"$errorsPath.UnrecognizedClass"
7475

7576
def genSubclassDispatch(x: SubclassDispatch): c.Tree = {
7677
val tpe = x.parent.tpe[c.universe.type](c.universe)
77-
val clazzName = newTermName("clazz")
78-
val compileTimeDispatch: List[CaseDef] = (x.subClasses map { subtpe =>
79-
val tpe = subtpe.tpe[c.universe.type](c.universe)
80-
CaseDef(Bind(clazzName, Ident(nme.WILDCARD)), q"clazz == classOf[$tpe]", createPickler(tpe, q"builder"))
81-
})(collection.breakOut)
78+
val clazz = newTermName("clazz")
79+
val compileTimeDispatch: List[CaseDef] =
80+
(x.subClasses map { subtpe =>
81+
val tpe = subtpe.tpe[c.universe.type](c.universe)
82+
CaseDef(
83+
Bind(clazz, Ident(nme.WILDCARD)),
84+
q"_root_.scala.pickling.util.ClassMapper.areSameClasses($clazz, classOf[$tpe])",
85+
createPickler(tpe, q"builder")
86+
)
87+
})(collection.breakOut)
8288

8389
val failDispatch = {
8490
val dispatcheeNames = x.subClasses.map(_.className).mkString(", ")
@@ -111,7 +117,8 @@ private[pickling] trait SourceGenerator extends Macro with tags.FastTypeTagMacro
111117
case Some(b) =>
112118
val parentTpe = x.parent.tpe[c.universe.type](c.universe)
113119
val impl = generatePickleImplFromAst(b)
114-
q"""if(classOf[$parentTpe] == picklee.getClass) $impl else $subclasses"""
120+
val checkIfParent = q"$classMapper.areSameClasses(picklee.getClass, classOf[$parentTpe])"
121+
q"""if($checkIfParent) $impl else $subclasses"""
115122
}
116123
}
117124
def genPickleEntry(op: PickleEntry): c.Tree = {

core/src/main/scala/scala/pickling/internal/RuntimePicklerRegistry.scala

Lines changed: 5 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package internal
33

44
import scala.pickling.runtime.CustomRuntime
55
import scala.pickling.spi.PicklerRegistry
6+
import scala.pickling.util.ClassMapper
67

78
/** Helper class to register picklers and unpicklers that
89
* handle special/crazy classes for runtime generation.
@@ -19,37 +20,10 @@ trait RuntimePicklerRegistry extends CustomRuntime {
1920
* this list because this is meant to be used
2021
* internally. If a user wants to do the same,
2122
* she just needs to use the [[PicklerRegistry]]. */
22-
val picklersToRegister = List(
23-
("scala.Tuple2", tupleGenerators),
24-
("scala.Tuple2$mcII$sp", tupleGenerators),
25-
("scala.Tuple2$mcIJ$sp", tupleGenerators),
26-
("scala.Tuple2$mcID$sp", tupleGenerators),
27-
("scala.Tuple2$mcIZ$sp", tupleGenerators),
28-
29-
("scala.Tuple2$mcJI$sp", tupleGenerators),
30-
("scala.Tuple2$mcJJ$sp", tupleGenerators),
31-
("scala.Tuple2$mcJD$sp", tupleGenerators),
32-
("scala.Tuple2$mcJC$sp", tupleGenerators),
33-
("scala.Tuple2$mcJZ$sp", tupleGenerators),
34-
35-
("scala.Tuple2$mcDI$sp", tupleGenerators),
36-
("scala.Tuple2$mcDJ$sp", tupleGenerators),
37-
("scala.Tuple2$mcDD$sp", tupleGenerators),
38-
("scala.Tuple2$mcDC$sp", tupleGenerators),
39-
("scala.Tuple2$mcDZ$sp", tupleGenerators),
40-
41-
("scala.Tuple2$mcCI$sp", tupleGenerators),
42-
("scala.Tuple2$mcCJ$sp", tupleGenerators),
43-
("scala.Tuple2$mcCD$sp", tupleGenerators),
44-
("scala.Tuple2$mcCC$sp", tupleGenerators),
45-
("scala.Tuple2$mcCZ$sp", tupleGenerators),
46-
47-
("scala.Tuple2$mcZI$sp", tupleGenerators),
48-
("scala.Tuple2$mcZJ$sp", tupleGenerators),
49-
("scala.Tuple2$mcZD$sp", tupleGenerators),
50-
("scala.Tuple2$mcZC$sp", tupleGenerators),
51-
("scala.Tuple2$mcZZ$sp", tupleGenerators)
52-
)
23+
val picklersToRegister =
24+
List("scala.Tuple2" -> tupleGenerators) ++
25+
ClassMapper.specializedTupleNamesFor("scala.Tuple2")
26+
.map(_ -> tupleGenerators)
5327

5428
final def registerRuntimePicklersAtInit(): Unit = {
5529
for((key, (pickler, unpickler)) <- picklersToRegister) {
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package scala.pickling.util
2+
3+
object ClassMapper {
4+
5+
val specializedTuplesTemplate =
6+
List(
7+
"$mcII$sp", "$mcIJ$sp", "$mcID$sp", "$mcIZ$sp", "$mcJI$sp", "$mcJJ$sp",
8+
"$mcJD$sp", "$mcJC$sp", "$mcJZ$sp", "$mcDI$sp", "$mcDJ$sp", "$mcDD$sp",
9+
"$mcDC$sp", "$mcDZ$sp", "$mcCI$sp", "$mcCJ$sp", "$mcCD$sp", "$mcCC$sp",
10+
"$mcCZ$sp", "$mcZI$sp", "$mcZJ$sp", "$mcZD$sp", "$mcZC$sp", "$mcZZ$sp"
11+
)
12+
13+
/* Map specialized classes to classes. Canonical use case: tuples.
14+
* We map classes instead of strings to check at runtime that they exist. */
15+
val specialMappingClasses: Map[Class[_], Class[_]] =
16+
mapSpecializedTuplesFor("scala.Tuple2") // add also other special cases
17+
18+
def specializedTupleNamesFor(tupleClassName: String): List[String] =
19+
specializedTuplesTemplate.map(tupleClassName + _)
20+
21+
def mapSpecializedTuplesFor(tupleClassName: String): Map[Class[_], Class[_]] = {
22+
val tupleClass = Class.forName(tupleClassName)
23+
specializedTupleNamesFor(tupleClassName)
24+
.map(Class.forName).map(_ -> tupleClass).toMap
25+
}
26+
27+
@inline def isSpecializedClass(specialized: Class[_], clazz: Class[_]) =
28+
specialMappingClasses.get(specialized).exists(_ == clazz)
29+
30+
def areSameClasses(clazz: Class[_], clazzT: Class[_]): Boolean =
31+
clazz == clazzT || isSpecializedClass(clazz, clazzT)
32+
33+
}

0 commit comments

Comments
 (0)