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

tethys.readers.instances.MapReaders.scala Maven / Gradle / Ivy

There is a newer version: 0.29.0
Show newest version
package tethys.readers.instances

import tethys.JsonReader
import tethys.compat.CollectionBuilder
import tethys.readers.tokens.TokenIterator
import tethys.readers.{FieldName, KeyReader, ReaderError}

import scala.annotation.tailrec
import scala.collection.mutable
import scala.language.higherKinds

private[tethys] trait MapReaders extends LowPriorityMapReaders {
  implicit def byteMapReader[K, M[X, Y] <: scala.collection.Map[X, Y]](implicit
      keyReader: KeyReader[K],
      cb: CollectionBuilder[(K, Byte), M[K, Byte]]
  ): JsonReader[M[K, Byte]] = {
    new MapReader[K, Byte, M] {
      override protected def appendBuilder(
          it: TokenIterator,
          builder: mutable.Builder[(K, Byte), M[K, Byte]],
          key: K
      )(implicit fieldName: FieldName): Unit = {
        builder += key -> PrimitiveReaders.ByteJsonReader.read(it)
      }
    }
  }

  implicit def shortMapReader[K, M[X, Y] <: scala.collection.Map[X, Y]](implicit
      keyReader: KeyReader[K],
      cb: CollectionBuilder[(K, Short), M[K, Short]]
  ): JsonReader[M[K, Short]] = {
    new MapReader[K, Short, M] {
      override protected def appendBuilder(
          it: TokenIterator,
          builder: mutable.Builder[(K, Short), M[K, Short]],
          key: K
      )(implicit fieldName: FieldName): Unit = {
        builder += key -> PrimitiveReaders.ShortJsonReader.read(it)
      }
    }
  }

  implicit def intMapReader[K, M[X, Y] <: scala.collection.Map[X, Y]](implicit
      keyReader: KeyReader[K],
      cb: CollectionBuilder[(K, Int), M[K, Int]]
  ): JsonReader[M[K, Int]] = {
    new MapReader[K, Int, M] {
      override protected def appendBuilder(
          it: TokenIterator,
          builder: mutable.Builder[(K, Int), M[K, Int]],
          key: K
      )(implicit fieldName: FieldName): Unit = {
        builder += key -> PrimitiveReaders.IntJsonReader.read(it)
      }
    }
  }

  implicit def longMapReader[K, M[X, Y] <: scala.collection.Map[X, Y]](implicit
      keyReader: KeyReader[K],
      cb: CollectionBuilder[(K, Long), M[K, Long]]
  ): JsonReader[M[K, Long]] = {
    new MapReader[K, Long, M] {
      override protected def appendBuilder(
          it: TokenIterator,
          builder: mutable.Builder[(K, Long), M[K, Long]],
          key: K
      )(implicit fieldName: FieldName): Unit = {
        builder += key -> PrimitiveReaders.LongJsonReader.read(it)
      }
    }
  }

  implicit def floatMapReader[K, M[X, Y] <: scala.collection.Map[X, Y]](implicit
      keyReader: KeyReader[K],
      cb: CollectionBuilder[(K, Float), M[K, Float]]
  ): JsonReader[M[K, Float]] = {
    new MapReader[K, Float, M] {
      override protected def appendBuilder(
          it: TokenIterator,
          builder: mutable.Builder[(K, Float), M[K, Float]],
          key: K
      )(implicit fieldName: FieldName): Unit = {
        builder += key -> PrimitiveReaders.FloatJsonReader.read(it)
      }
    }
  }

  implicit def doubleMapReader[K, M[X, Y] <: scala.collection.Map[X, Y]](
      implicit
      keyReader: KeyReader[K],
      cb: CollectionBuilder[(K, Double), M[K, Double]]
  ): JsonReader[M[K, Double]] = {
    new MapReader[K, Double, M] {
      override protected def appendBuilder(
          it: TokenIterator,
          builder: mutable.Builder[(K, Double), M[K, Double]],
          key: K
      )(implicit fieldName: FieldName): Unit = {
        builder += key -> PrimitiveReaders.DoubleJsonReader.read(it)
      }
    }
  }

  implicit def booleanMapReader[K, M[X, Y] <: scala.collection.Map[X, Y]](
      implicit
      keyReader: KeyReader[K],
      cb: CollectionBuilder[(K, Boolean), M[K, Boolean]]
  ): JsonReader[M[K, Boolean]] = {
    new MapReader[K, Boolean, M] {
      override protected def appendBuilder(
          it: TokenIterator,
          builder: mutable.Builder[(K, Boolean), M[K, Boolean]],
          key: K
      )(implicit fieldName: FieldName): Unit = {
        builder += key -> PrimitiveReaders.BooleanJsonReader.read(it)
      }
    }
  }
}

private[tethys] trait LowPriorityMapReaders extends IterableReaders {

  implicit def mapReader[K, A, M[X, Y] <: scala.collection.Map[X, Y]](implicit
      keyReader: KeyReader[K],
      jsonReader: JsonReader[A],
      cb: CollectionBuilder[(K, A), M[K, A]]
  ): JsonReader[M[K, A]] = {
    new MapReader[K, A, M] {
      override protected def appendBuilder(
          it: TokenIterator,
          builder: mutable.Builder[(K, A), M[K, A]],
          key: K
      )(implicit fieldName: FieldName): Unit = {
        builder += key -> jsonReader.read(it)
      }
    }
  }

  protected abstract class MapReader[K, A, M[_, _]](implicit
      keyReader: KeyReader[K],
      cb: CollectionBuilder[(K, A), M[K, A]]
  ) extends JsonReader[M[K, A]] {

    protected def appendBuilder(
        it: TokenIterator,
        builder: mutable.Builder[(K, A), M[K, A]],
        key: K
    )(implicit fieldName: FieldName): Unit

    override def read(
        it: TokenIterator
    )(implicit fieldName: FieldName): M[K, A] = {
      if (it.currentToken().isObjectStart)
        recRead(it.next(), cb.newBuilder)(fieldName)
      else
        ReaderError.wrongJson(
          s"Expected object start but found: ${it.currentToken()}"
        )
    }

    @tailrec
    private def recRead(
        it: TokenIterator,
        builder: mutable.Builder[(K, A), M[K, A]]
    )(fieldName: FieldName): M[K, A] = {
      it.currentToken() match {
        case token if token.isObjectEnd =>
          it.nextToken()
          builder.result()
        case token if token.isFieldName =>
          val name = it.fieldName()
          val nextFieldName = fieldName.appendFieldName(name)
          appendBuilder(
            it.next(),
            builder,
            keyReader.read(name)(nextFieldName)
          )(nextFieldName)
          recRead(it, builder)(fieldName)

        case token =>
          ReaderError.wrongJson(
            s"Expect end of object or field name but '$token' found"
          )(fieldName)
      }
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy