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

msgpack4z.MsgpackUnion.scala Maven / Gradle / Ivy

package msgpack4z

import java.math.BigInteger
import msgpack4z.MsgpackUnion.constNone
import scalaz.{IMap, Order}

sealed abstract class MsgpackUnion extends Product with Serializable {
  final def string: Opt[String] =
    this match {
      case MsgpackString(value) => new Opt(value)
      case _ => Opt.empty[String]
    }

  final def binary: Opt[Array[Byte]] =
    this match {
      case MsgpackBinary(value) => new Opt(value)
      case _ => Opt.empty
    }

  final def long: Option[Long] =
    this match {
      case MsgpackLong(value) => Some(value)
      case _ => None
    }

  final def ulong: Opt[BigInteger] =
    this match {
      case MsgpackULong(value) => new Opt(value)
      case _ => Opt.empty
    }

  final def double: Option[Double] =
    this match {
      case MsgpackDouble(value) => Some(value)
      case _ => None
    }

  final def array: Opt[List[MsgpackUnion]] =
    this match {
      case MsgpackArray(value) => new Opt(value)
      case _ => Opt.empty
    }

  final def vector: Opt[Vector[MsgpackUnion]] =
    this match {
      case MsgpackArray(value) => new Opt(value.toVector)
      case _ => Opt.empty
    }

  final def map: Opt[Map[MsgpackUnion, MsgpackUnion]] =
    this match {
      case MsgpackMap(value) => new Opt(value)
      case _ => Opt.empty
    }

  final def ext: Opt[(Byte, Array[Byte])] =
    this match {
      case MsgpackExt(tpe, data) => new Opt((tpe, data))
      case _ => Opt.empty
    }

  final def imap: Opt[IMap[MsgpackUnion, MsgpackUnion]] =
    this match {
      case MsgpackMap(value) =>
        val i = value.iterator
        @annotation.tailrec
        def loop(acc: IMap[MsgpackUnion, MsgpackUnion]): IMap[MsgpackUnion, MsgpackUnion] = {
          if (i.hasNext) {
            loop(acc + i.next())
          } else {
            acc
          }
        }
        new Opt(loop(IMap.empty))
      case _ =>
        Opt.empty
    }

  final def bool: Option[Boolean] =
    this match {
      case MsgpackTrue => Some(true)
      case MsgpackFalse => Some(false)
      case _ => None
    }

  final def isNil: Boolean =
    this.isInstanceOf[MsgpackNil.type]

  final def isTrue: Boolean =
    this eq MsgpackTrue

  final def isFalse: Boolean =
    this eq MsgpackFalse

  final def isNaN: Boolean =
    this match {
      case MsgpackDouble(value) =>
        java.lang.Double.isNaN(value)
      case _ =>
        false
    }

  final def fold[A](
    string: String => A,
    binary: Array[Byte] => A,
    long: Long => A,
    ulong: BigInteger => A,
    double: Double => A,
    array: List[MsgpackUnion] => A,
    map: Map[MsgpackUnion, MsgpackUnion] => A,
    bool: Boolean => A,
    ext: (Byte, Array[Byte]) => A,
    nil: => A
  ): A =
    this match {
      case MsgpackLong(value) =>
        long(value)
      case MsgpackString(value) =>
        string(value)
      case MsgpackTrue =>
        bool(true)
      case MsgpackFalse =>
        bool(false)
      case MsgpackNil =>
        nil
      case MsgpackArray(value) =>
        array(value)
      case MsgpackMap(value) =>
        map(value)
      case MsgpackBinary(value) =>
        binary(value)
      case MsgpackULong(value) =>
        ulong(value)
      case MsgpackDouble(value) =>
        double(value)
      case MsgpackExt(tpe, value) =>
        ext(tpe, value)
    }

  final def foldOpt[A](
    string: String => Option[A] = constNone,
    binary: Array[Byte] => Option[A] = constNone,
    long: Long => Option[A] = constNone,
    ulong: BigInteger => Option[A] = constNone,
    double: Double => Option[A] = constNone,
    array: List[MsgpackUnion] => Option[A] = constNone,
    map: Map[MsgpackUnion, MsgpackUnion] => Option[A] = constNone,
    bool: Boolean => Option[A] = constNone,
    ext: (Byte, Array[Byte]) => Option[A] = (_: Byte, _: Array[Byte]) => None,
    nil: Option[A] = None
  ): Option[A] =
    fold[Option[A]](
      string,
      binary,
      long,
      ulong,
      double,
      array,
      map,
      bool,
      ext,
      nil
    )

  protected[msgpack4z] def pack(packer: MsgPacker): Unit

  final def ===(that: MsgpackUnion): Boolean =
    this.equals(that)

  final def as[A](factory: PackerUnpackerFactory)(implicit A: MsgpackCodec[A]): UnpackResult[A] = {
    val p = factory.packer
    pack(p)
    A.unpack(factory.unpacker(p.result()))
  }
}

object MsgpackUnion {
  private[this] val returnConstNone = (_: Any) => None
  private def constNone[A, B]: A => Option[B] = returnConstNone.asInstanceOf[A => Option[B]]

  private[this] val LongMax = BigInteger.valueOf(Long.MaxValue)
  private[this] val LongMin = BigInteger.valueOf(Long.MinValue)

  implicit val msgpackUnionInstance: Order[MsgpackUnion] =
    MsgpackUnionOrder

  val unpackF: MsgUnpacker => MsgpackUnion = unpack

  implicit val codecInstance: MsgpackCodec[MsgpackUnion] =
    MsgpackCodec.codecTry[MsgpackUnion](
      (packer, value) => value.pack(packer),
      unpacker => unpack(unpacker)
    )

  def unpack(unpacker: MsgUnpacker): MsgpackUnion = {
    unpacker.nextType() match {
      case MsgType.NIL =>
        unpacker.unpackNil()
        MsgpackNil
      case MsgType.BOOLEAN =>
        if (unpacker.unpackBoolean())
          MsgpackTrue
        else
          MsgpackFalse
      case MsgType.INTEGER =>
        val i = unpacker.unpackBigInteger()
        if (LongMin.compareTo(i) <= 0 && i.compareTo(LongMax) <= 0) {
          MsgpackLong(i.longValue())
        } else {
          MsgpackULong(i)
        }
      case MsgType.FLOAT =>
        MsgpackDouble(unpacker.unpackDouble())
      case MsgType.STRING =>
        MsgpackString(unpacker.unpackString())
      case MsgType.ARRAY =>
        val size = unpacker.unpackArrayHeader()
        val array = new Array[MsgpackUnion](size)
        var i = 0
        while (i < size) {
          array(i) = unpack(unpacker)
          i += 1
        }
        unpacker.arrayEnd()
        var list: List[MsgpackUnion] = Nil
        i -= 1
        while (i >= 0) {
          list = new ::(array(i), list)
          i -= 1
        }
        MsgpackArray(list)
      case MsgType.MAP =>
        val size = unpacker.unpackMapHeader()
        val builder = Map.newBuilder[MsgpackUnion, MsgpackUnion]
        builder.sizeHint(size)
        var i = 0
        while (i < size) {
          val key = unpack(unpacker)
          val value = unpack(unpacker)
          builder += (key -> value)
          i += 1
        }
        unpacker.mapEnd()
        MsgpackMap(builder.result())
      case MsgType.BINARY =>
        new MsgpackBinary(unpacker.unpackBinary())
      case MsgType.EXTENSION =>
        val header = unpacker.unpackExtTypeHeader()
        new MsgpackExt(header.getType, unpacker.readPayload(header.getLength))
    }
  }

  val string: Extractor[String] = new Extractor[String] {
    override def unapply(value: MsgpackUnion) =
      value.string
    override def apply(value: String): MsgpackUnion =
      new MsgpackString(value)
  }
  val binary: Extractor[Array[Byte]] = new Extractor[Array[Byte]] {
    override def unapply(value: MsgpackUnion) =
      value.binary
    override def apply(value: Array[Byte]): MsgpackUnion =
      new MsgpackBinary(value)
  }
  val byte: Byte => MsgpackUnion = i => MsgpackLong(i)
  val short: Short => MsgpackUnion = i => MsgpackLong(i)
  val int: Int => MsgpackUnion = i => MsgpackLong(i)
  val long: Long => MsgpackUnion = MsgpackLong
  val ulong: Extractor[BigInteger] = new Extractor[BigInteger] {
    override def unapply(value: MsgpackUnion) =
      value.ulong
    override def apply(value: BigInteger): MsgpackUnion =
      new MsgpackULong(value)
  }
  val float: Float => MsgpackUnion = i => MsgpackDouble(i)
  val double: Double => MsgpackUnion = MsgpackDouble
  val array: Extractor[List[MsgpackUnion]] = new Extractor[List[MsgpackUnion]] {
    override def unapply(value: MsgpackUnion) =
      value.array
    override def apply(value: List[MsgpackUnion]): MsgpackUnion =
      new MsgpackArray(value)
  }
  val vector: Extractor[Vector[MsgpackUnion]] = new Extractor[Vector[MsgpackUnion]] {
    override def unapply(value: MsgpackUnion) =
      value.vector
    override def apply(value: Vector[MsgpackUnion]): MsgpackUnion =
      new MsgpackArray(value.toList)
  }
  val map: Extractor[Map[MsgpackUnion, MsgpackUnion]] = new Extractor[Map[MsgpackUnion, MsgpackUnion]] {
    override def unapply(value: MsgpackUnion) =
      value.map
    override def apply(value: Map[MsgpackUnion, MsgpackUnion]): MsgpackUnion =
      new MsgpackMap(value)
  }
  val imap: Extractor[IMap[MsgpackUnion, MsgpackUnion]] = new Extractor[IMap[MsgpackUnion, MsgpackUnion]] {
    override def unapply(value: MsgpackUnion) =
      value.imap
    override def apply(value: IMap[MsgpackUnion, MsgpackUnion]): MsgpackUnion = {
      val builder = Map.newBuilder[MsgpackUnion, MsgpackUnion]
      value.foldlWithKey(())((_, k, v) => builder += ((k, v)))
      new MsgpackMap(builder.result())
    }
  }
  def extension(tpe: Byte, data: Array[Byte]): MsgpackUnion =
    new MsgpackExt(tpe, data)
  val ext: Extractor[(Byte, Array[Byte])] = new Extractor[(Byte, Array[Byte])] {
    override def unapply(value: MsgpackUnion) =
      value.ext
    override def apply(t: (Byte, Array[Byte])): MsgpackUnion =
      new MsgpackExt(t._1, t._2)
  }
  val bool: Boolean => MsgpackUnion = { value =>
    if (value) MsgpackTrue
    else MsgpackFalse
  }
  val True: MsgpackUnion = MsgpackTrue
  val False: MsgpackUnion = MsgpackFalse
  val nil: MsgpackUnion = MsgpackNil
}

sealed abstract class Extractor[A <: AnyRef] extends (A => MsgpackUnion) {
  def unapply(value: MsgpackUnion): Opt[A]
}

final case class MsgpackString(value: String) extends MsgpackUnion {
  override protected[msgpack4z] def pack(packer: MsgPacker): Unit =
    packer.packString(value)
}

object MsgpackString extends (String => MsgpackUnion)

final case class MsgpackBinary(value: Array[Byte]) extends MsgpackUnion {
  override protected[msgpack4z] def pack(packer: MsgPacker): Unit =
    packer.packBinary(value)
  override def equals(other: Any): Boolean = {
    other match {
      case that: AnyRef if this eq that => true
      case MsgpackBinary(that) =>
        java.util.Arrays.equals(value, that)
      case _ =>
        false
    }
  }
  override def hashCode = java.util.Arrays.hashCode(value)
}

object MsgpackBinary extends (Array[Byte] => MsgpackUnion)

final case class MsgpackLong(value: Long) extends MsgpackUnion {
  override protected[msgpack4z] def pack(packer: MsgPacker): Unit =
    packer.packLong(value)

  override def equals(other: Any): Boolean =
    other match {
      case that: AnyRef if this eq that =>
        true
      case that: MsgpackLong =>
        value == that.value
      case that: MsgpackULong =>
        that.value == bigInteger
      case _ =>
        false
    }

  override def hashCode = BigInteger.valueOf(value).hashCode

  private[msgpack4z] def bigInteger: BigInteger = BigInteger.valueOf(value)
}

object MsgpackLong extends (Long => MsgpackUnion)

final case class MsgpackULong(value: BigInteger) extends MsgpackUnion {
  override protected[msgpack4z] def pack(packer: MsgPacker): Unit =
    packer.packBigInteger(value)

  override def hashCode = value.hashCode

  override def equals(other: Any): Boolean =
    other match {
      case that: AnyRef if this eq that =>
        true
      case that: MsgpackLong =>
        value == that.bigInteger
      case that: MsgpackULong =>
        that.value == value
      case _ =>
        false
    }
}

final case class MsgpackDouble(value: Double) extends MsgpackUnion {
  override protected[msgpack4z] def pack(packer: MsgPacker): Unit =
    packer.packDouble(value)
  override def equals(other: Any): Boolean =
    other match {
      case that: MsgpackDouble =>
        java.lang.Double.doubleToLongBits(this.value) == java.lang.Double.doubleToLongBits(that.value)
      case _ =>
        false
    }
  override final def hashCode = scala.runtime.Statics.doubleHash(value)
}

object MsgpackDouble extends (Double => MsgpackUnion)

final case class MsgpackArray(value: List[MsgpackUnion]) extends MsgpackUnion {
  override protected[msgpack4z] def pack(packer: MsgPacker): Unit = {
    packer.packArrayHeader(value.size)
    var list = value
    while (list ne Nil) {
      list.head.pack(packer)
      list = list.tail
    }
    packer.arrayEnd()
  }
}

final case class MsgpackMap(value: Map[MsgpackUnion, MsgpackUnion]) extends MsgpackUnion {
  override protected[msgpack4z] def pack(packer: MsgPacker): Unit = {
    packer.packMapHeader(value.size)
    value.foreach { case (k, v) =>
      k.pack(packer)
      v.pack(packer)
    }
    packer.mapEnd()
  }
}

object MsgpackMap extends (Map[MsgpackUnion, MsgpackUnion] => MsgpackUnion)

final case class MsgpackExt(tpe: Byte, data: Array[Byte]) extends MsgpackUnion {
  override protected[msgpack4z] def pack(packer: MsgPacker): Unit = {
    packer.packExtTypeHeader(tpe, data.length)
    packer.writePayload(data)
  }

  override def toString: String = hexString("MsgpackExt(type = " + tpe + ", value = ", " ", ")", 4)

  def hexString(start: String, sep: String, end: String, n: Int): String = {
    data.sliding(n, n).map(_.map(x => "%02x".format(x & 0xff)).mkString).mkString(start, sep, end)
  }

  override def hashCode = (tpe * 31) + java.util.Arrays.hashCode(data)

  override def equals(other: Any): Boolean =
    other match {
      case that: MsgpackExt =>
        (this eq that) || (
          (this.tpe == that.tpe) && java.util.Arrays.equals(this.data, that.data)
        )
      case _ =>
        false
    }
}

case object MsgpackTrue extends MsgpackUnion {
  override protected[msgpack4z] def pack(packer: MsgPacker): Unit =
    packer.packBoolean(true)
}

case object MsgpackFalse extends MsgpackUnion {
  override protected[msgpack4z] def pack(packer: MsgPacker): Unit =
    packer.packBoolean(false)
}

case object MsgpackNil extends MsgpackUnion {
  override protected[msgpack4z] def pack(packer: MsgPacker): Unit =
    packer.packNil()
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy