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

Commit

Permalink
Merge pull request #412 from jvican/generate-pickler-unpickler-together
Browse files Browse the repository at this point in the history
Force generation to create (un)picklers together
  • Loading branch information
jsuereth committed Apr 18, 2016
2 parents c66aaf5 + 48e1c4d commit c04a1ab
Show file tree
Hide file tree
Showing 15 changed files with 133 additions and 227 deletions.
7 changes: 4 additions & 3 deletions core/src/main/scala/scala/pickling/Pickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ trait Pickler[T] {
// Shim for Java code.
abstract class AbstractPickler[T] extends Pickler[T]
object Pickler {
def generate[T]: Pickler[T] = macro generator.Compat.genPickler_impl[T]
@deprecated("Use `PicklerUnpickler.generate` instead", "0.11")
def generate[T]: Pickler[T] = macro generator.Compat.genPicklerUnpickler_impl[T]
}

/** A dynamic pickler for type `T`. Its `pickle` method takes an object-to-be-pickled of
Expand Down Expand Up @@ -82,15 +83,15 @@ trait Unpickler[T] {
// Shim for Java code.
abstract class AbstractUnpickler[T] extends Unpickler[T]
object Unpickler {
def generate[T]: Unpickler[T] = macro generator.Compat.genUnpickler_impl[T]
@deprecated("Use `PicklerUnpickler.generate` instead", "0.11")
def generate[T]: Unpickler[T] = macro generator.Compat.genPicklerUnpickler_impl[T]
}
/* Shim for java code which wants to pickle/unpickle. */
abstract class AbstractPicklerUnpickler[T] extends Pickler[T] with Unpickler[T]
object PicklerUnpickler {
def apply[T](p: Pickler[T], u: Unpickler[T]): AbstractPicklerUnpickler[T] = new DelegatingPicklerUnpickler(p, u)
//def generate[T]: Pickler[T] with Unpickler[T] = macro Compat.PicklerUnpicklerMacros_impl[T]
def generate[T]: AbstractPicklerUnpickler[T] = macro generator.Compat.genPicklerUnpickler_impl[T]
def debugGenerate[T]: String = macro generator.Compat.genPicklerUnpickler_debug[T]
/** This is a private implementation of PicklerUnpickler that delegates pickle and unpickle to underlying. */
private class DelegatingPicklerUnpickler[T](p: Pickler[T], u: Unpickler[T]) extends AbstractPicklerUnpickler[T] {
// From Pickler
Expand Down
16 changes: 0 additions & 16 deletions core/src/main/scala/scala/pickling/generator/Compat.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,11 @@ import scala.reflect.macros.Context
import scala.reflect.runtime.{universe => ru}

private[pickling] object Compat {
def genPickler_impl[T: c.WeakTypeTag](c: Context): c.Expr[Pickler[T] with Generated] = {
val c0: c.type = c
val bundle = new { val c: c0.type = c0 } with PicklingMacros
c.Expr[Pickler[T] with Generated](bundle.genPickler[T])
}

def genPicklerUnpickler_impl[T: c.WeakTypeTag](c: Context): c.Expr[AbstractPicklerUnpickler[T] with Generated] = {
val c0: c.type = c
val bundle = new { val c: c0.type = c0 } with PicklingMacros
c.Expr[AbstractPicklerUnpickler[T] with Generated](bundle.genPicklerUnpickler[T])
}

def genUnpickler_impl[T: c.WeakTypeTag](c: Context): c.Expr[Unpickler[T] with Generated] = {
val c0: c.type = c
val bundle = new { val c: c0.type = c0 } with PicklingMacros
c.Expr[Unpickler[T] with Generated](bundle.genUnPickler[T])
}

def genPicklerUnpickler_debug[T: c.WeakTypeTag](c: Context): c.Expr[String] = {
val c0: c.type = c
val bundle = new { val c: c0.type = c0 } with PicklingMacros
c.Expr[String](bundle.debugPicklerUnpickler[T])
}
}
67 changes: 11 additions & 56 deletions core/src/main/scala/scala/pickling/generator/Macros.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,17 @@ package generator

private[pickling] object PicklingMacros {
import scala.language.experimental.macros
def genPickler[T]: Pickler[T] with Generated = macro scala.pickling.generator.Compat.genPickler_impl[T]
def genUnpickler[T]: Unpickler[T] with Generated = macro scala.pickling.generator.Compat.genUnpickler_impl[T]
def genPicklerUnpickler[T]: AbstractPicklerUnpickler[T] with Generated = macro scala.pickling.generator.Compat.genPicklerUnpickler_impl[T]

@deprecated("Use `genPicklerUnpickler` instead", "0.11")
def genPickler[T]: AbstractPicklerUnpickler[T] with Generated =
macro scala.pickling.generator.Compat.genPicklerUnpickler_impl[T]

@deprecated("Use `genPicklerUnpickler` instead", "0.11")
def genUnpickler[T]: AbstractPicklerUnpickler[T] with Generated =
macro scala.pickling.generator.Compat.genPicklerUnpickler_impl[T]

def genPicklerUnpickler[T]: AbstractPicklerUnpickler[T] with Generated =
macro scala.pickling.generator.Compat.genPicklerUnpickler_impl[T]
}
private[pickling] trait PicklingMacros extends Macro with SourceGenerator with TypeAnalysis {
import c.universe._
Expand Down Expand Up @@ -54,59 +62,6 @@ private[pickling] trait PicklingMacros extends Macro with SourceGenerator with T
}
}

def genPickler[T: c.WeakTypeTag]: c.Tree = preferringAlternativeImplicits {
val tpe = computeType[T]
checkClassType(tpe)
val sym = symbols.newClass(tpe)
val impl = PicklingAlgorithm.run(generator)(sym, logger)
val tree2 = impl map {
case PickleUnpickleImplementation(alg2, alg) => generatePicklerClass[T](alg2)
}
tree2 match {
case None =>
c.error(c.enclosingPosition, s"Failed to generate pickler for $tpe")
???
case Some(tree) =>
//System.err.println(s" --=== $tpe ===--\n$tree\n --=== / $tpe ===--")
tree
}
}
def genUnPickler[T: c.WeakTypeTag]: c.Tree = preferringAlternativeImplicits {
val tpe = computeType[T]
checkClassType(tpe)
val sym = symbols.newClass(tpe)
val impl = PicklingAlgorithm.run(generator)(sym, logger)
val tree2 = impl map {
case PickleUnpickleImplementation(alg2, alg) => generateUnpicklerClass[T](alg)
}
tree2 match {
case None =>
c.error(c.enclosingPosition, s"Failed to generate unpickler for $tpe")
???
case Some(tree) =>
//System.err.println(s" --=== $tpe ===--\n$tree\n --=== / $tpe ===--")
tree
}
}

def debugPicklerUnpickler[T: c.WeakTypeTag]: c.Tree = preferringAlternativeImplicits {
val tpe = computeType[T]
checkClassType(tpe)
val sym = symbols.newClass(tpe)
val impl = PicklingAlgorithm.run(generator)(sym, logger)
//System.err.println(impl)
val tree2 = impl map generatePicklerUnpicklerClass[T]
tree2 match {
case None =>
c.error(c.enclosingPosition, s"Failed to generate pickler/unpickler for $tpe")
???
case Some(tree) =>
//System.err.println(s" --=== $tpe ===--\n$tree\n --=== / $tpe ===--")
val treeString = s"$tree"
q"$treeString"
}
}

def genPicklerUnpickler[T: c.WeakTypeTag]: c.Tree = preferringAlternativeImplicits {
val tpe = computeType[T]
checkClassType(tpe)
Expand Down
65 changes: 0 additions & 65 deletions core/src/main/scala/scala/pickling/generator/sourcegen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -387,18 +387,6 @@ private[pickling] trait SourceGenerator extends Macro with tags.FastTypeTagMacr
val picklersRegistry = q"$picklingPath.internal.currentRuntime.picklers"
val generated = tq"$picklingPath.Generated"

def lazyInit(lookup: c.Tree, key: c.Tree, tpe: c.Tree,
notInitialized: c.TermName): c.Tree = {
q"""
if($picklersRegistry.isLookupEnabled) {
$lookup($key) match {
case Some(p) => p.asInstanceOf[$tpe]
case None => $notInitialized: $tpe
}
} else $notInitialized: $tpe
"""
}

def picklerUnpicklerLazyInit(lookup1: c.Tree, lookup2: c.Tree, key: c.Tree,
tpe: c.Tree, notInitialized: c.TermName) = {
q"""
Expand All @@ -411,59 +399,6 @@ private[pickling] trait SourceGenerator extends Macro with tags.FastTypeTagMacr
"""
}

/** generates the tree which will construct + return a new instance of a Pickler class, capable of
* pickling an instance of type T, using the behavior outlined by the PicklerAst.
*/
def generatePicklerClass[T: c.WeakTypeTag](picklerAst: PicklerAst): c.Tree = {

val tpe = computeType[T]
val picklerName = c.fresh(newTermName(syntheticBaseName(tpe) + "Pickler"))
val createTagTree = super[FastTypeTagMacros].impl[T]
val picklerType = tq"$picklingPath.Pickler[$tpe]"
val key = q"$createTagTree.key"
val lookup = q"$picklersRegistry.lookupExistingPickler"

q"""
_root_.scala.Predef.locally {
implicit object $picklerName extends $picklerType with $picklingPath.Generated
with $picklingPath.AutoRegisterPickler[$tpe]{

lazy val tag: $picklingPath.FastTypeTag[$tpe] = $createTagTree
def pickle(picklee: $tpe, builder: $picklingPath.PBuilder): _root_.scala.Unit = ${genPicklerLogic[T](picklerAst)}

}
${lazyInit(lookup, key, picklerType, picklerName)}
}
"""

}

def generateUnpicklerClass[T: c.WeakTypeTag](unpicklerAst: UnpicklerAst): c.Tree = {

val tpe = computeType[T]
val unpicklerName = c.fresh(newTermName(syntheticBaseName(tpe) + "Unpickler"))
val createTagTree = super[FastTypeTagMacros].impl[T]
val unpickleLogic = genUnpicklerLogic[T](unpicklerAst)
val unpicklerType = tq"$picklingPath.Unpickler[$tpe]"
val genUnpicklerType = tq"$unpicklerType with $generated"
val key = q"$createTagTree.key"
val lookup = q"$picklersRegistry.lookupExistingUnpickler"

q"""
_root_.scala.Predef.locally {
implicit object $unpicklerName extends $unpicklerType with $generated
with $picklingPath.AutoRegisterUnpickler[$tpe] {

lazy val tag: $picklingPath.FastTypeTag[$tpe] = $createTagTree
def unpickle(tagKey: _root_.java.lang.String, reader: $picklingPath.PReader): _root_.scala.Any = $unpickleLogic

}
${lazyInit(lookup, key, genUnpicklerType, unpicklerName)}
}
"""

}

def generatePicklerUnpicklerClass[T: c.WeakTypeTag](impl: PickleUnpickleImplementation): c.Tree = {

val tpe = computeType[T]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package scala.pickling
package internal

import scala.pickling.pickler.AnyUnpickler
import scala.pickling.pickler.AnyPicklerUnpickler
import scala.pickling.runtime.{Tuple2RTKnownTagUnpickler, Tuple2RTPickler}
import scala.pickling.spi.PicklerRegistry

Expand Down Expand Up @@ -59,9 +59,9 @@ trait RuntimePicklerRegistryHelper extends PicklerRegistry {
def tupleUnpicklerGenerator: FastTypeTag[_] => Unpickler[(Any,Any)] = {
case FastTypeTag(_, List(left, right)) =>
val lhs =
currentRuntime.picklers.lookupUnpickler(left.toString).getOrElse(AnyUnpickler).asInstanceOf[Unpickler[Any]]
currentRuntime.picklers.lookupUnpickler(left.toString).getOrElse(AnyPicklerUnpickler).asInstanceOf[Unpickler[Any]]
val rhs =
currentRuntime.picklers.lookupUnpickler(right.toString).getOrElse(AnyUnpickler).asInstanceOf[Unpickler[Any]]
currentRuntime.picklers.lookupUnpickler(right.toString).getOrElse(AnyPicklerUnpickler).asInstanceOf[Unpickler[Any]]
new Tuple2RTKnownTagUnpickler(lhs, rhs)
case tpe => new Tuple2RTPickler()
}
Expand Down
48 changes: 31 additions & 17 deletions core/src/main/scala/scala/pickling/pickler/Any.scala
Original file line number Diff line number Diff line change
@@ -1,34 +1,48 @@
package scala.pickling
package pickler

/** An pickler for "Any" value (will look up pickler at runtime, or generate it. */
object AnyPickler extends Pickler[Any] with AutoRegisterPickler[Any] {
import scala.pickling.internal.GRL
import scala.pickling.internal.currentRuntime
import scala.reflect.runtime.currentMirror

/** Generate a [[Pickler]] and [[Unpickler]] for [[Any]].
*
* It will look up pickler/unpickler at runtime, or generate it.
*/
object AnyPicklerUnpickler extends AbstractPicklerUnpickler[Any]
with AutoRegister[Any] {

override def tag: FastTypeTag[Any] = FastTypeTag.Any

/** Pickle [[Any]] by getting its class at runtime and looking
* up the correct [[Pickler]] for that class if available or
* generate it.
*
* Don't use [[AnyPicklerUnpickler]] for pickling classes with generic
* types. Otherwise, it will fail because of the type erasure
* and the lookup will replace the unknown type by [[Any]].
*/
override def pickle(picklee: Any, builder: PBuilder): Unit = {
// Here we just look up the pickler.
val clazz = picklee.getClass
val classLoader = this.getClass.getClassLoader
internal.GRL.lock()
GRL.lock()
val tag = try FastTypeTag.makeRaw(clazz)
finally internal.GRL.unlock()
val p = internal.currentRuntime.picklers.genPickler(classLoader, clazz, tag)
finally GRL.unlock()
val p = currentRuntime.picklers.genPickler(classLoader, clazz, tag)
p.asInstanceOf[Pickler[Any]].pickle(picklee, builder)
}
override def toString = "AnyPickler"
}
/** An unpickler for "Any" value (will look up unpickler at runtime, or generate it. */
object AnyUnpickler extends Unpickler[Any] with AutoRegisterUnpickler[Any] {
def tag: FastTypeTag[Any] = FastTypeTag.Any

/** Unpickle something as [[Any]] by looking up registered
* unpicklers for [[tag]] or using runtime unpickler generation.
*/
def unpickle(tag: String, reader: PReader): Any = {
val actualUnpickler = internal.currentRuntime.picklers.genUnpickler(scala.reflect.runtime.currentMirror, tag)
val actualUnpickler = currentRuntime.picklers.genUnpickler(currentMirror, tag)
actualUnpickler.unpickle(tag, reader)
}
override def toString = "AnyUnPickler"

override def toString = "AnyPicklerUnpickler"
}

/** Attempts to unpickle Any by looking up registered unpicklers using `currentMirror`.
*/
trait AnyUnpicklers {
// Any
implicit val anyUnpickler: Unpickler[Any] = AnyUnpickler
implicit val anyPicklerUnpickler: AbstractPicklerUnpickler[Any] = AnyPicklerUnpickler
}
Loading

0 comments on commit c04a1ab

Please sign in to comment.