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

ongo.reactivemongo-bson_2.10.0.11.13.source-code.bufferhandlers.scala Maven / Gradle / Ivy

/*
 * Copyright 2013 Stephane Godbillon (@sgodbillon)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package reactivemongo.bson.buffer

import reactivemongo.bson._
import scala.util.{ Failure, Success, Try }

trait BufferHandler {
  def serialize(bson: BSONValue, buffer: WritableBuffer): WritableBuffer
  def deserialize(buffer: ReadableBuffer): Try[(String, BSONValue)]

  def write(buffer: WritableBuffer, document: BSONDocument) = {
    serialize(document, buffer)
  }

  def write(buffer: WritableBuffer, arr: BSONArray) = {
    serialize(arr, buffer)
  }

  def readDocument(buffer: ReadableBuffer): Try[BSONDocument]

  def writeDocument(document: BSONDocument, buffer: WritableBuffer): WritableBuffer

  def stream(buffer: ReadableBuffer): Stream[(String, BSONValue)] = {
    val elem = deserialize(buffer)
    if (elem.isSuccess)
      elem.get #:: stream(buffer)
    else Stream.empty
  }
}

object DefaultBufferHandler extends BufferHandler {
  sealed trait BufferWriter[B <: BSONValue] {
    def write(value: B, buffer: WritableBuffer): WritableBuffer
  }

  sealed trait BufferReader[B <: BSONValue] {
    def read(buffer: ReadableBuffer): B
  }

  sealed trait BufferRW[B <: BSONValue] extends BufferWriter[B] with BufferReader[B]

  val handlersByCode: Map[Byte, BufferRW[_ <: BSONValue]] = Map(
    0x01.toByte -> BSONDoubleBufferHandler,
    0x02.toByte -> BSONStringBufferHandler,
    0x03.toByte -> BSONDocumentBufferHandler,
    0x04.toByte -> BSONArrayBufferHandler, // array
    0x05.toByte -> BSONBinaryBufferHandler, // binary TODO
    0x06.toByte -> BSONUndefinedBufferHandler, // undefined,
    0x07.toByte -> BSONObjectIDBufferHandler, // objectid,
    0x08.toByte -> BSONBooleanBufferHandler, // boolean
    0x09.toByte -> BSONDateTimeBufferHandler, // datetime
    0x0A.toByte -> BSONNullBufferHandler, // null
    0x0B.toByte -> BSONRegexBufferHandler, // regex
    0x0C.toByte -> BSONDBPointerBufferHandler, // dbpointer
    0x0D.toByte -> BSONJavaScriptBufferHandler, // JS
    0x0E.toByte -> BSONSymbolBufferHandler, // symbol
    0x0F.toByte -> BSONJavaScriptWSBufferHandler, // JS with scope
    0x10.toByte -> BSONIntegerBufferHandler,
    0x11.toByte -> BSONTimestampBufferHandler, // timestamp,
    0x12.toByte -> BSONLongBufferHandler, // long,
    0xFF.toByte -> BSONMinKeyBufferHandler, // min
    0x7F.toByte -> BSONMaxKeyBufferHandler) // max

  object BSONDoubleBufferHandler extends BufferRW[BSONDouble] {
    def write(value: BSONDouble, buffer: WritableBuffer): WritableBuffer = buffer.writeDouble(value.value)
    def read(buffer: ReadableBuffer): BSONDouble = BSONDouble(buffer.readDouble)
  }
  object BSONStringBufferHandler extends BufferRW[BSONString] {
    def write(value: BSONString, buffer: WritableBuffer): WritableBuffer = buffer.writeString(value.value)
    def read(buffer: ReadableBuffer): BSONString = BSONString(buffer.readString)
  }
  object BSONDocumentBufferHandler extends BufferRW[BSONDocument] {
    def write(doc: BSONDocument, buffer: WritableBuffer) = {
      val now = buffer.index
      buffer.writeInt(0)
      doc.elements.foreach { e =>
        buffer.writeByte(e._2.code.toByte)
        buffer.writeCString(e._1)
        serialize(e._2, buffer)
      }
      buffer.setInt(now, (buffer.index - now + 1))
      buffer.writeByte(0)
      buffer
    }
    def read(b: ReadableBuffer) = {
      val startIndex = b.index
      val length = b.readInt
      val buffer = b.slice(length - 4)
      b.discard(length - 4)
      def makeStream(): Stream[Try[(String, BSONValue)]] = {
        if (buffer.readable > 1) { // last is 0
          val code = buffer.readByte
          val name = buffer.readCString
          val elem = Try(name -> DefaultBufferHandler.handlersByCode.get(code).map(_.read(buffer)).get)
          elem #:: makeStream
        } else Stream.empty
      }
      val stream = makeStream
      stream.force // TODO remove
      new BSONDocument(stream)
    }
  }
  object BSONArrayBufferHandler extends BufferRW[BSONArray] {
    def write(array: BSONArray, buffer: WritableBuffer) = {
      val now = buffer.index
      buffer.writeInt(0)
      array.values.zipWithIndex.foreach { e =>
        buffer.writeByte(e._1.code.toByte)
        buffer.writeCString(e._2.toString)
        serialize(e._1, buffer)
      }
      buffer.setInt(now, (buffer.index - now + 1))
      buffer.writeByte(0)
      buffer
    }
    def read(b: ReadableBuffer) = {
      val startIndex = b.index
      val length = b.readInt
      val buffer = b.slice(length - 4)
      b.discard(length - 4)
      def makeStream(): Stream[Try[BSONValue]] = {
        if (buffer.readable > 1) { // last is 0
          val code = buffer.readByte
          val name = buffer.readCString
          val elem = Try(DefaultBufferHandler.handlersByCode.get(code).map(_.read(buffer)).get)
          elem #:: makeStream
        } else Stream.empty
      }
      val stream = makeStream
      stream.force // TODO remove
      new BSONArray(stream)
    }
  }
  object BSONBinaryBufferHandler extends BufferRW[BSONBinary] {
    def write(binary: BSONBinary, buffer: WritableBuffer) = {
      buffer.writeInt(binary.value.readable)
      buffer.writeByte(binary.subtype.value.toByte)
      val bin = binary.value.slice(binary.value.readable)
      buffer.writeBytes(bin.readArray(bin.readable)) // TODO
      buffer
    }
    def read(buffer: ReadableBuffer) = {
      val length = buffer.readInt
      val subtype = Subtype.apply(buffer.readByte)
      val bin = buffer.slice(length)
      buffer.discard(length)
      BSONBinary(bin, subtype)
    }
  }
  object BSONUndefinedBufferHandler extends BufferRW[BSONUndefined.type] {
    def write(undefined: BSONUndefined.type, buffer: WritableBuffer) = buffer
    def read(buffer: ReadableBuffer) = BSONUndefined
  }
  object BSONObjectIDBufferHandler extends BufferRW[BSONObjectID] {
    def write(objectId: BSONObjectID, buffer: WritableBuffer) = buffer writeBytes objectId.valueAsArray
    def read(buffer: ReadableBuffer) = BSONObjectID(buffer.readArray(12))
  }
  object BSONBooleanBufferHandler extends BufferRW[BSONBoolean] {
    def write(boolean: BSONBoolean, buffer: WritableBuffer) = buffer writeByte (if (boolean.value) 1 else 0)
    def read(buffer: ReadableBuffer) = BSONBoolean(buffer.readByte == 0x01)
  }
  object BSONDateTimeBufferHandler extends BufferRW[BSONDateTime] {
    def write(dateTime: BSONDateTime, buffer: WritableBuffer) = buffer writeLong dateTime.value
    def read(buffer: ReadableBuffer) = BSONDateTime(buffer.readLong)
  }
  object BSONNullBufferHandler extends BufferRW[BSONNull.type] {
    def write(`null`: BSONNull.type, buffer: WritableBuffer) = buffer
    def read(buffer: ReadableBuffer) = BSONNull
  }
  object BSONRegexBufferHandler extends BufferRW[BSONRegex] {
    def write(regex: BSONRegex, buffer: WritableBuffer) = { buffer writeCString regex.value; buffer writeCString regex.flags }
    def read(buffer: ReadableBuffer) = BSONRegex(buffer.readCString, buffer.readCString)
  }
  object BSONDBPointerBufferHandler extends BufferRW[BSONDBPointer] {
    def write(pointer: BSONDBPointer, buffer: WritableBuffer) = { buffer writeCString pointer.value; buffer writeBytes pointer.id }
    def read(buffer: ReadableBuffer) = BSONDBPointer(buffer.readCString, buffer.readArray(12))
  }
  object BSONJavaScriptBufferHandler extends BufferRW[BSONJavaScript] {
    def write(js: BSONJavaScript, buffer: WritableBuffer) = buffer writeString js.value
    def read(buffer: ReadableBuffer) = BSONJavaScript(buffer.readString)
  }
  object BSONSymbolBufferHandler extends BufferRW[BSONSymbol] {
    def write(symbol: BSONSymbol, buffer: WritableBuffer) = buffer writeString symbol.value
    def read(buffer: ReadableBuffer) = BSONSymbol(buffer.readString)
  }
  object BSONJavaScriptWSBufferHandler extends BufferRW[BSONJavaScriptWS] {
    def write(jsws: BSONJavaScriptWS, buffer: WritableBuffer) = buffer writeString jsws.value
    def read(buffer: ReadableBuffer) = BSONJavaScriptWS(buffer.readString)
  }
  object BSONIntegerBufferHandler extends BufferRW[BSONInteger] {
    def write(value: BSONInteger, buffer: WritableBuffer) = buffer writeInt value.value
    def read(buffer: ReadableBuffer): BSONInteger = BSONInteger(buffer.readInt)
  }
  object BSONTimestampBufferHandler extends BufferRW[BSONTimestamp] {
    def write(ts: BSONTimestamp, buffer: WritableBuffer) = buffer writeLong ts.value
    def read(buffer: ReadableBuffer) = BSONTimestamp(buffer.readLong)
  }
  object BSONLongBufferHandler extends BufferRW[BSONLong] {
    def write(long: BSONLong, buffer: WritableBuffer) = buffer writeLong long.value
    def read(buffer: ReadableBuffer) = BSONLong(buffer.readLong)
  }
  object BSONMinKeyBufferHandler extends BufferRW[BSONMinKey.type] {
    def write(b: BSONMinKey.type, buffer: WritableBuffer) = buffer
    def read(buffer: ReadableBuffer) = BSONMinKey
  }
  object BSONMaxKeyBufferHandler extends BufferRW[BSONMaxKey.type] {
    def write(b: BSONMaxKey.type, buffer: WritableBuffer) = buffer
    def read(buffer: ReadableBuffer) = BSONMaxKey
  }

  def serialize(bson: BSONValue, buffer: WritableBuffer): WritableBuffer = {
    handlersByCode.get(bson.code).get.asInstanceOf[BufferRW[BSONValue]].write(bson, buffer)
  }

  def deserialize(buffer: ReadableBuffer): Try[(String, BSONValue)] = Try {
    if (buffer.readable > 0) {
      val code = buffer.readByte
      buffer.readString -> handlersByCode.get(code).map(_.read(buffer)).get
    } else throw new NoSuchElementException("buffer can not be read, end of buffer reached")
  }

  def readDocument(buffer: ReadableBuffer): Try[BSONDocument] = Try {
    BSONDocumentBufferHandler.read(buffer)
  }

  def writeDocument(document: BSONDocument, buffer: WritableBuffer): WritableBuffer =
    serialize(document, buffer)
}

sealed trait BSONIterator extends Iterator[BSONElement] {
  val buffer: ReadableBuffer

  val startIndex = buffer.index
  val documentSize = buffer.readInt

  def next: BSONElement = {
    val code = buffer.readByte
    buffer.readString -> DefaultBufferHandler.handlersByCode.get(code).map(_.read(buffer)).get
  }

  def hasNext = buffer.index - startIndex + 1 < documentSize

  def mapped: Map[String, BSONElement] = {
    for (el <- this) yield (el._1, el)
  }.toMap
}

object BSONIterator {
  private[bson] def pretty(i: Int, it: Iterator[Try[BSONElement]]): String = {
    val prefix = (0 to i).map { i => "  " }.mkString("")
    (for (tryElem <- it) yield {
      tryElem match {
        case Success(elem) => elem._2 match {
          case array: BSONArray  => prefix + elem._1 + ": [\n" + pretty(i + 1, array.iterator) + "\n" + prefix + "]"

          case doc: BSONDocument => prefix + elem._1 + ": {\n" + pretty(i + 1, doc.stream.iterator) + "\n" + prefix + "}"

          case BSONString(s) =>
            prefix + elem._1 + ": \"" + s.replaceAll("\"", "\\\"") + '"'

          case _ => prefix + elem._1 + ": " + elem._2.toString
        }
        case Failure(e) => s"${prefix}ERROR[${e.getMessage()}]"
      }
    }).mkString(",\n")
  }
  /** Makes a pretty String representation of the given iterator of BSON elements. */
  def pretty(it: Iterator[Try[BSONElement]]): String = "{\n" + pretty(0, it) + "\n}"
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy