JsoniterTraversal

dev.constructive.eo.jsoniter.JsoniterTraversal

Read-WRITE Traversal over JSON byte buffers. Resolves a wildcard-bearing JSONPath against Array[Byte], decodes each matched span via JsonValueCodec[A] on read, and encodes-and- splices every focus back in one pass on write. No runtime AST.

Carrier: MultiFocus[PSVec] — the same carrier Traversal.each uses, peer to all the classical Traversal idioms. The choice over MultiFocus[List] matters for downstream composition: JsoniterTraversal[A].andThen(Traversal.each[List, A]) and similar same-carrier chains work via the existing mfAssocPSVec AssociativeFunctor instance, with zero-copy per-element reassembly. A List-carrier traversal would force a Composer hop or a manual .modify rebuild.

  • type X = (Array[Byte], List[JsonPathScanner.Span]) — original bytes + each KEPT focus's span, 1:1 aligned with the foci (spans whose decode throws are dropped TOGETHER with their focus, so the write side can trust the pairing).
  • to: Array[Byte] => (X, PSVec[A]) — runs JsonPathScanner.findAll, decodes every span via the codec into a single Array[AnyRef] allocation, wraps it as a PSVec. Spans whose decode throws are silently dropped (matches the read semantic "fold the focuses that exist") — and stay byte-untouched on write.
  • from: ((X, PSVec[A])) => Array[Byte] — encodes each focus via writeToArray and splices all spans back in a single pass (segments between spans are arraycopyd verbatim). A span↔foci length mismatch (an aggregate from after a shape-changing carrier op) passes the original bytes through unchanged, as does an empty focus set.

Composability: standard cats-eo extensions on Optic[..., MultiFocus[PSVec]] light up automatically via mfFold[PSVec], mfFunctor[PSVec], mfAssocPSVec, etc. — .foldMap, .modify, .headOption, .length, .exists, .modifyA, same-carrier .andThen all work without anything new shipping in this module. Mirrors dev.constructive.eo.avro.AvroTraversal's byte-carried write semantics. JsoniterPrism's '''Laws & preconditions''' apply verbatim: laws hold up to canonical re-encoding of the focused slices, and writes need decodable current focuses.

Attributes

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

Members list

Grouped members

Optics

def apply[A](path: String)(using codec: JsonValueCodec[A]): Optic[Array[Byte], Array[Byte], A, A, MultiFocus[PSVec]]

Build a read-write Traversal over a JSON byte buffer at the given JSONPath. The path MAY contain [*] wildcard steps (without them, this collapses to a single-or-zero-focus Traversal that still uses the MultiFocus[PSVec] carrier — fine, just narrower).

Build a read-write Traversal over a JSON byte buffer at the given JSONPath. The path MAY contain [*] wildcard steps (without them, this collapses to a single-or-zero-focus Traversal that still uses the MultiFocus[PSVec] carrier — fine, just narrower).

Throws IllegalArgumentException if the path string is not parseable.

Attributes

Example
import com.github.plokhotnyuk.jsoniter_scala.macros.JsonCodecMaker
given codec: JsonValueCodec[Long] = JsonCodecMaker.make
val itemsT = JsoniterTraversal[Long]("$.cart.items[*]")
val bytes: Array[Byte] = ...
itemsT.foldMap(identity[Long])(bytes)  // Long — sum of all items, zero AST allocation
itemsT.modify(_ * 10)(bytes)           // Array[Byte] — every item spliced in place
Source
JsoniterTraversal.scala
def fromSteps[A](steps: List[PathStep])(using codec: JsonValueCodec[A]): Optic[Array[Byte], Array[Byte], A, A, MultiFocus[PSVec]]

Build a Traversal from an already-parsed step list.

Build a Traversal from an already-parsed step list.

Attributes

Source
JsoniterTraversal.scala