def apply()

in scalding-serialization/src/main/scala/com/twitter/scalding/serialization/macros/impl/ordered_serialization/providers/OptionOrderedBuf.scala [34:154]


  def apply(c: Context)(
      buildDispatcher: => PartialFunction[c.Type, TreeOrderedBuf[c.type]],
      outerType: c.Type
  ): TreeOrderedBuf[c.type] = {
    import c.universe._
    def freshT(id: String) = TermName(c.freshName(id))
    val dispatcher = buildDispatcher

    val innerType = outerType.asInstanceOf[TypeRefApi].args.head
    val innerBuf: TreeOrderedBuf[c.type] = dispatcher(innerType)

    def genBinaryCompare(inputStreamA: TermName, inputStreamB: TermName) = {
      val valueOfA = freshT("valueOfA")
      val valueOfB = freshT("valueOfB")
      val tmpHolder = freshT("tmpHolder")
      q"""
        val $valueOfA: _root_.scala.Byte = $inputStreamA.readByte
        val $valueOfB: _root_.scala.Byte = $inputStreamB.readByte
        val $tmpHolder: _root_.scala.Int = _root_.java.lang.Byte.compare($valueOfA, $valueOfB)
        if($tmpHolder != 0 || $valueOfA == (0: _root_.scala.Byte)) {
          //either one is defined (different), or both are None (equal)
          $tmpHolder
        } else {
          ${innerBuf.compareBinary(inputStreamA, inputStreamB)}
        }
      """
    }

    def genHashFn(element: TermName) = {
      val innerValue = freshT("innerValue")
      q"""
        if($element.isEmpty)
          0
        else {
          val $innerValue = $element.get
          ${innerBuf.hash(innerValue)}
        }
      """
    }

    def genGetFn(inputStreamA: TermName) = {
      val tmpGetHolder = freshT("tmpGetHolder")
      q"""
        val $tmpGetHolder = $inputStreamA.readByte
        if($tmpGetHolder == (0: _root_.scala.Byte)) _root_.scala.None
        else _root_.scala.Some(${innerBuf.get(inputStreamA)})
      """
    }

    def genPutFn(inputStream: TermName, element: TermName) = {
      val tmpPutVal = freshT("tmpPutVal")
      val innerValue = freshT("innerValue")
      q"""
        if($element.isDefined) {
          $inputStream.writeByte(1: _root_.scala.Byte)
          val $innerValue: ${innerBuf.tpe} = $element.get
          ${innerBuf.put(inputStream, innerValue)}
        } else {
          $inputStream.writeByte(0: _root_.scala.Byte)
        }
      """
    }

    def genCompareFn(elementA: TermName, elementB: TermName) = {
      val aIsDefined = freshT("aIsDefined")
      val bIsDefined = freshT("bIsDefined")
      val innerValueA = freshT("innerValueA")
      val innerValueB = freshT("innerValueB")
      q"""
        val $aIsDefined: _root_.scala.Boolean = $elementA.isDefined
        val $bIsDefined: _root_.scala.Boolean = $elementB.isDefined
        if(!$aIsDefined) {
          if (!$bIsDefined) 0 // None == None
          else -1 // None < Some(_)
        }
        else {
          if(!$bIsDefined) 1 // Some > None
          else { // both are defined
            val $innerValueA: ${innerBuf.tpe} = $elementA.get
            val $innerValueB: ${innerBuf.tpe} = $elementB.get
            ${innerBuf.compare(innerValueA, innerValueB)}
          }
        }
      """
    }

    new TreeOrderedBuf[c.type] {
      override val ctx: c.type = c
      override val tpe = outerType
      override def compareBinary(inputStreamA: TermName, inputStreamB: TermName) =
        genBinaryCompare(inputStreamA, inputStreamB)
      override def hash(element: TermName): ctx.Tree = genHashFn(element)
      override def put(inputStream: TermName, element: TermName) = genPutFn(inputStream, element)
      override def get(inputStreamA: TermName): ctx.Tree = genGetFn(inputStreamA)
      override def compare(elementA: TermName, elementB: TermName): ctx.Tree =
        genCompareFn(elementA, elementB)
      override val lazyOuterVariables: Map[String, ctx.Tree] = innerBuf.lazyOuterVariables
      override def length(element: Tree): CompileTimeLengthTypes[c.type] =
        innerBuf.length(q"$element.get") match {
          case const: ConstantLengthCalculation[_] => FastLengthCalculation(c)(q"""
            if($element.isDefined) { 1 + ${const.toInt} }
            else { 1 }
            """)
          case f: FastLengthCalculation[_] =>
            val t = f.asInstanceOf[FastLengthCalculation[c.type]].t
            FastLengthCalculation(c)(q"""
            if($element.isDefined) { 1 + $t }
            else { 1 }
            """)
          case m: MaybeLengthCalculation[_] =>
            val t = m.asInstanceOf[MaybeLengthCalculation[c.type]].t
            val dynlen =
              q"""_root_.com.twitter.scalding.serialization.macros.impl.ordered_serialization.runtime_helpers.DynamicLen"""
            MaybeLengthCalculation(c)(q"""
            if ($element.isDefined) { $t + $dynlen(1) }
            else { $dynlen(1) }
          """)
          case _ => NoLengthCalculationAvailable(c)
        }
    }
  }