All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pickling.Pickler.scala Maven / Gradle / Ivy

The newest version!
package scala.pickling

import scala.language.experimental.macros

import scala.annotation.implicitNotFound
import scala.reflect.runtime.{universe => ru}
import scala.reflect.runtime.universe._

import internal._

/** A static pickler for type `T`. Its `pickle` method takes an object-to-be-pickled of
 *  static type `T`, and pickles it to an instance of `PBuilder`. In the process the object
 *  is turned into some external representation like a byte array. The particular external
 *  representation (the "pickle format") is defined by the `builder`.
 *
 *  This pickler requires that the dynamic type of the object-to-be-pickled is equal to
 *  the erasure of its static type `T`.
 */
@implicitNotFound(msg = "Cannot generate a pickler for ${T}. Recompile with -Xlog-implicits for details")
trait SPickler[T] {
  def pickle(picklee: T, builder: PBuilder): Unit
}

/** A dynamic pickler for type `T`. Its `pickle` method takes an object-to-be-pickled of
 *  static type `T`, and pickles it to an instance of `PBuilder`. In the process the object
 *  is turned into some external representation like a byte array. The particular external
 *  representation (the "pickle format") is defined by the `builder`.
 *
 *  In contrast to static picklers (instances of type `SPickler[T]`), a dynamic pickler of
 *  type `DPickler[T]` pickles any object of type `T`.
 */
@implicitNotFound(msg = "Cannot generate a DPickler for ${T}. Recompile with -Xlog-implicits for details")
trait DPickler[T] {
  def pickle(picklee: T, builder: PBuilder): Unit
}

object DPickler {
  implicit def genDPickler[T](implicit format: PickleFormat): DPickler[T] = macro Compat.PicklerMacros_dpicklerImpl[T]
}

trait GenPicklers extends RuntimePicklersUnpicklers {

  implicit def genPickler[T]: SPickler[T] = macro Compat.PicklerMacros_impl[T]
  // TODO: the primitive pickler hack employed here is funny, but I think we should fix this one
  // since people probably would also have to deal with the necessity to abstract over pickle formats
  def genPickler(classLoader: ClassLoader, clazz: Class[_], tag: FastTypeTag[_])(implicit share: refs.Share): SPickler[_] = {
    // println(s"generating runtime pickler for $clazz") // NOTE: needs to be an explicit println, so that we don't occasionally fallback to runtime in static cases
    val className = if (clazz == null) "null" else clazz.getName
    GlobalRegistry.picklerMap.get(className) match {
      case None =>
        // debug(s"!!! could not find registered pickler for class $className, tag ${tag.key} !!!")
        val pickler: SPickler[_] = if (clazz.isArray) {
          val mirror = ru.runtimeMirror(classLoader)
          val elemClass = clazz.getComponentType()
          val elemTag = FastTypeTag.mkRaw(elemClass, mirror)
          val elemPickler = genPickler(classLoader, elemClass, elemTag)

          mkRuntimeTravPickler[Array[AnyRef]](elemClass, elemTag, tag, elemPickler, null)
        } else {
          val runtime = new RuntimePickler(classLoader, clazz)
          runtime.mkPickler
        }
        GlobalRegistry.picklerMap += (className -> (x => pickler))
        pickler

      case Some(existingPickler) =>
        existingPickler(tag)
    }
  }
}

// marker trait to indicate a generated pickler
// this is important for the dispatch between custom and generated picklers
trait Generated

object SPickler extends CorePicklersUnpicklers with RuntimePicklersUnpicklers

@implicitNotFound(msg = "Cannot generate an unpickler for ${T}. Recompile with -Xlog-implicits for details")
trait Unpickler[T] {
  def unpickle(tag: => FastTypeTag[_], reader: PReader): Any
}

trait GenUnpicklers extends RuntimePicklersUnpicklers {

  implicit def genUnpickler[T]: Unpickler[T] with Generated = macro Compat.UnpicklerMacros_impl[T]

  // Note: parameter `tag` may be `null`.
  def genUnpickler(mirror: Mirror, tag: FastTypeTag[_])(implicit share: refs.Share): Unpickler[_] = {
    // println(s"generating runtime unpickler for ${tag.key}") // NOTE: needs to be an explicit println, so that we don't occasionally fallback to runtime in static cases
    val className = tag.key
    GlobalRegistry.unpicklerMap.get(className) match {
      case None =>
        // debug(s"!!! could not find registered unpickler for class $className !!!")
        val unpickler = if (className.startsWith("scala.Array")) {
          // debug(s"runtime unpickling of an array: $className")
          val elemTypeString = className.substring(12, className.length - 1)
          // debug(s"creating tag for element type: $elemTypeString")
          val elemTag = FastTypeTag(mirror, elemTypeString)
          val elemClass = Classes.classFromString(elemTypeString)
          val elemUnpickler = Unpickler.genUnpickler(mirror, elemTag)

          mkRuntimeTravPickler[Array[AnyRef]](elemClass, elemTag, tag, null, elemUnpickler)
        } else {
          val runtime = if (share.isInstanceOf[refs.ShareNothing]) {
              // debug(s"@@@ creating ShareNothingInterpretedUnpicklerRuntime for type $className")
              new ShareNothingInterpretedUnpicklerRuntime(mirror, tag)
            } else {
              // debug(s"@@@ creating InterpretedUnpicklerRuntime for type $className")
              new InterpretedUnpicklerRuntime(mirror, tag)
            }
          runtime.genUnpickler
        }
        GlobalRegistry.unpicklerMap += (className -> unpickler)
        unpickler
      case Some(existingUnpickler) =>
        existingUnpickler
    }
  }
}

object Unpickler extends CorePicklersUnpicklers with RuntimePicklersUnpicklers




© 2015 - 2025 Weber Informatics LLC | Privacy Policy