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

com.rojoma.json.v3.ast.ast.scala Maven / Gradle / Ivy

The newest version!
package com.rojoma.json.v3
package ast

import scala.language.implicitConversions
import scala.{collection => sc}
import scala.collection.immutable.SeqMap
import scala.reflect.ClassTag
import java.math.{BigInteger, BigDecimal => JBigDecimal}
import java.io.Writer

import extensions.DoubleWriter

sealed abstract class JsonInvalidValue(msg: String) extends IllegalArgumentException(msg) {
  def value: Any
}
case class JsonInvalidFloat(value: Float) extends JsonInvalidValue("Attempted to place a NaN or infinite value into a JSON AST.")
case class JsonInvalidDouble(value: Double) extends JsonInvalidValue("Attempted to place a NaN or infinite value into a JSON AST.")

// Closed typeclass to find out what concrete types a subclass of JValue represents
sealed abstract class Json[T <: JValue] {
  val jsonTypes : Set[JsonType]
  override lazy val toString = jsonTypes.toSeq.map(_.toString).sorted.mkString(",")
}

sealed trait JsonType
object JsonType {
  import codec._
  implicit val jCodec: JsonEncode[JsonType] with JsonDecode[JsonType] = new JsonEncode[JsonType] with JsonDecode[JsonType] {
    def encode(j: JsonType) = JString(j.toString)
    def decode(x: JValue) = x match {
      case JString(JObject.toString) => Right(JObject)
      case JString(JArray.toString) => Right(JArray)
      case JString(JString.toString) => Right(JString)
      case JString(JNumber.toString) => Right(JNumber)
      case JString(JBoolean.toString) => Right(JBoolean)
      case JString(JNull.toString) => Right(JNull)
      case s: JString => Left(DecodeError.InvalidValue(s))
      case other => Left(DecodeError.InvalidType(other.jsonType, JString))
    }
  }
}

/** A JSON datum.  This can be safely downcast to a more-specific type
  * using the `cast` method which is implicitly added to this class
  * in the companion object.*/
sealed trait JValue {
  override def toString = io.PrettyJsonWriter.toString(this)

  /** Forces this [[com.rojoma.json.v3.ast.JValue]] to be fully
    * evaluated.  In particular, the compound
    * [[com.rojoma.json.v3.codec.JsonEncode]]s will produce views of their
    * inputs instead of fully-evaluated
    * [[com.rojoma.json.v3.ast.JValue]]s.  This can be problematic if
    * the underlying structure can be mutated before this object is
    * used, or if this object is passed to another thread.
    *
    * What is or is not copied is not defined; the only postcondition
    * is that there are no lazy values left in the returned tree.
    * 
    * @return An equal [[com.rojoma.json.v3.ast.JValue]] with strict values. */
  def forced: JValue

  /** Produces a dynamically typed view of this `JValue` which can be
    * descended using dot-notation for field names or apply-type
    * syntax for arrays.  It can be turned back into a `JValue` with
    * the `!` or `?` methods.
    *
    * Note that certain field-names (the names common to all objects
    * plus `apply`, `applyDynamic`, and `selectDynamic` cannot be accessed
    * with simple field-notation.  Instead, pass them as strings to
    * the `apply` method. */
  @deprecated(message = "Prefer `dyn`", since = "3.1.1")
  def dynamic = new com.rojoma.json.v3.dynamic.DynamicJValue(Some(this))

  /** Produces a dynamically typed view of this `JValue` which can be
    * descended using dot-notation for field names or apply-type
    * syntax for arrays.  It can be turned back into a `JValue` with
    * the `!` or `?` methods.
    *
    * Note that certain field-names (the names common to all `Objects`
    * plus `apply`, `applyDynamic`, and `selectDynamic` cannot be accessed
    * with simple field-notation.  Instead, pass them as strings to
    * the `apply` method. */
  def dyn = com.rojoma.json.v3.dynamic.InformationalDynamicJValue(this)

  /* The concrete type of this value. */
  def jsonType: JsonType
}

object JValue {
  final override val toString = "value"

  /** Safe downcast with a fairly nice syntax.
    * This will statically prevent attempting to cast anywhere except
    * a subclass of the value's static type.
    *
    * It can be used for navigation in a JSON tree:
    * {{{
    *   for {
    *     JObject(foo) <- raw.cast[JObject]
    *     JArray(elems) <- foo.get("foo").flatMap(_.cast[JArray])
    *   } yield {
    *     ...something with elems...
    *   } getOrElse(throw "couldn't find interesting elements")
    * }}}
    */
  implicit def toCastable[T <: JValue](x: T) = new `-impl`.ast.DownCaster(x)

  implicit object Concrete extends Json[JValue] {
    val jsonTypes = JAtom.Concrete.jsonTypes ++ JCompound.Concrete.jsonTypes
  }
}

/** A [[com.rojoma.json.v3.ast.JValue]] that is not a [[com.rojoma.json.v3.ast.JNull]]. */
sealed trait JNotNullValue extends JValue

/** A JSON "atom" — anything except arrays or objects.  This and [[com.rojoma.json.v3.ast.JCompound]] form
  * a partition of the set of valid [[com.rojoma.json.v3.ast.JValue]]s. */
sealed abstract class JAtom extends JValue {
  final def forced: this.type = this
}

object JAtom {
  final override val toString = "atom"

  implicit object Concrete extends Json[JAtom] {
    val jsonTypes = Set[JsonType](JNumber, JString, JBoolean, JNull)
  }
}

/** A number. */
sealed abstract class JNumber extends JAtom with JNotNullValue {
  def toByte: Byte
  def toShort: Short
  def toInt: Int
  def toLong: Long
  def toBigInt: BigInt
  def toBigInteger: BigInteger
  def toFloat: Float
  def toDouble: Double
  def toBigDecimal: BigDecimal
  def toJBigDecimal: JBigDecimal

  final def jsonType = JNumber

  override final def toString = asString
  protected def asString: String
  private[v3] def toWriter(w: Writer) = w.write(asString)

  override def equals(o: Any) = o match {
    case that: JNumber => this.toJBigDecimal == that.toJBigDecimal
    case _ => false
  }
  override final lazy val hashCode = toJBigDecimal.hashCode
}

object JNumber extends JsonType {
  final override val toString = "number"

  private val stdCtx = java.math.MathContext.UNLIMITED

  private val doubleWriter = DoubleWriter.doubleWriter

  private class JIntNumber(val toInt: Int) extends JNumber {
    def toByte = toInt.toByte
    def toShort = toInt.toShort
    def toLong = toInt.toLong
    def toBigInt = BigInt(toInt)
    def toBigInteger = BigInteger.valueOf(toInt)

    def toFloat = toInt.toFloat
    def toDouble = toInt.toDouble
    def toBigDecimal = BigDecimal(toInt, stdCtx)
    lazy val toJBigDecimal = new JBigDecimal(toInt, stdCtx)

    def asString = toInt.toString

    override def equals(o: Any) = o match {
      case that: JIntNumber => this.toInt == that.toInt
      case that: JLongNumber => this.toLong == that.toLong
      case that: JBigIntNumber => this.toBigInt == that.toBigInt
      case that: JBigIntegerNumber => this.toBigInteger == that.toBigInteger
      case other => super.equals(other)
    }
  }

  private object JIntNumber {
    private val preallocated = {
      val tmp = new Array[JIntNumber](256)
      for(i <- 0 until 256) {
        tmp(i) = new JIntNumber(i - 128)
      }
      tmp
    }

    def create(n: Int) = {
      if(n >= -128 && n < 128) preallocated(n + 128)
      else new JIntNumber(n)
    }
  }

  private class JLongNumber(val toLong: Long) extends JNumber {
    def toByte = toLong.toByte
    def toShort = toLong.toShort
    def toInt = toLong.toInt
    def toBigInt = BigInt(toLong)
    def toBigInteger = BigInteger.valueOf(toLong)

    def toFloat = toLong.toFloat
    def toDouble = toLong.toDouble
    def toBigDecimal = BigDecimal(toLong, stdCtx)
    lazy val toJBigDecimal = new JBigDecimal(toLong, stdCtx)

    def asString = toLong.toString

    override def equals(o: Any) = o match {
      case that: JIntNumber => this.toLong == that.toLong
      case that: JLongNumber => this.toLong == that.toLong
      case that: JBigIntNumber => this.toBigInt == that.toBigInt
      case that: JBigIntegerNumber => this.toBigInt == that.toBigInt
      case _ => super.equals(o)
    }
  }

  private object JLongNumber {
    def create(n: Long) = {
      if(n >= Int.MinValue && n <= Int.MaxValue) JIntNumber.create(n.toInt)
      else new JLongNumber(n)
    }
  }

  private class JBigIntNumber(val toBigInt: BigInt) extends JNumber {
    def toByte: Byte = toBigInt.toByte
    def toShort: Short = toBigInt.toShort
    def toInt: Int = toBigInt.toInt
    def toLong: Long = toBigInt.toLong
    def toBigInteger: BigInteger = toBigInt.underlying()

    def toFloat: Float = toBigInt.toFloat
    def toDouble: Double = toBigInt.toDouble
    def toBigDecimal = BigDecimal(toBigInt, stdCtx)
    def toJBigDecimal = new JBigDecimal(toBigInteger, stdCtx)

    def asString = toBigInt.toString

    override def equals(o: Any) = o match {
      case that: JIntNumber => this.toBigInt == that.toBigInt
      case that: JLongNumber => this.toBigInt == that.toBigInt
      case that: JBigIntNumber => this.toBigInt == that.toBigInt
      case that: JBigIntegerNumber => this.toBigInt == that.toBigInt
      case other => super.equals(other)
    }
  }

  private object JBigIntNumber {
    val lowerBound = BigInt(Long.MinValue)
    val upperBound = BigInt(Long.MaxValue)
    def create(n: BigInt) = {
      if(n >= lowerBound && n <= upperBound) JLongNumber.create(n.toLong)
      else new JBigIntNumber(n)
    }
  }

  private class JBigIntegerNumber(val toBigInteger: BigInteger) extends JNumber {
    def toByte: Byte = toBigInteger.byteValue
    def toShort: Short = toBigInteger.shortValue
    def toInt: Int = toBigInteger.intValue
    def toLong: Long = toBigInteger.longValue
    def toBigInt: BigInt = BigInt(toBigInteger)

    def toFloat: Float = toBigInteger.floatValue
    def toDouble: Double = toBigInteger.doubleValue
    def toBigDecimal = BigDecimal(toBigInt, stdCtx)
    lazy val toJBigDecimal = new JBigDecimal(toBigInteger, stdCtx)

    def asString = toBigInt.toString

    override def equals(o: Any) = o match {
      case that: JIntNumber => this.toBigInteger == that.toBigInteger
      case that: JLongNumber => this.toBigInteger == that.toBigInteger
      case that: JBigIntNumber => this.toBigInteger == that.toBigInteger
      case that: JBigIntegerNumber => this.toBigInteger == that.toBigInteger
      case other => super.equals(other)
    }
  }

  private object JBigIntegerNumber {
    val lowerBound = BigInteger.valueOf(Long.MinValue)
    val upperBound = BigInteger.valueOf(Long.MaxValue)
    def create(n: BigInteger) = {
      if(n.compareTo(lowerBound) >= 0 && n.compareTo(upperBound) <= 0) JLongNumber.create(n.longValue)
      else new JBigIntegerNumber(n)
    }
  }

  private class JFloatNumber(val toFloat: Float) extends JNumber {
    if(toFloat.isNaN || toFloat.isInfinite) throw JsonInvalidFloat(toFloat)

    def toByte = toFloat.toByte
    def toShort: Short = toFloat.toShort
    def toInt: Int = toFloat.toInt
    def toLong: Long = toFloat.toLong
    def toBigInt: BigInt = toBigDecimal.toBigInt
    def toBigInteger: BigInteger = toJBigDecimal.toBigInteger

    def toDouble: Double = toFloat.toDouble
    def toBigDecimal = BigDecimal(toDouble, stdCtx)
    lazy val toJBigDecimal = new JBigDecimal(toDouble, stdCtx)

    def asString = toFloat.toString
  }

  private class JDoubleNumber(val toDouble: Double) extends JNumber {
    if(toDouble.isNaN || toDouble.isInfinite) throw JsonInvalidDouble(toDouble)

    def toByte: Byte = toDouble.toByte
    def toShort: Short = toDouble.toShort
    def toInt: Int = toDouble.toInt
    def toLong: Long = toDouble.toLong
    def toBigInt: BigInt = toBigDecimal.toBigInt
    def toBigInteger: BigInteger = toJBigDecimal.toBigInteger

    def toFloat: Float = toDouble.toFloat
    def toBigDecimal = BigDecimal(toDouble, stdCtx)
    lazy val toJBigDecimal = new JBigDecimal(toDouble, stdCtx)

    def asString = doubleWriter.toString(toDouble)
    override def toWriter(w: Writer) = doubleWriter.toWriter(w, toDouble)
  }

  private class JBigDecimalNumber(val toBigDecimal: BigDecimal) extends JNumber {
    def toByte: Byte = toBigDecimal.toByte
    def toShort: Short = toBigDecimal.toShort
    def toInt: Int = toBigDecimal.toInt
    def toLong: Long = toBigDecimal.toLong
    def toBigInt: BigInt = toBigDecimal.toBigInt
    def toBigInteger: BigInteger = toJBigDecimal.toBigInteger

    def toFloat: Float = toBigDecimal.toFloat
    def toDouble: Double = toBigDecimal.toDouble
    lazy val toJBigDecimal = toBigDecimal.underlying()

    def asString = toBigDecimal.toString
  }

  private class JJBigDecimalNumber(val toJBigDecimal: JBigDecimal) extends JNumber {
    def toByte: Byte = toJBigDecimal.byteValue
    def toShort: Short = toJBigDecimal.shortValue
    def toInt: Int = toJBigDecimal.intValue
    def toLong: Long = toJBigDecimal.longValue
    def toBigInt: BigInt = BigInt(toBigInteger)
    def toBigInteger: BigInteger = toJBigDecimal.toBigInteger

    def toFloat: Float = toBigDecimal.floatValue
    def toDouble: Double = toBigDecimal.doubleValue
    def toBigDecimal: BigDecimal = BigDecimal(toJBigDecimal)

    def asString = toJBigDecimal.toString
  }

  private class JUncheckedStringNumber(override val asString: String) extends JNumber {
    def toByte: Byte = try { asString.toByte} catch { case _: NumberFormatException => toBigDecimal.toByte }
    def toShort: Short = try { asString.toShort } catch { case _: NumberFormatException => toBigDecimal.toShort }
    def toInt: Int = try { asString.toInt } catch { case _: NumberFormatException => toBigDecimal.toInt }
    def toLong: Long = try { asString.toLong } catch { case _: NumberFormatException => toBigDecimal.toLong }
    def toBigInt = try { BigInt(asString) } catch { case _: NumberFormatException => toBigDecimal.toBigInt }
    def toBigInteger = try { new BigInteger(asString) } catch { case _: NumberFormatException => toJBigDecimal.toBigInteger }

    def toFloat: Float = try { asString.toFloat } catch { case _: NumberFormatException => toBigDecimal.toFloat }
    def toDouble: Double = try { asString.toDouble } catch { case _: NumberFormatException => toBigDecimal.toDouble }
    def toBigDecimal = BigDecimal(asString, stdCtx)
    lazy val toJBigDecimal = new JBigDecimal(asString, stdCtx)
  }

  def apply(b: Byte): JNumber = JIntNumber.create(b)
  def apply(s: Short): JNumber = JIntNumber.create(s)
  def apply(i: Int): JNumber = JIntNumber.create(i)
  def apply(l: Long): JNumber = JLongNumber.create(l)
  def apply(bi: BigInt): JNumber = JBigIntNumber.create(bi)
  def apply(bi: BigInteger): JNumber = JBigIntegerNumber.create(bi)
  def apply(f: Float): JNumber = new JFloatNumber(f)
  def apply(d: Double): JNumber = new JDoubleNumber(d)
  def apply(bd: BigDecimal): JNumber = new JBigDecimalNumber(bd)
  def apply(bd: JBigDecimal): JNumber = new JJBigDecimalNumber(bd)

  def unsafeFromString(s: String): JNumber = new JUncheckedStringNumber(s)

  implicit object Concrete extends Json[JNumber] {
    val jsonTypes = Set[JsonType](JNumber)
  }
}

/** A JSON string.  This does not yet enforce well-formedness with
  * respect to surrogate pairs, but it probably should. */
case class JString(string: String) extends JAtom with JNotNullValue {
  def jsonType = JString
}

object JString extends scala.runtime.AbstractFunction1[String, JString] with JsonType {
  override final val toString = "string"

  implicit object Concrete extends Json[JString] {
    val jsonTypes = Set[JsonType](JString)
  }
}

/** A boolean */
case class JBoolean(boolean: Boolean) extends JAtom with JNotNullValue {
  def jsonType = JBoolean
}

object JBoolean extends scala.runtime.AbstractFunction1[Boolean, JBoolean] with JsonType {
  val canonicalTrue = new JBoolean(true)
  val canonicalFalse = new JBoolean(false)

  def apply(boolean: Boolean) = if(boolean) canonicalTrue else canonicalFalse

  override final val toString = "boolean"

  implicit object Concrete extends Json[JBoolean] {
    val jsonTypes = Set[JsonType](JBoolean)
  }
}

/** Null. */
sealed abstract class JNull extends JAtom // so the object has a nameable type
case object JNull extends JNull with JsonType {
  final override val toString = "null"

  def jsonType = JNull

  implicit object Concrete extends Json[JNull] {
    val jsonTypes = Set[JsonType](JNull)
  }
}

/** The common superclass of arrays and objects.  This and [[com.rojoma.json.v3.ast.JAtom]] form
  * a partition of the set of valid [[com.rojoma.json.v3.ast.JValue]]s. */
sealed trait JCompound extends JNotNullValue {
  def forced: JCompound
  def size: Int
}

object JCompound {
  final override val toString = "compound"

  implicit object Concrete extends Json[JCompound] {
    val jsonTypes = JArray.Concrete.jsonTypes ++ JObject.Concrete.jsonTypes
  }
}

/** A JSON array, which is a `scala.collection.Seq` of JValues. */
case class JArray(elems: sc.Seq[JValue]) extends sc.Seq[JValue] with JCompound {
  override def length = elems.length
  override def apply(idx: Int) = elems(idx)
  override def iterator = elems.iterator

  // overloads of final methods to produce JArrays if statically determinable
  final def ++(suffix: IterableOnce[JValue]) = new JArray(elems ++ suffix)
  final def ++:(prefix: IterableOnce[JValue]) = new JArray(prefix ++: elems)
  final def +:(elem: JValue) = new JArray(elem +: elems)
  final def :+(elem: JValue) = new JArray(elems :+ elem)
  final def :++(suffix: IterableOnce[JValue]) = new JArray(elems :++ suffix)
  final def concat(suffix: sc.Seq[JValue]) = new JArray(elems.concat(suffix))

  // And now we delegate all Seq members to elems, rather than letting
  // default implementations provide them in terms of the above three
  override def appended[B >: JValue](elem: B): sc.Seq[B] = elems.appended(elem)
  final def appended(elem: JValue) = new JArray(elems.appended(elem))

  override def appendedAll[B >: JValue](elems: IterableOnce[B]): sc.Seq[B] = this.elems.appendedAll(elems)
  final def appendedAll(elems: IterableOnce[JValue]) = new JArray(this.elems.appendedAll(elems))

  override def applyOrElse[A1 <: Int, B1 >: JValue](x: A1, default: A1 => B1) = elems.applyOrElse(x, default)
  override def canEqual(that: Any) = elems.canEqual(that)
  override def collect[B](pf: PartialFunction[JValue, B]) = elems.collect(pf)
  final def collect(pf: PartialFunction[JValue, JValue]) = new JArray(elems.collect(pf))
  override def collectFirst[B](pf: PartialFunction[JValue, B]) = elems.collectFirst(pf)
  override def combinations(n: Int): Iterator[JArray] = elems.combinations(n).map(JArray)
  override def compose[R](k: PartialFunction[R, Int]) = elems.compose(k)
  override def contains[A1 >: JValue](elem: A1) = elems.contains(elem)
  override def containsSlice[B >: JValue](that: sc.Seq[B]) = elems.containsSlice(that)
  override def copyToArray[B >: JValue](xs: Array[B], start: Int, len: Int) = elems.copyToArray(xs, start, len)
  override def corresponds[B](that: sc.Seq[B])(p: (JValue, B) => Boolean) = elems.corresponds(that)(p)
  override def corresponds[B](that: IterableOnce[B])(p: (JValue, B) => Boolean) = elems.corresponds(that)(p)
  override def count(p: JValue => Boolean) = elems.count(p)
  override def diff[B >: JValue](that: sc.Seq[B]) = elems.diff(that)
  override def distinct = elems.distinct
  override def distinctBy[B](f: JValue => B) = elems.distinctBy(f)
  override def drop(n: Int) = new JArray(elems.drop(n))
  override def dropRight(n: Int) = new JArray(elems.dropRight(n))
  override def dropWhile(p: JValue => Boolean) = new JArray(elems.dropWhile(p))
  override def elementWise = elems.elementWise
  override def empty = JArray.empty
  override def endsWith[B >: JValue](that: Iterable[B]) = elems.endsWith(that)
  override def equals(o: Any) = elems.equals(o)
  override def exists(p: JValue => Boolean) = elems.exists(p)
  override def filter(p: JValue => Boolean) = new JArray(elems.filter(p))
  override def filterNot(p: JValue => Boolean) = new JArray(elems.filterNot(p))
  override def find(p: JValue => Boolean) = elems.find(p)
  override def findLast(p: JValue => Boolean) = elems.findLast(p)
  override def flatMap[B](f: JValue => IterableOnce[B]) = elems.flatMap(f)
  final def flatMap(f: JValue => IterableOnce[JValue]) = new JArray(elems.flatMap(f))
  override def flatten[B](implicit asIterable: JValue => IterableOnce[B]) = elems.flatten
  final def flatten[B](implicit asIterable: JValue => IterableOnce[JValue]) = new JArray(elems.flatten)
  override def fold[A >: JValue](z: A)(op: (A, A) => A) = elems.fold(z)(op)
  override def foldLeft[B](z: B)(op: (B, JValue) => B) = elems.foldLeft(z)(op)
  override def foldRight[B](z: B)(op: (JValue, B) => B) = elems.foldRight(z)(op)
  override def forall(p: JValue => Boolean) = elems.forall(p)
  override def foreach[U](f: JValue => U) = elems.foreach(f)
  override def groupBy[K](f: JValue => K) = elems.groupBy(f).view.mapValues(JArray).to(SeqMap)
  override def groupMap[K, B](key: JValue => K)(f: JValue => B) = elems.groupMap(key)(f)
  final def groupMap[K](key: JValue => K)(f: JValue => JValue) = elems.groupMap(key)(f).view.mapValues(JArray).to(SeqMap)
  override def groupMapReduce[K, B](key: JValue => K)(f: JValue => B)(reduce: (B, B) => B) = elems.groupMapReduce(key)(f)(reduce)
  override def grouped(size: Int) = elems.grouped(size).map(JArray)
  override def hashCode() = elems.hashCode
  override def head = elems.head
  override def headOption = elems.headOption
  override def indexOf[B >: JValue](elem: B, from: Int) = elems.indexOf(elem, from)
  override def indexOfSlice[B >: JValue](that: sc.Seq[B], from: Int) = elems.indexOfSlice(that, from)
  override def indexWhere(p: JValue => Boolean, from: Int) = elems.indexWhere(p, from)
  override def indices = elems.indices
  override def init = new JArray(elems.init)
  override def inits = elems.inits.map(JArray)
  override def intersect[B >: JValue](that: sc.Seq[B]) = new JArray(elems.intersect(that))
  override def isDefinedAt(idx: Int) = elems.isDefinedAt(idx)
  override def isEmpty = elems.isEmpty
  override def isTraversableAgain = elems.isTraversableAgain
  override def iterableFactory = elems.iterableFactory
  override def knownSize = elems.knownSize
  override def last = elems.last
  override def lastIndexOf[B >: JValue](elem: B, end: Int = length - 1) = elems.lastIndexOf(elem, end)
  override def lastIndexOfSlice[B >: JValue](that: sc.Seq[B], end: Int) = elems.lastIndexOfSlice(that, end)
  override def lastIndexWhere(p: JValue => Boolean, end: Int) = elems.lastIndexWhere(p, end)
  override def lastOption = elems.lastOption
  // lazyZip we'll allow to be inherited
  override def lengthCompare(that: Iterable[_]) = elems.lengthCompare(that)
  override def lengthCompare(len: Int) = elems.lengthCompare(len)
  override def lift = elems.lift
  override def map[B](f: JValue => B) = elems.map(f)
  final def map(f: JValue => JValue) = new JArray(elems.map(f))
  override def max[B >: JValue : math.Ordering] = elems.max[B]
  override def maxBy[B : math.Ordering](f: JValue => B) = elems.maxBy(f)
  override def maxByOption[B : math.Ordering](f: JValue => B) = elems.maxByOption(f)
  override def maxOption[B >: JValue : math.Ordering] = elems.maxOption[B]
  override def min[B >: JValue : math.Ordering] = elems.min[B]
  override def minBy[B : math.Ordering](f: JValue => B) = elems.minBy(f)
  override def minByOption[B : math.Ordering](f: JValue => B) = elems.minByOption(f)
  override def minOption[B >: JValue : math.Ordering] = elems.minOption[B]
  override def orElse[A1 <: Int, B1 >: JValue](that: PartialFunction[A1, B1]) = elems.orElse(that)
  override def padTo[B >: JValue](len: Int, elem: B) = elems.padTo(len, elem)
  final def padTo(len: Int, elem: JValue) = new JArray(elems.padTo(len, elem))
  override def partition(p: JValue => Boolean) = {
    val (a, b) = elems.partition(p)
    (new JArray(a), new JArray(b))
  }
  override def partitionMap[A1, A2](f: JValue => Either[A1, A2]) = elems.partitionMap(f)
  override def patch[B >: JValue](from: Int, other: IterableOnce[B], replaced: Int) = elems.patch(from, other, replaced)
  final def patch(from: Int, other: IterableOnce[JValue], replaced: Int) = new JArray(elems.patch(from, other, replaced))
  override def permutations = elems.permutations.map(JArray)
  override def prepended[B >: JValue](elem: B) = elems.prepended(elem)
  final def prepended(elem: JValue) = new JArray(elems.prepended(elem))
  override def prependedAll[B >: JValue](prefix: IterableOnce[B]) = elems.prependedAll(prefix)
  final def prependedAll(prefix: IterableOnce[JValue]) = new JArray(elems.prependedAll(prefix))
  override def product[B >: JValue : math.Numeric] = elems.product[B]
  override def reduce[B >: JValue](op: (B, B) => B) = elems.reduce(op)
  override def reduceLeft[B >: JValue](op: (B, JValue) => B) = elems.reduceLeft(op)
  override def reduceLeftOption[B >: JValue](op: (B, JValue) => B) = elems.reduceLeftOption(op)
  override def reduceOption[B >: JValue](op: (B, B) => B) = elems.reduceOption(op)
  override def reduceRight[B >: JValue](op: (JValue, B) => B) = elems.reduceRight(op)
  override def reduceRightOption[B >: JValue](op: (JValue, B) => B) = elems.reduceRightOption(op)
  override def reverse = new JArray(elems.reverse)
  override def reverseIterator = elems.reverseIterator
  override def runWith[U](action: JValue => U) = elems.runWith(action)
  override def sameElements[B >: JValue](that: IterableOnce[B]) = elems.sameElements(that)
  // scans deliberately do not have JArray-specific overrides because
  // it's not clear to me that it would be a good idea.
  override def scan[B >: JValue](z: B)(op: (B, B) => B) = elems.scan(z)(op)
  override def scanLeft[B](z: B)(op: (B, JValue) => B) = elems.scanLeft(z)(op)
  override def scanRight[B](z: B)(op: (JValue, B) => B) = elems.scanRight(z)(op)
  override def search[B >: JValue : Ordering](elem: B, from: Int, to: Int) = elems.search(elem, from, to)
  override def search[B >: JValue : Ordering](elem: B) = elems.search(elem)
  override def segmentLength(p: JValue => Boolean, from: Int) = elems.segmentLength(p, from)
  override def slice(from: Int, until: Int) = new JArray(elems.slice(from, until))
  override def sliding(size: Int, step: Int) = elems.sliding(size, step).map(JArray)
  override def sliding(size: Int) = elems.sliding(size).map(JArray)
  override def sortBy[B : Ordering](f: JValue => B) = new JArray(elems.sortBy(f))
  override def sortWith(lt: (JValue, JValue) => Boolean) = new JArray(elems.sortWith(lt))
  override def sorted[B >: JValue : Ordering] = elems.sorted[B]
  override def span(p: JValue => Boolean) = {
    val (a, b) = elems.span(p)
    (new JArray(a), new JArray(b))
  }
  override def splitAt(n: Int) = {
    val (a, b) = elems.splitAt(n)
    (new JArray(a), new JArray(b))
  }
  override def startsWith[B >: JValue](that: IterableOnce[B], offset: Int = 0) = elems.startsWith(that)
  override def stepper[S <: sc.Stepper[_]](implicit shape: sc.StepperShape[JValue, S]) = elems.stepper[S]
  override def sum[B >: JValue : math.Numeric] = elems.sum[B]
  override def tail = new JArray(elems.tail)
  override def tails = elems.tails.map(JArray)
  override def take(n: Int) = new JArray(elems.take(n))
  override def takeRight(n: Int) = new JArray(elems.takeRight(n))
  override def takeWhile(p: JValue => Boolean) = new JArray(elems.takeWhile(p))
  override def tapEach[U](f: JValue => U) = new JArray(elems.tapEach(f))
  override def to[C1](factory: sc.Factory[JValue, C1]) = elems.to(factory)
  override def toArray[B >: JValue : ClassTag] = elems.toArray[B]
  override def toIndexedSeq = elems.toIndexedSeq
  override def toList = elems.toList
  override def toMap[K, V](implicit ev: <:<[JValue, (K, V)]) = elems.toMap
  override def toSeq = elems.toSeq
  override def toSet[B >: JValue] = elems.toSet[B]
  override def toVector = elems.toVector
  // transpose also does not have a JArray-producing override deliberately
  override def transpose[B](implicit asIterable: JValue => Iterable[B]) = elems.transpose[B]
  override def unapply(a: Int) = elems.unapply(a)
  override def unzip[A1, A2](implicit asPair: JValue => (A1, A2)) = elems.unzip[A1, A2]
  override def unzip3[A1, A2, A3](implicit asPair: JValue => (A1, A2, A3)) = elems.unzip3[A1, A2, A3]
  override def updated[B >: JValue](index: Int, elem: B) = elems.updated(index, elem)
  final def updated(index: Int, elem: JValue) = new JArray(elems.updated(index, elem))
  override def view = elems.view
  override def withFilter(p: JValue => Boolean) = elems.withFilter(p)
  override def zip[B](that: IterableOnce[B]) = elems.zip(that)
  override def zipAll[A1 >: JValue, B](that: Iterable[B], thisElem: A1, thatElem: B) = elems.zipAll(that, thisElem, thatElem)
  override def zipWithIndex = elems.zipWithIndex

  def forced: JArray = {
    // not just "toSeq.map(_forced)" because the seq might be a Stream or view
    val forcedArray: Vector[JValue] =
      elems.view.map(_.forced).toVector
    new JArray(forcedArray) {
      override def forced = this
    }
  }

  def jsonType = JArray
}

object JArray extends scala.runtime.AbstractFunction1[sc.Seq[JValue], JArray] with sc.Factory[JValue, JArray] with JsonType {
  val empty: JArray = new JArray(Vector.empty) { // Vector because JsonReader is guaranteed to return JArrays which contain Vectors.
    override def forced = this
  }
  val canonicalEmpty = empty

  override def apply(elems: sc.Seq[JValue]) =
    elems match {
      case arr: JArray => arr
      case other => new JArray(other)
    }

  override final val toString = "array"
  implicit object Concrete extends Json[JArray] {
    val jsonTypes = Set[JsonType](JArray)
  }

  private class JArrayBuilder extends sc.mutable.Builder[JValue, JArray] {
    private val underlying = Vector.newBuilder[JValue]
    override def addOne(elem: JValue) = { underlying.addOne(elem); this }
    override def clear(): Unit = underlying.clear()
    override def result(): JArray = JArray(underlying.result())
  }

  override def fromSpecific(it: IterableOnce[JValue]) = JArray(it.iterator.to(Vector))
  override def newBuilder: sc.mutable.Builder[JValue, JArray] = new JArrayBuilder

  implicit def jarrayFactory[A <: JValue]: sc.Factory[A, JArray] = this
}

/** A JSON object, which is a `scala.collection.Map` from `String` to [[com.rojoma.json.v3.ast.JValue]]. */
case class JObject(val fields: sc.Map[String, JValue]) extends sc.Map[String, JValue] with JCompound {
  override def get(key: String) = fields.get(key)
  override def iterator = fields.iterator

  @deprecated("Use - or removed on an immutable Map", "2.13.0")
  def -(key: String) = new JObject(fields - key)
  @deprecated("Use -- or removedAll on an immutable Map", "2.13.0")
  def -(key1: String, key2: String, keys: String*) = new JObject(fields.-(key1, key2, keys : _*))

  override def ++[V2 >: JValue](xs: IterableOnce[(String, V2)]) = fields ++ xs
  override def andThen[C](k: PartialFunction[JValue, C]) = fields.andThen(k)
  override def andThen[C](k: JValue => C) = fields.andThen(k)
  override def apply(key: String) = fields(key)
  override def applyOrElse[K1 <: String, V1 >: JValue](x: K1, default: K1 => V1) = fields.applyOrElse(x, default)
  override def canEqual(that: Any) = fields.canEqual(that)
  override def collect[K2, V2](pf: PartialFunction[(String, JValue), (K2, V2)]) = fields.collect(pf)
  final def collect(pf: PartialFunction[(String, JValue), (String, JValue)]) = new JObject(fields.collect(pf))
  override def collect[B](pf: PartialFunction[(String, JValue), B]) = fields.collect(pf)
  override def collectFirst[B](pf: PartialFunction[(String, JValue), B]) = fields.collectFirst(pf)
  override def compose[A](f: A => String) = fields.compose(f)
  override def concat[V2 >: JValue](suffix: IterableOnce[(String, V2)]) = fields.concat(suffix)
  final def concat[V2 <: JValue](suffix: sc.Map[String, V2]) = new JObject(fields.concat(suffix))
  override def concat[B >: (String, JValue)](suffix: IterableOnce[B]) = fields.concat(suffix)
  override def contains(key: String) = fields.contains(key)
  override def copyToArray[B >: (String, JValue)](xs: Array[B], start: Int, len: Int) = fields.copyToArray(xs, start, len)
  override def corresponds[B](that: IterableOnce[B])(p: ((String, JValue), B) => Boolean) = fields.corresponds(that)(p)
  override def count(p: ((String, JValue)) => Boolean) = fields.count(p)
  override def default(key: String) = fields.default(key)
  override def drop(n: Int) = new JObject(fields.drop(n))
  override def dropRight(n: Int) = new JObject(fields.dropRight(n))
  override def dropWhile(p: ((String, JValue)) => Boolean) = new JObject(fields.dropWhile(p))
  override def elementWise = fields.elementWise
  override def empty = JObject.empty
  override def equals(o: Any) = fields.equals(o)
  override def exists(p: ((String, JValue)) => Boolean) = fields.exists(p)
  override def filter(pred: ((String, JValue)) => Boolean) = new JObject(fields.filter(pred))
  override def filterNot(pred: ((String, JValue)) => Boolean) = new JObject(fields.filterNot(pred))
  override def find(p: ((String, JValue)) => Boolean) = fields.find(p)
  override def flatMap[K2, V2](f: ((String, JValue)) => IterableOnce[(K2, V2)]) = fields.flatMap(f)
  final def flatMap(f: ((String, JValue)) => IterableOnce[(String, JValue)]) = new JObject(fields.flatMap(f))
  override def flatMap[B](f: ((String, JValue)) => IterableOnce[B]) = fields.flatMap(f)
  override def flatten[B](implicit asIterable: ((String, JValue)) => IterableOnce[B]) = fields.flatten[B]
  override def fold[A >: (String, JValue)](z: A)(op: (A, A) => A) = fields.fold(z)(op)
  override def foldLeft[B](z: B)(op: (B, (String, JValue)) => B) = fields.foldLeft(z)(op)
  override def foldRight[B](z: B)(op: ((String, JValue), B) => B) = fields.foldRight(z)(op)
  override def forall(p: ((String, JValue)) => Boolean) = fields.forall(p)
  override def foreach[U](f: ((String, JValue)) => U) = fields.foreach(f)
  override def foreachEntry[U](f: (String, JValue) => U) = fields.foreachEntry(f)
  override def getOrElse[V1 >: JValue](key: String, default: => V1) = fields.getOrElse(key, default)
  override def groupBy[K](f: ((String, JValue)) => K) = fields.groupBy(f).view.mapValues(JObject).to(SeqMap)
  override def groupMap[K, B](key: ((String, JValue)) => K)(f: ((String, JValue)) => B) = fields.groupMap(key)(f)
  override def groupMapReduce[K, B](key: ((String, JValue)) => K)(f: ((String, JValue)) => B)(reduce: (B, B) => B) = fields.groupMapReduce(key)(f)(reduce)
  override def grouped(size: Int) = fields.grouped(size).map(JObject)
  override def hashCode() = fields.hashCode()
  override def head = fields.head
  override def headOption = fields.headOption
  override def init = new JObject(fields.init)
  override def inits = fields.inits.map(JObject)
  override def isDefinedAt(key: String) = fields.isDefinedAt(key)
  override def isEmpty = fields.isEmpty
  override def isTraversableAgain = fields.isTraversableAgain
  override def iterableFactory = fields.iterableFactory
  override def keySet = fields.keySet
  override def keyStepper[S <: sc.Stepper[_]](implicit shape: sc.StepperShape[String, S]) = fields.keyStepper[S]
  override def keys = fields.keys
  override def keysIterator = fields.keysIterator
  override def knownSize = fields.size
  override def last = fields.last
  override def lastOption = fields.lastOption
  // lazyZip gets inherited
  override def lift = fields.lift
  override def map[K2, V2](f: ((String, JValue)) => (K2, V2)) = fields.map(f)
  final def map(f: ((String, JValue)) => (String, JValue)) = new JObject(fields.map(f))
  override def map[B](f: ((String, JValue)) => B) = fields.map(f)
  override def mapFactory = fields.mapFactory
  override def max[B >: (String, JValue) : math.Ordering] = fields.max[B]
  override def maxBy[B : math.Ordering](f: ((String, JValue)) => B) = fields.maxBy(f)
  override def maxByOption[B : math.Ordering](f: ((String, JValue)) => B) = fields.maxByOption(f)
  override def maxOption[B >: (String, JValue) : math.Ordering] = fields.maxOption[B]
  override def min[B >: (String, JValue) : math.Ordering] = fields.min[B]
  override def minBy[B : math.Ordering](f: ((String, JValue)) => B) = fields.minBy(f)
  override def minByOption[B : math.Ordering](f: ((String, JValue)) => B) = fields.minByOption(f)
  override def minOption[B >: (String, JValue) : math.Ordering] = fields.minOption[B]
  override def orElse[A1 <: String, B1 >: JValue](that: PartialFunction[A1, B1]) = fields.orElse(that)
  override def partition(p: ((String, JValue)) => Boolean) = {
    val (a, b) = fields.partition(p)
    (new JObject(a), new JObject(b))
  }
  override def partitionMap[A1, A2](f: ((String, JValue)) => Either[A1, A2]) = fields.partitionMap(f)
  override def product[B >: (String, JValue) : math.Numeric] = fields.product[B]
  override def reduce[B >: (String, JValue)](op: (B, B) => B) = fields.reduce(op)
  override def reduceLeft[B >: (String, JValue)](op: (B, (String, JValue)) => B) = fields.reduceLeft(op)
  override def reduceLeftOption[B >: (String, JValue)](op: (B, (String, JValue)) => B) = fields.reduceLeftOption(op)
  override def reduceOption[B >: (String, JValue)](op: (B, B) => B) = fields.reduceOption(op)
  override def reduceRight[B >: (String, JValue)](op: ((String, JValue), B) => B) = fields.reduceRight(op)
  override def reduceRightOption[B >: (String, JValue)](op: ((String, JValue), B) => B) = fields.reduceRightOption(op)
  override def runWith[U](action: JValue => U) = fields.runWith(action)
  override def scan[B >: (String, JValue)](z: B)(op: (B, B) => B) = fields.scan(z)(op)
  override def scanLeft[B](z: B)(op: (B, (String, JValue)) => B) = fields.scanLeft(z)(op)
  override def scanRight[B](z: B)(op: ((String, JValue), B) => B) = fields.scanRight(z)(op)
  override def size = fields.size
  override def sizeCompare(that: Iterable[_]) = fields.sizeCompare(that)
  override def sizeCompare(otherSize: Int) = fields.sizeCompare(otherSize)
  override def slice(from: Int, until: Int) = new JObject(fields.slice(from, until))
  override def sliding(size: Int, step: Int) = fields.sliding(size, step).map(JObject)
  override def sliding(size: Int) = fields.sliding(size).map(JObject)
  override def span(p: ((String, JValue)) => Boolean) = {
    val (a, b) = fields.span(p)
    (new JObject(a), new JObject(b))
  }
  override def splitAt(n: Int) = {
    val (a, b) = fields.splitAt(n)
    (new JObject(a), new JObject(b))
  }
  override def stepper[S <: sc.Stepper[_]](implicit shape: sc.StepperShape[(String, JValue), S]) = fields.stepper[S]
  override def sum[B >: (String, JValue) : Numeric] = fields.sum[B]
  override def tail = new JObject(fields.tail)
  override def tails = fields.tails.map(JObject)
  override def take(n: Int) = new JObject(fields.take(n))
  override def takeRight(n: Int) = new JObject(fields.takeRight(n))
  override def takeWhile(p: ((String, JValue)) => Boolean) = new JObject(fields.takeWhile(p))
  override def tapEach[U](f: ((String, JValue)) => U) = new JObject(fields.tapEach(f))
  override def to[C1](factory: sc.Factory[(String, JValue), C1]) = fields.to(factory)
  override def toArray[B >: (String, JValue) : ClassTag] = fields.toArray[B]
  override def toIndexedSeq = fields.toIndexedSeq
  override def toList = fields.toList
  override def toMap[K, V](implicit ev: <:<[(String, JValue), (K, V)]) = fields.toMap
  override def toSeq = fields.toSeq
  override def toSet[B >: (String, JValue)] = fields.toSet
  override def toVector = fields.toVector
  override def transpose[B](implicit asIterable: ((String, JValue)) => Iterable[B]) = fields.transpose[B]
  override def unapply(a: String) = fields.unapply(a)
  override def unzip[A1, A2](implicit asPair: ((String, JValue)) => ((A1, A2))) = fields.unzip[A1, A2]
  override def unzip3[A1, A2, A3](implicit asPair: ((String, JValue)) => ((A1, A2, A3))) = fields.unzip3[A1, A2, A3]
  override def valueStepper[S <: sc.Stepper[_]](implicit shape: sc.StepperShape[JValue, S]) = fields.valueStepper[S]
  override def values = fields.values
  override def valuesIterator = fields.valuesIterator
  override def view = fields.view
  override def withFilter(p: ((String, JValue)) => Boolean) = fields.withFilter(p)
  override def zip[B](that: IterableOnce[B]) = fields.zip(that)
  override def zipAll[A1 >: (String, JValue), B](that: Iterable[B], thisElem: A1, thatElem: B) = fields.zipAll(that, thisElem, thatElem)
  override def zipWithIndex = fields.zipWithIndex

  def forced: JObject = {
    new JObject(fields.view.mapValues(_.forced).to(SeqMap)) {
      override def forced = this
    }
  }

  def jsonType = JObject
}

object JObject extends scala.runtime.AbstractFunction1[sc.Map[String, JValue], JObject] with sc.Factory[(String, JValue), JObject] with JsonType {
  val empty: JObject = new JObject(SeqMap.empty) {
    override def forced = this
  }
  val canonicalEmpty = empty
  override final val toString = "object"
  implicit object Concrete extends Json[JObject] {
    val jsonTypes = Set[JsonType](JObject)
  }

  override def apply(fields: sc.Map[String, JValue]) =
    fields match {
      case arr: JObject => arr
      case other => new JObject(other)
    }

  private class JObjectBuilder extends sc.mutable.Builder[(String, JValue), JObject] {
    private val underlying = SeqMap.newBuilder[String, JValue]
    override def addOne(elem: (String, JValue)) = { underlying.addOne(elem); this }
    override def clear(): Unit = underlying.clear()
    override def result(): JObject = JObject(underlying.result())
  }

  override def fromSpecific(it: IterableOnce[(String, JValue)]) = JObject(it.iterator.to(SeqMap))
  override def newBuilder: sc.mutable.Builder[(String, JValue), JObject] = new JObjectBuilder

  implicit def jobjectFactory[A <: JValue]: sc.Factory[(String, A), JObject] = this
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy