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

scala.pickling.internal.DefaultPicklerRegistry.scala Maven / Gradle / Ivy

The newest version!
package scala.pickling
package internal

import scala.collection.concurrent.TrieMap
import scala.collection.mutable
import scala.reflect.runtime.universe.Mirror
import scala.pickling.spi.{PicklerRegistry, RuntimePicklerGenerator}



/** Default pickle registry just uses TrieMaps and delgates behavior to a runtime pickler generator. */
final class DefaultPicklerRegistry(generator: RuntimePicklerGenerator) extends PicklerRegistry with RuntimePicklerRegistryHelper {
  type PicklerGenerator = AppliedType => Pickler[_]
  type UnpicklerGenerator = AppliedType => Unpickler[_]
  // TODO - We need to move the special encoding for runtime classes into here, rather than in magical traits.

  private val picklerMap: mutable.Map[String, Pickler[_]] = new TrieMap[String, Pickler[_]]
  private val picklerGenMap: mutable.Map[String, PicklerGenerator] = new TrieMap[String, PicklerGenerator]
  private val unpicklerMap: mutable.Map[String, Unpickler[_]] = new TrieMap[String, Unpickler[_]]
  private val unpicklerGenMap: mutable.Map[String, UnpicklerGenerator] = new TrieMap[String, UnpicklerGenerator]

  // During constrcution, we can now register the default picklers against our cache of picklers.
  autoRegisterDefaults()

  override def genUnpickler(mirror: Mirror, tagKey: String)(implicit share: refs.Share): Unpickler[_] = {
    lookupUnpickler(tagKey) match {
      case Some(p) => p
      case None =>
        // TODO - This should probably just be taking the `tagKey` and no mirror or share, the mirror/share
        //        should be configured by the default runtime.
        val p = generator.genUnpickler(mirror, tagKey)
        registerUnpickler(tagKey, p)
        p
    }
  }
  def genPickler(classLoader: ClassLoader, clazz: Class[_], tag: FastTypeTag[_])(implicit share: refs.Share): Pickler[_] = {
    lookupPickler(tag.key) match {
      case Some(p) => p
      case None =>
        // TODO - genPickler should probably just be using the tag and `currentMirror` of internal.
        val p = generator.genPickler(classLoader, clazz, tag)
        registerPickler(tag.key, p)
        p
    }
  }

  /** Registers a pickler with this registry for future use. */
  override def registerPickler[T](key: String, p: Pickler[T]): Unit =
    picklerMap.put(key, p)

  /** Registers an unpickler with this registry for future use. */
  override def registerUnpickler[T](key: String, p: Unpickler[T]): Unit =
    unpicklerMap.put(key, p)

  /** Checks the existince of an unpickler. */
  override def lookupUnpickler(key: String): Option[Unpickler[_]] = {
    unpicklerMap.get(key) match {
      case x: Some[Unpickler[_]] => x
      case None =>
        // Now we use the typeConstructor registry
        AppliedType.parseFull(key) match {
          case Some(a) =>
            unpicklerGenMap.get(a.typename) match {
              case Some(gen) =>
                // Genereate the pickler, register it with ourselves for future lookup, and return it.
                val up = gen(a)
                registerUnpickler(key, up)
                Some(up)
              case None => None
            }
          case None => None // This key is not an applied type.
        }
    }
  }

  /** Looks for a pickler with the given FastTypeTag string. */
  override def lookupPickler(key: String): Option[Pickler[_]] = {
    picklerMap.get(key) match {
      case x: Some[Pickler[_]] => x
      case None =>
        // TODO - fix AppliedType for a `parseAll` string or some such.
        AppliedType.parseFull(key) match {
          case Some(a) =>
            picklerGenMap.get(a.typename) match {
              case Some(gen) =>
                // Genereate the pickler, register it with ourselves for future lookup, and return it.
                val up = gen(a)
                registerPickler(key, up)
                Some(up)
              case None => None
            }
          case None => None // This key is not an applied type.
        }
    }

  }

  /** Registers a function which can generate picklers for a given type constructor.
    *
    * @param typeConstructorKey  The type constructor.  e.g. "scala.List" for something that can make scala.List[A] picklers.
    * @param generator  A function which takes an applied type string (your type + arguments) and returns a pickler for
    *                   this type.
    */
  override def registerUnpicklerGenerator[T](typeConstructorKey: String, generator: (AppliedType) => Unpickler[T]): Unit =
    unpicklerGenMap.put(typeConstructorKey, generator)


  /** Registers a function which can generate picklers for a given type constructor.
    *
    * @param typeConstructorKey  The type constructor.  e.g. "scala.List" for something that can make scala.List[A] picklers.
    * @param generator  A function which takes an applied type string (your type + arguments) and returns a pickler for
    *                   this type.
    */
  override def registerPicklerGenerator[T](typeConstructorKey: String, generator: (AppliedType) => Pickler[T]): Unit =
    picklerGenMap.put(typeConstructorKey, generator)

  /** Registers a pickler and unpickler for a type with this registry for future use.
    * @param key  The type key for the pickler. Note: In reflective scenarios this may not include type parameters.
    *             In those situations, the pickler should be able to handle arbitrary (existential) type parameters.
    * @param p  The unpickler to register.
    */
  override def registerPicklerUnpickler[T](key: String, p: (Pickler[T] with Unpickler[T])): Unit = {
    registerPickler(key, p)
    registerUnpickler(key, p)
  }

  /** Registers a function which can generate picklers for a given type constructor.
    *
    * @param typeConstructorKey  The type constructor.  e.g. "scala.List" for something that can make scala.List[A] picklers.
    * @param generator  A function which takes an applied type string (your type + arguments) and returns a pickler for
    *                   this type.
    */
  override def registerPicklerUnpicklerGenerator[T](typeConstructorKey: String, generator: (AppliedType) => (Pickler[T] with Unpickler[T])): Unit = {
    registerPicklerGenerator(typeConstructorKey, generator)
    registerUnpicklerGenerator(typeConstructorKey, generator)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy