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

ujson.Js.scala Maven / Gradle / Ivy

There is a newer version: 0.6.3
Show newest version
package ujson


import ujson.util.Util

import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer

sealed trait Js extends Transformable {
  def value: Any


  /**
    * Returns the `String` value of this [[Js.Value]], fails if it is not
    * a [[Js.Str]]
    */
  def str = this match{
    case Js.Str(value) => value
    case _ => throw Js.InvalidData(this, "Expected Js.Str")
  }
  /**
    * Returns the key/value map of this [[Js.Value]], fails if it is not
    * a [[Js.Obj]]
    */
  def obj = this match{
    case Js.Obj(value) => value
    case _ => throw Js.InvalidData(this, "Expected Js.Obj")
  }
  /**
    * Returns the elements of this [[Js.Value]], fails if it is not
    * a [[Js.Arr]]
    */
  def arr = this match{
    case Js.Arr(value) => value
    case _ => throw Js.InvalidData(this, "Expected Js.Arr")
  }
  /**
    * Returns the `Double` value of this [[Js.Value]], fails if it is not
    * a [[Js.Num]]
    */
  def num = this match{
    case Js.Num(value) => value
    case _ => throw Js.InvalidData(this, "Expected Js.Num")
  }

  /**
    * Looks up the [[Js.Value]] as a [[Js.Arr]] using an index, throws
    * otherwise if it's not a [[Js.Arr]]
    */
  def apply(i: Int): Js.Value = this.arr(i)
  def update(i: Int, v: Js.Value): Unit = this.arr(i) = v
  /**
    * Looks up the [[Js.Value]] as a [[Js.Obj]] using an index, throws
    * otherwise if it's not a [[Js.Obj]]
    */
  def apply(s: java.lang.String): Js.Value = this.obj(s)
  def update(s: String, v: Js.Value): Unit = this.obj(s) = v

  def transform[T](f: ujson.Visitor[_, T]) = Js.transform(this, f)
  override def toString = render()
  def render(indent: Int = -1) = this.transform(StringRenderer(indent)).toString
}

/**
* A very small, very simple JSON AST that uPickle uses as part of its
* serialization process. A common standard between the Jawn AST (which
* we don't use so we don't pull in the bulk of Spire) and the Javascript
* JSON AST.
*/
object Js extends AstTransformer[Js]{

  case class Str(value: String) extends Value
  case class Obj(value: mutable.Map[String, Value]) extends Value
  object Obj{
    def apply(items: (String, Value)*): Obj = Obj(mutable.Map(items:_*))
  }
  case class Arr(value: ArrayBuffer[Value]) extends Value
  object Arr{
    def apply(items: Value*): Arr = Arr(items.to[mutable.ArrayBuffer])
  }
  case class Num(value: Double) extends Value
  case object False extends Value{
    def value = false
  }
  case object True extends Value{
    def value = true
  }
  case object Null extends Value{
    def value = null
  }


  implicit def JsonableByte(i: Byte) = Num(i)
  implicit def JsonableShort(i: Short) = Num(i)
  implicit def JsonableInt(i: Int) = Num(i)
  implicit def JsonableLong(i: Long) = Str(i.toString)
  implicit def JsonableFloat(i: Float) = Num(i)
  implicit def JsonableDouble(i: Double) = Num(i)
  implicit def JsonableNull(i: Null) = Null
  implicit def JsonableString(s: CharSequence) = Str(s.toString)
  
  
  type Value = Js
  def transform[T](j: Js.Value, f: ujson.Visitor[_, T]): T = {
    j match{
      case Js.Null => f.visitNull(-1)
      case Js.True => f.visitTrue(-1)
      case Js.False => f.visitFalse(-1)
      case Js.Str(s) => f.visitString(s, -1)
      case Js.Num(d) => f.visitNumRaw(d, -1)
      case Js.Arr(items) => transformArray(f, items)
      case Js.Obj(items) => transformObject(f, items)
    }
  }

  def visitArray(index: Int) = new AstArrVisitor[ArrayBuffer](xs => Js.Arr(xs))

  def visitObject(index: Int) = new AstObjVisitor[mutable.Map[String, Js]](xs => Js.Obj(xs))

  def visitNull(index: Int) = Js.Null

  def visitFalse(index: Int) = Js.False

  def visitTrue(index: Int) = Js.True


  override def visitNum(s: CharSequence, decIndex: Int, expIndex: Int, index: Int) = {
    Js.Num(
      if (decIndex != -1 || expIndex != -1) s.toString.toDouble
      else Util.parseIntegralNum(s, decIndex, expIndex, index)
    )
  }

  override def visitNumRaw(d: Double, index: Int) = Js.Num(d)

  def visitString(s: CharSequence, index: Int) = Js.Str(s.toString)

  /**
    * Thrown when uPickle tries to convert a JSON blob into a given data
    * structure but fails because part the blob is invalid
    *
    * @param data The section of the JSON blob that uPickle tried to convert.
    *             This could be the entire blob, or it could be some subtree.
    * @param msg Human-readable text saying what went wrong
    */
  case class InvalidData(data: Js.Value, msg: String)
    extends Exception(s"$msg (data: $data)")
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy