JsoniterInPlacePrism

dev.constructive.eo.jsoniter.JsoniterInPlacePrism

A JsoniterPrism that reads its document '''in place''': the source is a JsonSlice, a range of a larger byte array, scanned and decoded where it lies. Made by prism.inPlace, or at the root by JsoniterPrism.inPlace to drill from there with the same .field / .at / .each / Dynamic surface (JsoniterPrismPath). Same path, same codec, and the same '''Laws & preconditions''' as the whole-array prism, with slices compared by content.

'''No copy is made.''' The optic reads the caller's array where it lies, and .raw focuses a view of it. So:

  • '''Don't mutate the array''' while the slice, or anything read from it (a .raw focus), is in use: the optic reads the bytes as they are when it runs.
  • A slice, and any slice focus, keeps the '''whole''' underlying array reachable, however few bytes it covers. Call JsonSlice.toArray for anything kept long-term.
  • '''Writes never mutate the source.''' A write that splices (a Hit) returns a slice over a '''fresh''' array holding only the slice's bytes — array[offset, start) ++ encoded ++ array[end, until) — at offset 0; the bytes around the slice are neither copied nor touched. A write that changes nothing (a Miss) hands back the input slice itself.

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

  • type X = (JsonSlice, (JsonSlice, Int, Int)) — Miss carries the source slice for pass-through; Hit carries it with the focused span's ABSOLUTE [start, end) in its array.
  • to scans slice.array from slice.offset to slice.until and decodes the span via readFromSubArray. Nothing outside the slice is read, and nothing is copied.
  • from on a Hit encodes the new focus and splices it in, as above.

The whole-array JsoniterPrism runs the same scan and splice over (0, length), so a slice reads and writes exactly like the same bytes copied out.

Attributes

Source
JsoniterPrism.scala
Graph
Supertypes
trait Dynamic
trait Optic[JsonSlice, JsonSlice, A, A, Affine]
trait Serializable
class Object
trait Matchable
class Any
Show all

Members list

Grouped members

Operations

inline def cross[C, D](o: Optic[JsonSlice, JsonSlice, C, D, Affine])(using Accessor[Affine], ReverseAccessor[Affine]): Optic[A, A, C, D, Affine]

Build-then-observe across the build-output ⇄ read-input seam, preserving structure, on a shared carrier F. Flip self (it must be reversible — Accessor[F] and ReverseAccessor[F], i.e. an Iso or Review over Direct) so it reads T from B, then andThen that under the same carrier. The result is the full Optic[B, A, C, D, F], not a collapsed getter: its read capability follows the carrier (.get for Direct), and self's read focus A survives as the composite's write-back focus.

Build-then-observe across the build-output ⇄ read-input seam, preserving structure, on a shared carrier F. Flip self (it must be reversible — Accessor[F] and ReverseAccessor[F], i.e. an Iso or Review over Direct) so it reads T from B, then andThen that under the same carrier. The result is the full Optic[B, A, C, D, F], not a collapsed getter: its read capability follows the carrier (.get for Direct), and self's read focus A survives as the composite's write-back focus.

This is exactly self.reverse.andThen(that). The motivating case is ana.cross(cata): a Review (the unfold) crossed with a getter on the built S (the fold) — a (materializing) hylomorphism whose .get reads the folded value. When that sits on a different carrier (a Prism, a Fold, …), the cross-carrier cross overload below is selected instead.

Seam: that's source is self's T and its back-type is self's S.

Attributes

Inherited from:
Optic
Source
Optic.scala

Type members

Types

type X = (JsonSlice, (JsonSlice, Int, Int))

Existential leftover carried alongside the focus — the type-level witness the carrier uses to rebuild T. Concrete at construction (Lens.apply sets X = S, Prism.apply sets X = S, …) and abstract when the optic is bound to Optic[…, F] without refinement.

Existential leftover carried alongside the focus — the type-level witness the carrier uses to rebuild T. Concrete at construction (Lens.apply sets X = S, Prism.apply sets X = S, …) and abstract when the optic is bound to Optic[…, F] without refinement.

Attributes

Source
JsoniterPrism.scala

Value members

Concrete methods

def from(aff: Affine[X, A]): JsonSlice

Close the carrier: given a modified focus B (and the leftover X already inside the F), reassemble the result T.

Close the carrier: given a modified focus B (and the leftover X already inside the F), reassemble the result T.

Attributes

Source
JsoniterPrism.scala

Re-focus on the '''raw encoded span''', as a JsonSlice: same path, same scan, but the focus is the focused value's own JSON bytes — a '''view''' of them where they lie in the source array, not a copy (the whole-array JsoniterPrism.raw copies them out). No typed decode runs. The span is checked to be one well-formed JSON value (jsoniter-scala's skip, which allocates nothing), so a malformed one misses, as it does for JsoniterPrism.raw.

Re-focus on the '''raw encoded span''', as a JsonSlice: same path, same scan, but the focus is the focused value's own JSON bytes — a '''view''' of them where they lie in the source array, not a copy (the whole-array JsoniterPrism.raw copies them out). No typed decode runs. The span is checked to be one well-formed JSON value (jsoniter-scala's skip, which allocates nothing), so a malformed one misses, as it does for JsoniterPrism.raw.

The focus is a slice of the '''source''' array, under the rules above: don't mutate the array while it's in use, and it keeps the whole array reachable (.toArray to keep it). It is the source of further in-place optics, through ordinary andThen: JsoniterPrism.inPlace[Issue].field(_.detail).raw.andThen(severityP), with severityP = JsoniterPrism.inPlace[Detail].field(_.severity), is one Optic[JsonSlice, JsonSlice, Severity, Severity, Affine], nothing copied on the way down.

'''Writing''' through it splices the new focus's bytes '''verbatim''' — no re-encoding and no validation, as JsoniterPrism.raw writes — into a fresh array, by the write rule above: neither the source array nor the new focus's own array is changed. A composed write ((raw andThen severityP).replace(s)) re-encodes only the leaf: the inner prism splices it into a fresh copy of the focused span, and this one splices that into a fresh copy of the document.

Attributes

Source
JsoniterPrism.scala

Encode a standalone, as a slice over an array of its own. Lawful only for the ROOT prism, as JsoniterPrism.reverseGet is.

Encode a standalone, as a slice over an array of its own. Lawful only for the ROOT prism, as JsoniterPrism.reverseGet is.

Attributes

Source
JsoniterPrism.scala
def to(slice: JsonSlice): Affine[X, A]

Push the source S into the carrier, extracting the focus A and packing the leftover X. Paired with from to reconstruct T.

Push the source S into the carrier, extracting the focus A and packing the leftover X. Paired with from to reconstruct T.

Attributes

Source
JsoniterPrism.scala

Inherited methods

def andThen[C, IB, G[_, _]](inner: Optic[A, Unit, C, IB, G])(using rc: ReadCompose[Affine, G]): rc.Out[JsonSlice, C]

ANY outer ∘ read-only inner — the inner is honestly one-way (T = Unit: a Getter, AffineFold, or Fold), so only the two READ sides matter and the composite collapses to the read-only join of their strengths via compose.ReadCompose (Getter / PickFold / ForgetFold).

ANY outer ∘ read-only inner — the inner is honestly one-way (T = Unit: a Getter, AffineFold, or Fold), so only the two READ sides matter and the composite collapses to the read-only join of their strengths via compose.ReadCompose (Getter / PickFold / ForgetFold).

A trait member (not an extension in the companion) deliberately: once a receiver is statically one of the fused concrete classes, its andThen member overloads enter resolution and Scala 3 never falls back to extension methods when they all fail — the collapse must be in the member overload set to be reachable without an expected-type ascription.

Only the inner's T is pinned to Unit; its B stays free (IB) even though read-only inners always have B = Unit. That keeps this overload strictly LESS specific than the same-carrier andThen above (which accepts every argument this one does whenever B = Unit at the receiver), so a same-carrier read-only ∘ read-only call resolves unambiguously to the AssociativeFunctor path and this one fires exactly on the cross-seam cells the generic member cannot type.

Attributes

Inherited from:
Optic
Source
Optic.scala
inline def andThen[C, D](o: Optic[A, A, C, D, Affine]): Optic[JsonSlice, JsonSlice, C, D, Affine]

Compose with another optic under the shared carrier F. Requires AssociativeFunctor[F]. Cross-carrier composition (Lens → Optional, Lens → Traversal, …) goes through the Morph-summoning overload of this same method.

Compose with another optic under the shared carrier F. Requires AssociativeFunctor[F]. Cross-carrier composition (Lens → Optional, Lens → Traversal, …) goes through the Morph-summoning overload of this same method.

Attributes

Example
case class Address(street: String)
case class Person(address: Address)
val streetLens = lens[Person](_.address).andThen(lens[Address](_.street))
Inherited from:
Optic
Source
Optic.scala
transparent inline def selectDynamic(inline name: String): Any

Dynamic field sugar — JsoniterPrism[Person].name lowers to JsoniterPrism[Person].field(_.name). Compile-time checked against A's case fields; the field's JsonValueCodec is summoned at the call site.

Dynamic field sugar — JsoniterPrism[Person].name lowers to JsoniterPrism[Person].field(_.name). Compile-time checked against A's case fields; the field's JsonValueCodec is summoned at the call site.

Attributes

Inherited from:
JsoniterPath
Source
JsoniterPath.scala