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

caliban.client.__Value.scala Maven / Gradle / Ivy

The newest version!
package caliban.client

import com.github.plokhotnyuk.jsoniter_scala.core.{ writeToString, JsonReader, JsonValueCodec, JsonWriter }
import com.github.plokhotnyuk.jsoniter_scala.macros.JsonCodecMaker

import scala.annotation.switch
import scala.collection.immutable.TreeMap

/**
 * Value that can be returned by the server or sent as an argument.
 */
sealed trait __Value { self =>
  def dropNullValues: __Value = self match {
    case __Value.__ListValue(values)   => __Value.__ListValue(values.map(_.dropNullValues))
    case __Value.__ObjectValue(fields) =>
      __Value.__ObjectValue(fields.flatMap { case (name, value) =>
        value match {
          case __Value.__NullValue => None
          case _                   => Some(name -> value.dropNullValues)
        }
      })
    case _                             => self
  }
}

object __Value {
  private final val MaxDepth                                    = 1023
  private implicit val stringCodecMaker: JsonValueCodec[String] = JsonCodecMaker.make[String]

  case object __NullValue                                   extends __Value {
    override def toString: String = "null"
  }
  case class __NumberValue(value: BigDecimal)               extends __Value {
    override def toString: String = s"$value"
  }
  case class __EnumValue(value: String)                     extends __Value {
    override def toString: String = value
  }
  case class __StringValue(value: String)                   extends __Value {
    override def toString: String = writeToString(value)
  }
  case class __BooleanValue(value: Boolean)                 extends __Value {
    override def toString: String = value.toString
  }
  case class __ListValue(values: List[__Value])             extends __Value {
    override def toString: String = values.map(_.toString).mkString("[", ",", "]")
  }
  case class __ObjectValue(fields: List[(String, __Value)]) extends __Value {
    override def toString: String =
      fields.map { case (name, value) => s"""$name:${value.toString}""" }.mkString("{", ",", "}")
  }

  object __ObjectValue {
    implicit val codec: JsonValueCodec[__ObjectValue] = new JsonValueCodec[__ObjectValue] {
      def decodeValue(in: JsonReader, default: __ObjectValue): __ObjectValue = {
        val b = in.nextToken()
        if (b == '{') {
          in.rollbackToken()
          decodeJsonValue(in, MaxDepth) match {
            case v: __ObjectValue => v
            case v                => in.decodeError(s"expected object but received $v")
          }
        } else in.decodeError(s"expected object but received $b")
      }

      def encodeValue(x: __ObjectValue, out: JsonWriter): Unit =
        encodeJsonValue(x, out, MaxDepth)

      def nullValue: __ObjectValue =
        null.asInstanceOf[__ObjectValue]
    }
  }

  implicit val jsonCodec: JsonValueCodec[__Value] = new JsonValueCodec[__Value] {
    def decodeValue(in: JsonReader, default: __Value): __Value =
      decodeJsonValue(in, MaxDepth)

    def encodeValue(x: __Value, out: JsonWriter): Unit =
      encodeJsonValue(x, out, MaxDepth)

    def nullValue: __Value = __NullValue
  }

  private val emptyValueObject = __ObjectValue(Nil)
  private val emptyValueList   = __ListValue(Nil)

  private def encodeJsonValue(x: __Value, out: JsonWriter, depth: Int): Unit = x match {
    case __NumberValue(value)  => out.writeVal(value)
    case __EnumValue(value)    => out.writeVal(value)
    case __StringValue(value)  => out.writeVal(value)
    case __BooleanValue(value) => out.writeVal(value)
    case __ListValue(values)   =>
      val newDepth = depth - 1
      if (newDepth < 0) out.encodeError("Max depth reached")
      out.writeArrayStart()
      values.foreach(encodeJsonValue(_, out, depth - 1))
      out.writeArrayEnd()
    case __ObjectValue(fields) =>
      val newDepth = depth - 1
      if (newDepth < 0) out.encodeError("Max depth reached")
      out.writeObjectStart()
      fields.foreach { case (name, value) =>
        out.writeKey(name)
        encodeJsonValue(value, out, depth - 1)
      }
      out.writeObjectEnd()
    case `__NullValue`         => out.writeNull()
  }

  private def decodeJsonValue(in: JsonReader, depth: Int): __Value = {
    val b = in.nextToken()
    (b: @switch) match {
      case 'n'                                                             =>
        in.readNullOrError(__NullValue, "unexpected JSON value")
      case 't' | 'f'                                                       =>
        in.rollbackToken()
        __BooleanValue(in.readBoolean())
      case '{'                                                             =>
        val newDepth = depth - 1
        if (newDepth < 0) in.decodeError("Max depth reached")
        else if (in.isNextToken('}')) emptyValueObject
        else {
          in.rollbackToken()
          val fields = TreeMap.newBuilder[String, __Value]
          while ({
            fields += in.readKeyAsString() -> decodeJsonValue(in, newDepth)
            in.isNextToken(',')
          }) ()
          if (in.isCurrentToken('}')) __ObjectValue(fields.result().toList)
          else in.objectEndOrCommaError()
        }
      case '['                                                             =>
        val newDepth = depth - 1
        if (newDepth < 0) in.decodeError("Max depth reached")
        else if (in.isNextToken(']')) emptyValueList
        else {
          in.rollbackToken()
          val values = Array.newBuilder[__Value]
          while ({
            values += decodeJsonValue(in, newDepth)
            in.isNextToken(',')
          }) ()
          if (in.isCurrentToken(']')) __ListValue(values.result().toList)
          else in.arrayEndOrCommaError()
        }
      case '"'                                                             =>
        in.rollbackToken()
        __StringValue(in.readString(null))
      case '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '-' =>
        in.rollbackToken()
        __NumberValue(in.readBigDecimal(null))
      case c                                                               =>
        in.decodeError(s"unexpected token: $c")
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy