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

tech.ytsaurus.spyt.serialization.YsonEncoder.scala Maven / Gradle / Ivy

package tech.ytsaurus.spyt.serialization

import com.google.protobuf.CodedOutputStream
import org.apache.spark.sql.types.DataType
import tech.ytsaurus.spyt.serializers.{YsonEncoderConfig, YsonRowConverter, YtTypeHolder}
import tech.ytsaurus.typeinfo.TiType
import tech.ytsaurus.yson.{YsonConsumer, YsonTags}

import java.io.ByteArrayOutputStream

class YsonEncoder(stream: ByteArrayOutputStream) extends YsonConsumer {
  private val output = CodedOutputStream.newInstance(stream, 8192)
  private var firstItem = false

  private def writeBytes(bytes: Array[Byte], offset: Int, length: Int): Unit = translateException {
    output.writeSInt32NoTag(bytes.length)
    output.writeRawBytes(bytes, offset, length)
  }

  private def translateException(f: => Unit): Unit = {
    try {
      f
    } catch {
      case e: Exception => throw ExceptionUtils.translate(e)
    }
  }

  def onInteger(value: Long): Unit = translateException {
    output.writeRawByte(YsonTags.BINARY_INT)
    output.writeSInt64NoTag(value)
  }

  def onBoolean(value: Boolean): Unit = translateException {
    output.writeRawByte(if (value) YsonTags.BINARY_TRUE else YsonTags.BINARY_FALSE)
  }

  def onDouble(value: Double): Unit = translateException {
    output.writeRawByte(YsonTags.BINARY_DOUBLE)
    output.writeDoubleNoTag(value)
  }

  def onEntity(): Unit = translateException {
    output.writeRawByte(YsonTags.ENTITY)
  }

  def onListItem(): Unit = translateException {
    if (firstItem) firstItem = false
    else output.writeRawByte(YsonTags.ITEM_SEPARATOR)
  }

  def onBeginList(): Unit = translateException {
    firstItem = true
    output.writeRawByte(YsonTags.BEGIN_LIST)
  }

  def onEndList(): Unit = translateException {
    firstItem = false
    output.writeRawByte(YsonTags.END_LIST)
  }

  def onBeginAttributes(): Unit = translateException {
    firstItem = true
    output.writeRawByte(YsonTags.BEGIN_ATTRIBUTES)
  }

  def onEndAttributes(): Unit = translateException {
    firstItem = false
    output.writeRawByte(YsonTags.END_ATTRIBUTES)
  }

  def onBeginMap(): Unit = translateException {
    firstItem = true
    output.writeRawByte(YsonTags.BEGIN_MAP)
  }

  def onEndMap(): Unit = translateException {
    firstItem = false
    output.writeRawByte(YsonTags.END_MAP)
  }

  override def onUnsignedInteger(l: Long): Unit = {
    output.writeRawByte(YsonTags.BINARY_UINT)
    output.writeUInt64NoTag(l)
  }

  override def onString(bytes: Array[Byte], i: Int, i1: Int): Unit = {
    output.writeRawByte(YsonTags.BINARY_STRING)
    writeBytes(bytes, i, i1)
  }

  override def onKeyedItem(bytes: Array[Byte], i: Int, i1: Int): Unit = {
    if (firstItem) firstItem = false
    else output.writeRawByte(YsonTags.ITEM_SEPARATOR)
    output.writeRawByte(YsonTags.BINARY_STRING)
    writeBytes(bytes, i, i1)
    output.writeRawByte(YsonTags.KEY_VALUE_SEPARATOR)
  }

  def close(): Unit = translateException {
    output.flush()
  }
}


object YsonEncoder {
  def encode(value: Any, dataType: DataType, skipNulls: Boolean,
             typeV3Format: Boolean = false, ytType: Option[TiType] = None): Array[Byte] = {
    val output = new ByteArrayOutputStream(200)
    val writer = new YsonEncoder(output)
    write(value, dataType, skipNulls, writer, typeV3Format, ytType)
    writer.close()
    output.toByteArray
  }

  private def write(value: Any, dataType: DataType, skipNulls: Boolean, writer: YsonEncoder,
                    typeV3Format: Boolean, ytType: Option[TiType]): Unit = {
    YsonRowConverter.serializeValue(value, dataType,
      YsonEncoderConfig(skipNulls, typeV3Format), writer, YtTypeHolder(ytType))
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy