-
-
Notifications
You must be signed in to change notification settings - Fork 99
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
upickle codec #1163
Comments
@jam01 Hi, Jose! Thanks for opening the discussion! Yes, it would be great to have your visitor implementation to be published. If you would like to contribute here then |
@jam01 Please see latest changes in the related branch: https://github.com/plokhotnyuk/jsoniter-scala/tree/upickle-visitor Next steps:
|
Here are results of benchmarks for parsing and serialization of GeoJSON messages on
|
Yeah the changes make sense! I thought a mark reset was needed, but wasn't 100% sure. I'm also curious why the CI build needed to have ujson.Arr cast as ujson.Value, I tried the same scalac flags in my local and it still worked without the cast. As far as the numbers I think the really interesting comparison would be against ujson reading benchmarks. |
Here are results of benchmarks for the same JSON sample parsed/serialized to/from
|
Huh that's a big gap |
Unfortunately, those results are great because the current implementation use From the other side |
Probably if you are interested only in parsing/serialization to/from import com.github.plokhotnyuk.jsoniter_scala.core.{JsonReader, JsonValueCodec, JsonWriter}
import upickle.core.{ArrVisitor, ObjVisitor, StringVisitor, Transformer, Visitor}
final class Decoder[J](maxDepth: Int = 32)
(implicit v: Visitor[?, J]) extends JsonValueCodec[J] {
override def nullValue: J = null.asInstanceOf[J]
override def encodeValue(x: J, out: JsonWriter): Unit =
throw new UnsupportedOperationException("Codec only supports decoding")
override def decodeValue(in: JsonReader, default: J): J =
decode(in, maxDepth, v)
private[this] def decode[Z](in: JsonReader, depth: Int, v: Visitor[?, Z]): Z = {
val b = in.nextToken()
if (b == '"') {
in.rollbackToken()
v.visitString(in.readString(null), -1)
} else if (b == 'f' || b == 't') {
in.rollbackToken()
if (in.readBoolean()) v.visitTrue(-1)
else v.visitFalse(-1)
} else if (b >= '0' && b <= '9' || b == '-') {
in.rollbackToken()
v.visitFloat64(in.readDouble(), -1)
} else if (b == '[') {
val depthM1 = depth - 1
if (depthM1 < 0) in.decodeError("depth limit exceeded")
val isEmpty = in.isNextToken(']')
val arrV = v.visitArray(if (isEmpty) 0 else -1, -1).narrow
if (!isEmpty) {
in.rollbackToken()
while ({
arrV.visitValue(decode(in, depthM1, arrV.subVisitor), -1)
in.isNextToken(',')
}) ()
if (!in.isCurrentToken(']')) in.arrayEndOrCommaError()
}
arrV.visitEnd(-1)
} else if (b == '{') {
val depthM1 = depth - 1
if (depthM1 < 0) in.decodeError("depth limit exceeded")
val isEmpty = in.isNextToken('}')
val objV = v.visitObject(if (isEmpty) 0 else -1, jsonableKeys = true, -1).narrow
if (!isEmpty) {
in.rollbackToken()
while ( {
val key = in.readKeyAsString()
objV.visitKeyValue(objV.visitKey(-1).visitString(key, -1))
objV.visitValue(decode(in, depthM1, objV.subVisitor), -1)
in.isNextToken(',')
}) ()
if (!in.isCurrentToken('}')) in.objectEndOrCommaError()
}
objV.visitEnd(-1)
} else in.readNullOrError(v.visitNull(-1), "expected JSON value")
}
}
final class Encoder[I](implicit t: Transformer[I]) extends JsonValueCodec[I] {
override def decodeValue(in: JsonReader, default: I): I =
throw new UnsupportedOperationException("Codec only supports encoding")
override def encodeValue(x: I, out: JsonWriter): Unit = {
val visitor = new Visitor[Any, JsonWriter] {
private[this] val objVisitor = new ObjVisitor[Any, JsonWriter] {
override def visitKey(index: Int): Visitor[?, ?] = StringVisitor
override def visitKeyValue(v: Any): Unit = out.writeKey(v.toString)
override def subVisitor: Visitor[?, ?] = visitor
override def visitValue(v: Any, index: Int): Unit = ()
override def visitEnd(index: Int): JsonWriter = {
out.writeObjectEnd()
out
}
}
private[this] val arrVisitor = new ArrVisitor[Any, JsonWriter] {
override def subVisitor: Visitor[?, ?] = visitor
override def visitValue(v: Any, index: Int): Unit = ()
override def visitEnd(index: Int): JsonWriter = {
out.writeArrayEnd()
out
}
}
override def visitNull(index: Int): JsonWriter = {
out.writeNull()
out
}
override def visitFalse(index: Int): JsonWriter = {
out.writeVal(false)
out
}
override def visitTrue(index: Int): JsonWriter = {
out.writeVal(true)
out
}
override def visitInt64(i: Long, index: Int): JsonWriter = {
out.writeVal(i)
out
}
override def visitFloat64(d: Double, index: Int): JsonWriter = {
out.writeVal(d)
out
}
override def visitFloat64String(s: String, index: Int): JsonWriter = {
out.writeNonEscapedAsciiVal(s)
out
}
override def visitFloat64StringParts(s: CharSequence, decIndex: Int, expIndex: Int, index: Int): JsonWriter = {
out.writeNonEscapedAsciiVal(s.toString)
out
}
override def visitString(s: CharSequence, index: Int): JsonWriter = {
out.writeVal(s.toString)
out
}
override def visitBinary(bytes: Array[Byte], offset: Int, len: Int, index: Int): JsonWriter = {
val trimmed =
if (offset == 0 && bytes.length == len) bytes
else bytes.slice(offset, offset + len)
out.writeBase64Val(trimmed, doPadding = true)
out
}
override def visitArray(length: Int, index: Int): ArrVisitor[Any, JsonWriter] = {
out.writeArrayStart()
arrVisitor
}
override def visitObject(length: Int, jsonableKeys: Boolean, index: Int): ObjVisitor[Any, JsonWriter] = {
out.writeObjectStart()
objVisitor
}
override def visitFloat32(d: Float, index: Int): JsonWriter = {
out.writeVal(d)
out
}
override def visitInt32(i: Int, index: Int): JsonWriter = {
out.writeVal(i)
out
}
override def visitUInt64(i: Long, index: Int): JsonWriter = {
out.writeVal(i)
out
}
override def visitChar(s: Char, index: Int): JsonWriter = {
out.writeVal(s)
out
}
override def visitExt(tag: Byte, bytes: Array[Byte], offset: Int, len: Int, index: Int): JsonWriter =
visitBinary(bytes, offset, len, index)
}
t.transform(x, visitor)
}
override def nullValue: I = null.asInstanceOf[I]
} |
Right! I implemented the reading of discrete I do suppose the next performance gain would be for the reader to support |
Hey @plokhotnyuk I intended to open a Discussions question, but it's seemingly not enabled.
I implemented a codec for upickle's Visitor. I wanted to see if you had interest in adopting it I'd gladly contribute it.
See:
Codec
JsonWriter and En/Decoder
The text was updated successfully, but these errors were encountered: