JsoniterPrism

dev.constructive.eo.jsoniter.JsoniterPrism
object JsoniterPrism

Read-write optic over a JSON byte buffer. Resolves a JSONPath subset against Array[Byte], decodes the focused slice via JsonValueCodec[A] on read, encodes-and-splices on write. No runtime AST.

Carrier: dev.constructive.eo.data.Affine. Shape Optic[Array[Byte], Array[Byte], A, A, Affine]:

  • type X = (Array[Byte], (Array[Byte], Int, Int))
    • Fst[X] = Array[Byte] — original source bytes (Miss carries this for pass-through)
    • Snd[X] = (Array[Byte], Int, Int) — bytes + the focused span (Hit carries this; phase-2 splice writes use the span to memcpy the new encoding back in)
  • to: Array[Byte] => Affine[X, A] runs the path scanner; on hit, decodes the slice via readFromSubArray and packs Hit(snd = (bytes, start, end), b = decoded). On miss (path doesn't resolve, decode throws), packs Miss(fst = bytes) for pass-through.
  • from: Affine[X, A] => Array[Byte] (phase 2) — Hit encodes h.b via writeToArray and splices into the source bytes at the recorded [start, end) span. Three arraycopys into a fresh buffer; cost is O(src.length). Miss returns the original bytes unchanged.

Composability: the standard cats-eo extension methods on Optic[..., Affine] light up automatically — .foldMap, .modify, .replace, .andThen, etc. No new Composer / AssociativeFunctor needed; reuses the existing Affine machinery.

'''Laws & preconditions''' (normative):

  • The Optional laws hold '''up to canonical re-encoding of the focused slice''': modify(identity) re-encodes the focus through the codec, normalising number forms (1e01.0), escapes, and key order INSIDE the span. Bytes outside the span (whitespace, sibling formatting) are never touched. Byte-for-byte identity holds only for focus slices already in the codec's canonical form.
  • '''Writes require a decodable current focus''': the Affine to decodes eagerly, so .replace onto a span whose current value doesn't decode as A is a Miss pass-through — template placeholders must be VALID encodings of the focus type.

Attributes

Source
JsoniterPrism.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, Affine]

Build a read-write Prism over a JSON byte buffer at the given JSONPath.

Build a read-write Prism over a JSON byte buffer at the given JSONPath.

Throws IllegalArgumentException if the path string is not parseable. Path syntax: $, dotted field names ($.foo.bar), array indices ($[0]). See PathParser for the full grammar.

Attributes

Example
import com.github.plokhotnyuk.jsoniter_scala.macros.JsonCodecMaker
given codec: JsonValueCodec[Long] = JsonCodecMaker.make
val idP = JsoniterPrism[Long]("$.payload.user.id")
val bytes: Array[Byte] = ...
idP.foldMap(identity)(bytes)  // Long, no AST allocation
Source
JsoniterPrism.scala
def fromSteps[A](steps: List[PathStep])(using codec: JsonValueCodec[A]): Optic[Array[Byte], Array[Byte], A, A, Affine]

Build a Prism from an already-parsed step list — useful for reusing a parsed path across multiple optics, or when constructing programmatically.

Build a Prism from an already-parsed step list — useful for reusing a parsed path across multiple optics, or when constructing programmatically.

Attributes

Source
JsoniterPrism.scala