JsonPathScanner

dev.constructive.eo.jsoniter.JsonPathScanner

Hand-rolled JSON byte scanner. Resolves a PathStep list against an Array[Byte] JSON document and returns the byte span [start, end) of the resolved value, or -1 for the start if the path doesn't match.

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.

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.

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.

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.

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