JsonPathScanner

dev.constructive.eo.jsoniter.JsonPathScanner

Hand-rolled JSON byte scanner. Resolves a PathStep list against a JSON document in an Array[Byte] — the whole array, or a range [from, until) of it — and returns the byte span [start, end) of the resolved value, or -1 for the start if the path doesn't match. Every helper threads the range's until as its bound, so a ranged scan never reads past it.

Why hand-rolled rather than reusing jsoniter-scala-core's JsonReader: the scanner only needs to skip-with-backtracking, not decode. Embedding JsonReader would force us to thread its mark / rollback state through every call site, and its API doesn't expose byte offsets directly. 100-ish LoC of dispatch is cheaper than the impedance mismatch.

The scanner is permissive about whitespace (skips it everywhere) and strict about structure (unbalanced quotes / brackets short-circuit to "miss"). It does NOT validate the document; an invalid JSON whose path step happens to resolve will return a span — decoding is the layer that surfaces validity failures.

Attributes

Source
JsonPathScanner.scala
Graph
Supertypes
class Object
trait Matchable
class Any
Self type

Members list

Grouped members

Scanner

final case class Span(start: Int, end: Int)

Result of a scan: start >= 0 means hit, start == -1 means miss. Avoids Option allocation on the hot path. End is bytes.length on miss.

Result of a scan: start >= 0 means hit, start == -1 means miss. Avoids Option allocation on the hot path. End is bytes.length on miss.

Attributes

Source
JsonPathScanner.scala
Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
def find(bytes: Array[Byte], path: List[PathStep]): Span

Resolve path against bytes. Returns the byte span of the focused value (start, end), or Miss if any step fails to match. Rejects PathStep.Wildcard — wildcards produce 0-or-many results and don't fit a single-Span return; route them through findAll. The whole-array case of the ranged overload below.

Resolve path against bytes. Returns the byte span of the focused value (start, end), or Miss if any step fails to match. Rejects PathStep.Wildcard — wildcards produce 0-or-many results and don't fit a single-Span return; route them through findAll. The whole-array case of the ranged overload below.

Attributes

Source
JsonPathScanner.scala
def find(bytes: Array[Byte], from: Int, until: Int, path: List[PathStep]): Span

Resolve path against the document in bytes[from, until), reading nothing outside that range: a value that runs past until is malformed, exactly as one that runs past the end of an array of its own. Spans are absolute positions in bytes. The caller guarantees 0 <= from <= until <= bytes.length (JsonSlice checks it once, at construction).

Resolve path against the document in bytes[from, until), reading nothing outside that range: a value that runs past until is malformed, exactly as one that runs past the end of an array of its own. Spans are absolute positions in bytes. The caller guarantees 0 <= from <= until <= bytes.length (JsonSlice checks it once, at construction).

Attributes

Source
JsonPathScanner.scala
def findAll(bytes: Array[Byte], path: List[PathStep]): List[Span]

Resolve path against bytes, returning every span that matches. Wildcard steps fan out across array elements; a path with no wildcards returns 0 or 1 spans. Spans are returned in document order. On any structural mismatch (wrong context for a step, malformed JSON), the sub-tree is silently skipped — the caller sees fewer spans, not an error. The whole-array case of the ranged overload below.

Resolve path against bytes, returning every span that matches. Wildcard steps fan out across array elements; a path with no wildcards returns 0 or 1 spans. Spans are returned in document order. On any structural mismatch (wrong context for a step, malformed JSON), the sub-tree is silently skipped — the caller sees fewer spans, not an error. The whole-array case of the ranged overload below.

Attributes

Source
JsonPathScanner.scala
def findAll(bytes: Array[Byte], from: Int, until: Int, path: List[PathStep]): List[Span]

findAll over the document in bytes[from, until), reading nothing outside that range. Spans are absolute positions in bytes; same precondition on the range as the ranged find.

findAll over the document in bytes[from, until), reading nothing outside that range. Spans are absolute positions in bytes; same precondition on the range as the ranged find.

Attributes

Source
JsonPathScanner.scala

Value members

Concrete fields

val Miss: Span

The single sentinel "miss" Span.

The single sentinel "miss" Span.

Attributes

Source
JsonPathScanner.scala