-
Notifications
You must be signed in to change notification settings - Fork 149
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
Async engine for ZIO JSON #576
Comments
class Registers(registers: Array[Any])
trait AsyncDecoding[+Value] {
/**
* Resets all state of the decoding to the initial values, such that the
* decoding is equivalent to a new one. This method can be used by single-fibered
* code in order to accelerate performance and avoid re-creating decodings for
* the same type of data.
*/
def reset(): Unit
/**
* Returns the number of characters consumed. If this is equal to the length of the
* char sequence, then the full length was consumed, but no more data is desired,
* because the decoding processs is finished. On the other hand, if this is greater
* than the length of the char sequence, then the full length was consumed, and
* more data is desired. If this is less than the length of the char sequence, then
* no more data is required, and the decoding stopped short of consuming all characters
* in the char sequence. If there is an error, then an `AsyncDecodingError` is thrown.
*/
def feed(chars: CharSequence): Int
}
final case class AsyncDecodingError(message: String, path: List[String] = Nil) extends Exception(message) with NoStackTrace
trait AsyncDecoder[+Value] {
def unsafeNewDecoding(index: Int, registers: Registers): AsyncDecoding[Value]
}
object AsyncDecoder {
val boolean: AsyncDecoder[Boolean] =
(index: Int, registers: Registers) =>
new AsyncDecoding[Boolean] {
var state: Int = 0
val BranchMask = 0x3
val BranchBitLen = 2
def branch(): Int = (state & BranchMask)
def position(): Int = (state >> BranchBitLen)
val Undecided = 1
val IsTrue = 2
val IsFalse = 3
def setBranch(branch: Int): Unit = state = (state & ~BranchMask) | branch
def setPosition(int: Int): Unit = state = (state & BranchMask) | (int << BranchBitLen)
def setBranchAndPosition(branch: Int, pos: Int): Unit = state = branch | (pos << BranchBitLen)
// 't' 'r' 'u' 'e'
// 'f' 'a' 'l' 's' 'e'
def reset(): Unit = state = 0
def feed(chars: CharSequence): Int =
if (chars.length == 0) ???
else {
branch() match {
case Undecided =>
chars.charAt(0) match {
case 't' =>
// TODO: Do NOT modify the state if we can read it all at once (the happy path!)
// TODO: Read all the chars, or pause when we get as far as we can:
setBranchAndPosition(IsTrue, 1)
???
case 'f' =>
// TODO: Do NOT modify the state if we can read it all at once (the happy path!)
// TODO: Read all the chars, or pause when we get as far as we can:
setBranchAndPosition(IsFalse, 1)
???
case _ => throw AsyncDecodingError("""Expected "true" or "false" boolean literal""")
}
case IsTrue =>
val curPos = position()
if (curPos == 4) registers.registers(index) = true
???
case IsFalse =>
val curPos = position()
???
}
}
}
} |
I'll take it |
@jkobejs Awesome! Please make sure to target the |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Given the Loom is still a ways out, it can make sense to investigate an async engine for JSON to see if we can achieve performance in the ballpark of the sync engine in the happy path.
Such an async engine would be push-based rather than _pull-based. This means that instead of pulling new characters from a
Reader
, it would be pushed characters a block at a time.A push-based engine could adopt parallel parsing. Parallel parsing is required for fallback, but also for parsing multiple fields at the same time.
TODO
The text was updated successfully, but these errors were encountered: