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

mess.ast.MsgPack.scala Maven / Gradle / Ivy

The newest version!
package mess.ast

import java.math.BigInteger

import org.msgpack.core.{MessagePack, MessagePacker, MessageUnpacker, MessageFormat => MF}

import scala.annotation.tailrec
import scala.collection.mutable

sealed trait MsgPack {

  def isNil: Boolean

  def isEmpty: Boolean

  def pack(acc: MessagePacker): Unit

  def asBoolean: Option[Boolean]

  def asByteArray: Option[Array[Byte]]

  def asExtension: Option[(Byte, Int, Array[Byte])]

  def asByte: Option[Byte]

  def asShort: Option[Short]

  def asInt: Option[Int]

  def asLong: Option[Long]

  def asBigInt: Option[BigInt]

  def asDouble: Option[Double]

  def asFloat: Option[Float]

  def asChar: Option[Char]

  def asString: Option[String]

  def asMap: Option[Map[MsgPack, MsgPack]]

  def asVector: Option[Vector[MsgPack]]
}

object MsgPack {

  private[mess] final case object MEmpty extends MsgPack {
    def isNil: Boolean                                = false
    def isEmpty: Boolean                              = true
    def pack(acc: MessagePacker): Unit                = ()
    def asBoolean: Option[Boolean]                    = None
    def asByteArray: Option[Array[Byte]]              = None
    def asExtension: Option[(Byte, Int, Array[Byte])] = None
    def asByte: Option[Byte]                          = None
    def asShort: Option[Short]                        = None
    def asInt: Option[Int]                            = None
    def asLong: Option[Long]                          = None
    def asBigInt: Option[BigInt]                      = None
    def asDouble: Option[Double]                      = None
    def asFloat: Option[Float]                        = None
    def asChar: Option[Char]                          = None
    def asString: Option[String]                      = None
    def asMap: Option[Map[MsgPack, MsgPack]]          = None
    def asVector: Option[Vector[MsgPack]]             = None
  }

  private[mess] final case object MNil extends MsgPack {
    def isNil: Boolean                                = true
    def isEmpty: Boolean                              = false
    def pack(acc: MessagePacker): Unit                = acc.packNil()
    def asBoolean: Option[Boolean]                    = None
    def asByteArray: Option[Array[Byte]]              = None
    def asExtension: Option[(Byte, Int, Array[Byte])] = None
    def asByte: Option[Byte]                          = None
    def asShort: Option[Short]                        = None
    def asInt: Option[Int]                            = None
    def asLong: Option[Long]                          = None
    def asBigInt: Option[BigInt]                      = None
    def asDouble: Option[Double]                      = None
    def asFloat: Option[Float]                        = None
    def asChar: Option[Char]                          = None
    def asString: Option[String]                      = None
    def asMap: Option[Map[MsgPack, MsgPack]]          = None
    def asVector: Option[Vector[MsgPack]]             = None
  }

  private[mess] final case class MBool(a: Boolean) extends MsgPack {
    def isNil: Boolean                                = false
    def isEmpty: Boolean                              = false
    def pack(acc: MessagePacker): Unit                = acc.packBoolean(a)
    def asBoolean: Option[Boolean]                    = Some(a)
    def asByteArray: Option[Array[Byte]]              = None
    def asExtension: Option[(Byte, Int, Array[Byte])] = None
    def asByte: Option[Byte]                          = None
    def asShort: Option[Short]                        = None
    def asInt: Option[Int]                            = None
    def asLong: Option[Long]                          = None
    def asBigInt: Option[BigInt]                      = None
    def asDouble: Option[Double]                      = None
    def asFloat: Option[Float]                        = None
    def asChar: Option[Char]                          = None
    def asString: Option[String]                      = None
    def asMap: Option[Map[MsgPack, MsgPack]]          = None
    def asVector: Option[Vector[MsgPack]]             = None
  }

  private[mess] final case class MString(a: String) extends MsgPack {
    def isNil: Boolean                                = false
    def isEmpty: Boolean                              = false
    def pack(acc: MessagePacker): Unit                = acc.packString(a)
    def asBoolean: Option[Boolean]                    = None
    def asByteArray: Option[Array[Byte]]              = None
    def asExtension: Option[(Byte, Int, Array[Byte])] = None
    def asByte: Option[Byte]                          = None
    def asShort: Option[Short]                        = None
    def asInt: Option[Int]                            = None
    def asLong: Option[Long]                          = None
    def asBigInt: Option[BigInt]                      = None
    def asDouble: Option[Double]                      = None
    def asFloat: Option[Float]                        = None
    def asChar: Option[Char]                          = if (a.length == 1) Some(a.charAt(0)) else None
    def asString: Option[String]                      = Some(a)
    def asMap: Option[Map[MsgPack, MsgPack]]          = None
    def asVector: Option[Vector[MsgPack]]             = None
  }

  private[mess] final case class MByte(a: Byte) extends MsgPack {
    def isNil: Boolean                                = false
    def isEmpty: Boolean                              = false
    def pack(acc: MessagePacker): Unit                = acc.packByte(a)
    def asBoolean: Option[Boolean]                    = None
    def asByteArray: Option[Array[Byte]]              = None
    def asExtension: Option[(Byte, Int, Array[Byte])] = None
    def asByte: Option[Byte]                          = Some(a)
    def asShort: Option[Short]                        = Some(a.toShort)
    def asInt: Option[Int]                            = Some(a.toInt)
    def asLong: Option[Long]                          = Some(a.toLong)
    def asBigInt: Option[BigInt]                      = Some(BigInt(a.toInt))
    def asDouble: Option[Double]                      = None
    def asFloat: Option[Float]                        = None
    def asChar: Option[Char]                          = None
    def asString: Option[String]                      = None
    def asMap: Option[Map[MsgPack, MsgPack]]          = None
    def asVector: Option[Vector[MsgPack]]             = None
  }

  private[mess] final case class MShort(a: Short) extends MsgPack {
    def isNil: Boolean                                = false
    def isEmpty: Boolean                              = false
    def pack(acc: MessagePacker): Unit                = acc.packShort(a)
    def asBoolean: Option[Boolean]                    = None
    def asByteArray: Option[Array[Byte]]              = None
    def asExtension: Option[(Byte, Int, Array[Byte])] = None
    def asByte: Option[Byte]                          = Some(a.toByte)
    def asShort: Option[Short]                        = Some(a)
    def asInt: Option[Int]                            = Some(a.toInt)
    def asLong: Option[Long]                          = Some(a.toLong)
    def asBigInt: Option[BigInt]                      = Some(BigInt(a.toInt))
    def asDouble: Option[Double]                      = None
    def asFloat: Option[Float]                        = None
    def asChar: Option[Char]                          = None
    def asString: Option[String]                      = None
    def asMap: Option[Map[MsgPack, MsgPack]]          = None
    def asVector: Option[Vector[MsgPack]]             = None
  }

  private[mess] final case class MInt(a: Int) extends MsgPack {
    def isNil: Boolean                                = false
    def isEmpty: Boolean                              = false
    def pack(acc: MessagePacker): Unit                = acc.packInt(a)
    def asBoolean: Option[Boolean]                    = None
    def asByteArray: Option[Array[Byte]]              = None
    def asExtension: Option[(Byte, Int, Array[Byte])] = None
    def asByte: Option[Byte]                          = Some(a.toByte)
    def asShort: Option[Short]                        = Some(a.toShort)
    def asInt: Option[Int]                            = Some(a.toInt)
    def asLong: Option[Long]                          = Some(a.toLong)
    def asBigInt: Option[BigInt]                      = Some(BigInt(a))
    def asDouble: Option[Double]                      = None
    def asFloat: Option[Float]                        = None
    def asChar: Option[Char]                          = None
    def asString: Option[String]                      = None
    def asMap: Option[Map[MsgPack, MsgPack]]          = None
    def asVector: Option[Vector[MsgPack]]             = None
  }

  private[mess] final case class MLong(a: Long) extends MsgPack {
    def isNil: Boolean                                = false
    def isEmpty: Boolean                              = false
    def pack(acc: MessagePacker): Unit                = acc.packLong(a)
    def asBoolean: Option[Boolean]                    = None
    def asByteArray: Option[Array[Byte]]              = None
    def asExtension: Option[(Byte, Int, Array[Byte])] = None
    def asByte: Option[Byte]                          = Some(a.toByte)
    def asShort: Option[Short]                        = Some(a.toShort)
    def asInt: Option[Int]                            = Some(a.toInt)
    def asLong: Option[Long]                          = Some(a)
    def asBigInt: Option[BigInt]                      = Some(BigInt(a))
    def asDouble: Option[Double]                      = None
    def asFloat: Option[Float]                        = None
    def asChar: Option[Char]                          = None
    def asString: Option[String]                      = None
    def asMap: Option[Map[MsgPack, MsgPack]]          = None
    def asVector: Option[Vector[MsgPack]]             = None
  }

  private[mess] final case class MBigInt(a: BigInt) extends MsgPack {
    def isNil: Boolean                                = false
    def isEmpty: Boolean                              = false
    def pack(acc: MessagePacker): Unit                = acc.packBigInteger(a.bigInteger)
    def asBoolean: Option[Boolean]                    = None
    def asByteArray: Option[Array[Byte]]              = None
    def asExtension: Option[(Byte, Int, Array[Byte])] = None
    def asByte: Option[Byte]                          = Some(a.toByte)
    def asShort: Option[Short]                        = Some(a.toShort)
    def asInt: Option[Int]                            = Some(a.toInt)
    def asLong: Option[Long]                          = Some(a.toLong)
    def asBigInt: Option[BigInt]                      = Some(a)
    def asDouble: Option[Double]                      = None
    def asFloat: Option[Float]                        = None
    def asChar: Option[Char]                          = None
    def asString: Option[String]                      = None
    def asMap: Option[Map[MsgPack, MsgPack]]          = None
    def asVector: Option[Vector[MsgPack]]             = None
  }

  private[mess] final case class MDouble(a: Double) extends MsgPack {
    def isNil: Boolean                                = false
    def isEmpty: Boolean                              = false
    def pack(acc: MessagePacker): Unit                = acc.packDouble(a)
    def asBoolean: Option[Boolean]                    = None
    def asByteArray: Option[Array[Byte]]              = None
    def asExtension: Option[(Byte, Int, Array[Byte])] = None
    def asByte: Option[Byte]                          = None
    def asShort: Option[Short]                        = None
    def asInt: Option[Int]                            = None
    def asLong: Option[Long]                          = None
    def asBigInt: Option[BigInt]                      = None
    def asDouble: Option[Double]                      = Some(a)
    def asFloat: Option[Float]                        = Some(a.toFloat)
    def asChar: Option[Char]                          = None
    def asString: Option[String]                      = None
    def asMap: Option[Map[MsgPack, MsgPack]]          = None
    def asVector: Option[Vector[MsgPack]]             = None
  }

  private[mess] final case class MFloat(a: Float) extends MsgPack {
    def isNil: Boolean                                = false
    def isEmpty: Boolean                              = false
    def pack(acc: MessagePacker): Unit                = acc.packFloat(a)
    def asBoolean: Option[Boolean]                    = None
    def asByteArray: Option[Array[Byte]]              = None
    def asExtension: Option[(Byte, Int, Array[Byte])] = None
    def asByte: Option[Byte]                          = None
    def asShort: Option[Short]                        = None
    def asInt: Option[Int]                            = None
    def asLong: Option[Long]                          = None
    def asBigInt: Option[BigInt]                      = None
    def asDouble: Option[Double]                      = Some(a.toDouble)
    def asFloat: Option[Float]                        = Some(a)
    def asChar: Option[Char]                          = None
    def asString: Option[String]                      = None
    def asMap: Option[Map[MsgPack, MsgPack]]          = None
    def asVector: Option[Vector[MsgPack]]             = None
  }

  private[mess] final case class MArray(a: Vector[MsgPack]) extends MsgPack {
    def isNil: Boolean   = false
    def isEmpty: Boolean = false
    def pack(acc: MessagePacker): Unit = {
      acc.packArrayHeader(a.size)
      a.foreach(_.pack(acc))
    }
    def asBoolean: Option[Boolean]                    = None
    def asByteArray: Option[Array[Byte]]              = None
    def asExtension: Option[(Byte, Int, Array[Byte])] = None
    def asByte: Option[Byte]                          = None
    def asShort: Option[Short]                        = None
    def asInt: Option[Int]                            = None
    def asLong: Option[Long]                          = None
    def asBigInt: Option[BigInt]                      = None
    def asDouble: Option[Double]                      = None
    def asFloat: Option[Float]                        = None
    def asChar: Option[Char]                          = None
    def asString: Option[String]                      = None
    def asMap: Option[Map[MsgPack, MsgPack]]          = None
    def asVector: Option[Vector[MsgPack]]             = Some(a)
  }

  private[mess] final case class MMap(a: mutable.HashMap[MsgPack, MsgPack]) extends MsgPack {
    def isNil: Boolean                                = false
    def isEmpty: Boolean                              = false
    def asBoolean: Option[Boolean]                    = None
    def asByteArray: Option[Array[Byte]]              = None
    def asExtension: Option[(Byte, Int, Array[Byte])] = None
    def asByte: Option[Byte]                          = None
    def asShort: Option[Short]                        = None
    def asInt: Option[Int]                            = None
    def asLong: Option[Long]                          = None
    def asBigInt: Option[BigInt]                      = None
    def asDouble: Option[Double]                      = None
    def asFloat: Option[Float]                        = None
    def asChar: Option[Char]                          = None
    def asString: Option[String]                      = None
    def asMap: Option[Map[MsgPack, MsgPack]]          = Some(a.toMap)
    def asVector: Option[Vector[MsgPack]]             = None
    def add(k: MsgPack, v: MsgPack): MsgPack = {
      this.copy(a += k -> v)
    }
    def pack(acc: MessagePacker): Unit = {
      acc.packMapHeader(a.size)
      a.foreach {
        case (k, v) =>
          k.pack(acc)
          v.pack(acc)
      }
    }
    def iterator: Iterator[(MsgPack, MsgPack)] = a.iterator
  }

  private[mess] final case class MExtension(typ: Byte, size: Int, a: Array[Byte]) extends MsgPack {
    def isNil: Boolean   = false
    def isEmpty: Boolean = false
    def pack(acc: MessagePacker): Unit = {
      acc.packExtensionTypeHeader(typ, size)
      acc.writePayload(a)
    }

    def asBoolean: Option[Boolean]                    = None
    def asByteArray: Option[Array[Byte]]              = Some(a)
    def asExtension: Option[(Byte, Int, Array[Byte])] = Some((typ, size, a))
    def asByte: Option[Byte]                          = None
    def asShort: Option[Short]                        = None
    def asInt: Option[Int]                            = None
    def asLong: Option[Long]                          = None
    def asBigInt: Option[BigInt]                      = None
    def asDouble: Option[Double]                      = None
    def asFloat: Option[Float]                        = None
    def asChar: Option[Char]                          = None
    def asString: Option[String]                      = None
    def asMap: Option[Map[MsgPack, MsgPack]]          = None
    def asVector: Option[Vector[MsgPack]]             = None
  }

  private[mess] final case class MBin(a: Array[Byte]) extends MsgPack {
    def isNil: Boolean   = false
    def isEmpty: Boolean = false
    def pack(acc: MessagePacker): Unit = {
      acc.packBinaryHeader(a.length)
      acc.writePayload(a)
    }
    def asBoolean: Option[Boolean]                    = None
    def asByteArray: Option[Array[Byte]]              = Some(a)
    def asExtension: Option[(Byte, Int, Array[Byte])] = None
    def asByte: Option[Byte]                          = None
    def asShort: Option[Short]                        = None
    def asInt: Option[Int]                            = None
    def asLong: Option[Long]                          = None
    def asBigInt: Option[BigInt]                      = None
    def asDouble: Option[Double]                      = None
    def asFloat: Option[Float]                        = None
    def asChar: Option[Char]                          = None
    def asString: Option[String]                      = None
    def asMap: Option[Map[MsgPack, MsgPack]]          = None
    def asVector: Option[Vector[MsgPack]]             = None
  }

  @tailrec private[this] def unpackArr(size: Int,
                                       acc: mutable.Builder[MsgPack, Vector[MsgPack]],
                                       buffer: MessageUnpacker): Vector[MsgPack] = {
    if (size == 0) acc.result()
    else unpackArr(size - 1, acc += unpack(buffer), buffer)
  }

  @tailrec private[this] def unpackMap(size: Int,
                                       acc: mutable.HashMap[MsgPack, MsgPack],
                                       buffer: MessageUnpacker): mutable.HashMap[MsgPack, MsgPack] = {
    if (size == 0) acc
    else {
      val k = unpack(buffer)
      val v = unpack(buffer)
      unpackMap(size - 1, acc += k -> v, buffer)
    }
  }

  def pack(msgPack: MsgPack, config: MessagePack.PackerConfig): Array[Byte] = {
    val buffer = config.newBufferPacker()
    try {
      msgPack.pack(buffer)
      buffer.toByteArray
    } finally buffer.close()
  }

  def unpack(bytes: Array[Byte], config: MessagePack.UnpackerConfig): MsgPack = {
    val buffer = config.newUnpacker(bytes)
    try unpack(buffer)
    finally buffer.close()
  }

  def unpack(buffer: MessageUnpacker): MsgPack = {
    if (!buffer.hasNext) MsgPack.MEmpty
    else
      buffer.getNextFormat match {
        case MF.NIL =>
          buffer.unpackNil()
          MsgPack.MNil
        case MF.BOOLEAN =>
          MsgPack.MBool(buffer.unpackBoolean())
        case MF.FLOAT32 =>
          MsgPack.MFloat(buffer.unpackFloat())
        case MF.FLOAT64 =>
          MsgPack.MDouble(buffer.unpackDouble())
        case MF.POSFIXINT | MF.NEGFIXINT | MF.INT8 =>
          MsgPack.MByte(buffer.unpackByte())
        case MF.UINT8 =>
          val x = buffer.unpackShort()
          if (x < 128) MsgPack.MByte(x.toByte) else MsgPack.MShort(x)
        case MF.INT16 =>
          MsgPack.MShort(buffer.unpackShort())
        case MF.INT32 =>
          MsgPack.MInt(buffer.unpackInt())
        case MF.UINT16 =>
          val x = buffer.unpackInt()
          if (x < 32768) MsgPack.MShort(x.toShort) else MsgPack.MInt(x)
        case MF.INT64 =>
          MsgPack.MLong(buffer.unpackLong())
        case MF.UINT32 =>
          val x = buffer.unpackLong()
          if (x < 2147483648L) MsgPack.MInt(x.toInt) else MsgPack.MLong(x)
        case MF.UINT64 =>
          val x = buffer.unpackBigInteger()
          if (x.compareTo(BigInteger.valueOf(9223372036854775807L)) <= 0)
            MsgPack.MLong(x.longValue())
          else
            MsgPack.MBigInt(BigInt(x))
        case MF.STR8 | MF.STR16 | MF.STR32 | MF.FIXSTR =>
          MsgPack.MString(buffer.unpackString())
        case MF.FIXARRAY | MF.ARRAY16 | MF.ARRAY32 =>
          val size = buffer.unpackArrayHeader()
          MsgPack.MArray(unpackArr(size, Vector.newBuilder, buffer))
        case MF.FIXMAP | MF.MAP16 | MF.MAP32 =>
          val size = buffer.unpackMapHeader()
          MsgPack.MMap(unpackMap(size, mutable.HashMap.empty, buffer))
        case MF.BIN8 | MF.BIN16 | MF.BIN32 =>
          val size = buffer.unpackBinaryHeader()
          MsgPack.MBin(buffer.readPayload(size))
        case MF.EXT8 | MF.EXT16 | MF.EXT32 | MF.FIXEXT1 | MF.FIXEXT2 | MF.FIXEXT4 | MF.FIXEXT8 | MF.FIXEXT16 =>
          val ext   = buffer.unpackExtensionTypeHeader()
          val bytes = Array.ofDim[Byte](ext.getLength)
          buffer.readPayload(bytes)
          MsgPack.MExtension(ext.getType, ext.getLength, bytes)
        case MF.NEVER_USED =>
          throw sys.error("cannot unpack format: NEVER USED")
      }
  }

  private[this] final val True  = MBool(true)
  private[this] final val False = MBool(false)

  def nil: MsgPack                                        = MNil
  def empty: MsgPack                                      = MEmpty
  def fromPairs(xs: (MsgPack, MsgPack)*): MsgPack         = MMap(mutable.HashMap(xs: _*))
  def fromPairSeq(xs: Seq[(MsgPack, MsgPack)]): MsgPack   = MMap(mutable.HashMap(xs: _*))
  def fromValues(xs: MsgPack*): MsgPack                   = MArray(xs.toVector)
  def fromVector(xs: Vector[MsgPack]): MsgPack            = MArray(xs)
  def fromBoolean(x: Boolean): MsgPack                    = if (x) True else False
  def fromString(x: String): MsgPack                      = MString(x)
  def fromBigInt(x: BigInt): MsgPack                      = MBigInt(x)
  def fromByte(x: Byte): MsgPack                          = MByte(x)
  def fromShort(x: Short): MsgPack                        = MShort(x)
  def fromInt(x: Int): MsgPack                            = MInt(x)
  def fromLong(x: Long): MsgPack                          = MLong(x)
  def fromFloat(x: Float): MsgPack                        = MFloat(x)
  def fromDouble(x: Double): MsgPack                      = MDouble(x)
  def fromBytes(x: Array[Byte]): MsgPack                  = MBin(x)
  def extension(typ: Byte, size: Int, bytes: Array[Byte]) = MExtension(typ, size, bytes)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy