Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More efficient encoding to AST #1292

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 12 additions & 14 deletions zio-json/shared/src/main/scala/zio/json/JsonEncoder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -204,20 +204,18 @@ object JsonEncoder extends GeneratedTupleEncoders with EncoderLowPriority1 with
override def toJsonAST(a: A): Either[String, Json] = encoder.toJsonAST(a)
}

implicit val boolean: JsonEncoder[Boolean] = explicit(_.toString, Json.Bool.apply)
implicit val symbol: JsonEncoder[Symbol] = string.contramap(_.name)
implicit val byte: JsonEncoder[Byte] = explicit(_.toString, n => Json.Num(n))
implicit val short: JsonEncoder[Short] = explicit(_.toString, n => Json.Num(n))
implicit val int: JsonEncoder[Int] = explicit(_.toString, n => Json.Num(n))
implicit val long: JsonEncoder[Long] = explicit(_.toString, n => Json.Num(n))
implicit val bigInteger: JsonEncoder[java.math.BigInteger] =
explicit(_.toString, n => Json.Num(new java.math.BigDecimal(n)))
implicit val scalaBigInt: JsonEncoder[BigInt] =
explicit(_.toString, n => Json.Num(new java.math.BigDecimal(n.bigInteger)))
implicit val double: JsonEncoder[Double] = explicit(SafeNumbers.toString, n => Json.Num(n))
implicit val float: JsonEncoder[Float] = explicit(SafeNumbers.toString, n => Json.Num(n))
implicit val bigDecimal: JsonEncoder[java.math.BigDecimal] = explicit(_.toString, Json.Num.apply)
implicit val scalaBigDecimal: JsonEncoder[BigDecimal] = explicit(_.toString, n => Json.Num(n.bigDecimal))
implicit val boolean: JsonEncoder[Boolean] = explicit(_.toString, Json.Bool.apply)
implicit val symbol: JsonEncoder[Symbol] = string.contramap(_.name)
implicit val byte: JsonEncoder[Byte] = explicit(_.toString, Json.Num.apply)
implicit val short: JsonEncoder[Short] = explicit(_.toString, Json.Num.apply)
implicit val int: JsonEncoder[Int] = explicit(_.toString, Json.Num.apply)
implicit val long: JsonEncoder[Long] = explicit(_.toString, Json.Num.apply)
implicit val bigInteger: JsonEncoder[java.math.BigInteger] = explicit(_.toString, Json.Num.apply)
implicit val scalaBigInt: JsonEncoder[BigInt] = explicit(_.toString, Json.Num.apply)
implicit val double: JsonEncoder[Double] = explicit(SafeNumbers.toString, Json.Num.apply)
implicit val float: JsonEncoder[Float] = explicit(SafeNumbers.toString, Json.Num.apply)
implicit val bigDecimal: JsonEncoder[java.math.BigDecimal] = explicit(_.toString, n => new Json.Num(n))
implicit val scalaBigDecimal: JsonEncoder[BigDecimal] = explicit(_.toString, Json.Num.apply)

implicit def option[A](implicit A: JsonEncoder[A]): JsonEncoder[Option[A]] = new JsonEncoder[Option[A]] {
def unsafeEncode(oa: Option[A], indent: Option[Int], out: Write): Unit =
Expand Down
85 changes: 48 additions & 37 deletions zio-json/shared/src/main/scala/zio/json/ast/ast.scala
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ object Json {
Json.Obj(Chunk.fromArray(array))
}

override def asObject: Some[Json.Obj] = Some(this)
override def asObject: Some[Json.Obj] = new Some(this)
override def mapObject(f: Json.Obj => Json.Obj): Json.Obj = f(this)
override def mapObjectKeys(f: String => String): Json.Obj = Json.Obj(fields.map(e => f(e._1) -> e._2))
override def mapObjectValues(f: Json => Json): Json.Obj = mapValues(f)
Expand All @@ -393,16 +393,16 @@ object Json {

override final def unsafeFromJsonAST(trace: List[JsonError], json: Json): Obj =
json match {
case obj @ Obj(_) => obj
case _ => Lexer.error("Not an object", trace)
case obj: Obj => obj
case _ => Lexer.error("Not an object", trace)
}
}
private lazy val obje = JsonEncoder.keyValueChunk[String, Json]
implicit val encoder: JsonEncoder[Obj] = new JsonEncoder[Obj] {
def unsafeEncode(a: Obj, indent: Option[Int], out: Write): Unit =
obje.unsafeEncode(a.fields, indent, out)

override final def toJsonAST(a: Obj): Either[String, Json] = Right(a)
override final def toJsonAST(a: Obj): Either[String, Json] = new Right(a)
}

implicit val codec: JsonCodec[Obj] = JsonCodec(encoder, decoder)
Expand All @@ -424,7 +424,7 @@ object Json {
} ++ leftover)
}

override def asArray: Some[Chunk[Json]] = Some(elements)
override def asArray: Some[Chunk[Json]] = new Some(elements)
override def mapArray(f: Chunk[Json] => Chunk[Json]): Json.Arr = Json.Arr(f(elements))
override def mapArrayValues(f: Json => Json): Json.Arr = Json.Arr(elements.map(f))
}
Expand All @@ -446,22 +446,22 @@ object Json {

override final def unsafeFromJsonAST(trace: List[JsonError], json: Json): Arr =
json match {
case arr @ Arr(_) => arr
case _ => Lexer.error("Not an array", trace)
case arr: Arr => arr
case _ => Lexer.error("Not an array", trace)
}
}
private lazy val arre = JsonEncoder.chunk[Json]
implicit val encoder: JsonEncoder[Arr] = new JsonEncoder[Arr] {
def unsafeEncode(a: Arr, indent: Option[Int], out: Write): Unit =
arre.unsafeEncode(a.elements, indent, out)

override final def toJsonAST(a: Arr): Either[String, Json] = Right(a)
override final def toJsonAST(a: Arr): Either[String, Json] = new Right(a)
}

implicit val codec: JsonCodec[Arr] = JsonCodec(encoder, decoder)
}
final case class Bool(value: Boolean) extends Json {
override def asBoolean: Some[Boolean] = Some(value)
override def asBoolean: Some[Boolean] = new Some(value)
override def mapBoolean(f: Boolean => Boolean): Json.Bool = Json.Bool(f(value))
}

Expand All @@ -479,22 +479,22 @@ object Json {

override final def unsafeFromJsonAST(trace: List[JsonError], json: Json): Bool =
json match {
case b @ Bool(_) => b
case _ => Lexer.error("Not a bool value", trace)
case b: Bool => b
case _ => Lexer.error("Not a bool value", trace)
}
}
implicit val encoder: JsonEncoder[Bool] = new JsonEncoder[Bool] {
def unsafeEncode(a: Bool, indent: Option[Int], out: Write): Unit =
JsonEncoder.boolean.unsafeEncode(a.value, indent, out)

override final def toJsonAST(a: Bool): Either[String, Json] = Right(a)
override final def toJsonAST(a: Bool): Either[String, Json] = new Right(a)
}

implicit val codec: JsonCodec[Bool] = JsonCodec(encoder, decoder)
}
final case class Str(value: String) extends Json {
override def asString: Some[String] = Some(value)
override def mapString(f: String => String): Json.Str = Json.Str(f(value))
override def asString: Some[String] = new Some(value)
override def mapString(f: String => String): Json.Str = new Json.Str(f(value))
}
object Str {
implicit val decoder: JsonDecoder[Str] = new JsonDecoder[Str] {
Expand All @@ -503,47 +503,59 @@ object Json {

override final def unsafeFromJsonAST(trace: List[JsonError], json: Json): Str =
json match {
case s @ Str(_) => s
case _ => Lexer.error("Not a string value", trace)
case s: Str => s
case _ => Lexer.error("Not a string value", trace)
}
}
implicit val encoder: JsonEncoder[Str] = new JsonEncoder[Str] {
def unsafeEncode(a: Str, indent: Option[Int], out: Write): Unit =
JsonEncoder.string.unsafeEncode(a.value, indent, out)

override final def toJsonAST(a: Str): Either[String, Json] = Right(a)
override final def toJsonAST(a: Str): Either[String, Json] = new Right(a)
}

implicit val codec: JsonCodec[Str] = JsonCodec(encoder, decoder)
}
final case class Num(value: java.math.BigDecimal) extends Json {
override def asNumber: Some[Json.Num] = Some(this)
override def mapNumber(f: java.math.BigDecimal => java.math.BigDecimal): Json.Num = Json.Num(f(value))
override def asNumber: Some[Json.Num] = new Some(this)
override def mapNumber(f: java.math.BigDecimal => java.math.BigDecimal): Json.Num = new Json.Num(f(value))
}
object Num {
def apply(value: Byte): Num = Num(BigDecimal(value.toInt).bigDecimal)
def apply(value: Short): Num = Num(BigDecimal(value.toInt).bigDecimal)
def apply(value: Int): Num = Num(BigDecimal(value).bigDecimal)
def apply(value: Long): Num = Num(BigDecimal(value).bigDecimal)
def apply(value: BigDecimal): Num = Num(value.bigDecimal)
def apply(value: Float): Num = Num(BigDecimal.decimal(value).bigDecimal)
def apply(value: Double): Num = Num(BigDecimal(value).bigDecimal)
@inline def apply(value: Byte): Num = apply(value.toInt)
@inline def apply(value: Short): Num = apply(value.toInt)
def apply(value: Int): Num = new Num({
if (value < 512 && value > -512) new java.math.BigDecimal(value)
else BigDecimal(value).bigDecimal
})
def apply(value: Long): Num = new Num({
if (value < 512 && value > -512) new java.math.BigDecimal(value)
else BigDecimal(value).bigDecimal
})
@inline def apply(value: BigDecimal): Num = new Num(value.bigDecimal)
def apply(value: BigInt): Num =
if (value.isValidLong) apply(value.toLong)
else new Json.Num(new java.math.BigDecimal(value.bigInteger))
def apply(value: java.math.BigInteger): Num =
if (value.bitCount < 64) apply(value.longValue)
else new Json.Num(new java.math.BigDecimal(value))
def apply(value: Float): Num = new Num(new java.math.BigDecimal(value.toString))
def apply(value: Double): Num = new Num(new java.math.BigDecimal(value))

implicit val decoder: JsonDecoder[Num] = new JsonDecoder[Num] {
def unsafeDecode(trace: List[JsonError], in: RetractReader): Num =
Num(JsonDecoder.bigDecimal.unsafeDecode(trace, in))

override final def unsafeFromJsonAST(trace: List[JsonError], json: Json): Num =
json match {
case n @ Num(_) => n
case _ => Lexer.error("Not a number", trace)
case n: Num => n
case _ => Lexer.error("Not a number", trace)
}
}
implicit val encoder: JsonEncoder[Num] = new JsonEncoder[Num] {
def unsafeEncode(a: Num, indent: Option[Int], out: Write): Unit =
JsonEncoder.bigDecimal.unsafeEncode(a.value, indent, out)

override final def toJsonAST(a: Num): Either[String, Num] = Right(a)
override final def toJsonAST(a: Num): Either[String, Num] = new Right(a)
}

implicit val codec: JsonCodec[Num] = JsonCodec(encoder, decoder)
Expand All @@ -557,22 +569,21 @@ object Json {
Null
}

override final def unsafeFromJsonAST(trace: List[JsonError], json: Json): Null.type =
json match {
case Null => Null
case _ => Lexer.error("Not null", trace)
}
override final def unsafeFromJsonAST(trace: List[JsonError], json: Json): Null.type = {
if (json ne Null) Lexer.error("Not null", trace)
Null
}
}
implicit val encoder: JsonEncoder[Null.type] = new JsonEncoder[Null.type] {
def unsafeEncode(a: Null.type, indent: Option[Int], out: Write): Unit =
out.write("null")

override final def toJsonAST(a: Null.type): Either[String, Json] = Right(a)
override final def toJsonAST(a: Null.type): Either[String, Json] = new Right(a)
}

implicit val codec: JsonCodec[Null.type] = JsonCodec(encoder, decoder)

override def asNull: Some[Unit] = Some(())
override def asNull: Some[Unit] = new Some(())
}

implicit val decoder: JsonDecoder[Json] = new JsonDecoder[Json] {
Expand Down Expand Up @@ -606,7 +617,7 @@ object Json {
case Null => Null.encoder.unsafeEncode(Null, indent, out)
}

override final def toJsonAST(a: Json): Either[String, Json] = Right(a)
override final def toJsonAST(a: Json): Either[String, Json] = new Right(a)
}

implicit val codec: JsonCodec[Json] = JsonCodec(encoder, decoder)
Expand Down