dev.constructive.eo.generics

Auto-derivation entry points for EO optics — Scala 3 quoted macros for Lens / Prism / Plated. Scaffolds on Mateusz Kubuszok's hearth macro-commons library.

Derived setters call the primary constructor directly (new S(...), never .copy) — uniform across case classes and enum cases, but the emitted call carries no outer accessor, so derive only for '''top-level''' ADTs, not types nested inside a class.

Attributes

Members list

Grouped members

Constructors

Derive a lens from one or more case-class field accessors. Two-step partial application — lens[Person](_.age) — pins S while letting the focus type be inferred. Works on any N-field case class or Scala 3 enum case (emits new S(…), doesn't require .copy).

Derive a lens from one or more case-class field accessors. Two-step partial application — lens[Person](_.age) — pins S while letting the focus type be inferred. Works on any N-field case class or Scala 3 enum case (emits new S(…), doesn't require .copy).

The return type is arity-and-cover driven:

  • partial cover, one selector → SimpleLens[S, A, XA] with XA the NamedTuple complement of the non-focused fields;
  • partial cover, N ≥ 2 selectors → SimpleLens with NamedTuple focus in '''selector''' order and NamedTuple complement in '''declaration''' order among non-focused fields;
  • full cover at any arity (including lens[Wrapper](_.value) on a 1-field case class) → BijectionIso[S, S, NT, NT].

Selectors must be single-field accessors — nested paths (_.a.b), duplicates, and unknown fields are compile errors.

Attributes

Example
case class Person(name: String, age: Int)
val ageLens = lens[Person](_.age)
val asTuple = lens[Person](_.name, _.age)  // full cover → BijectionIso
Source
package.scala
inline def plate[S]: Plated[S]

Derive a dev.constructive.eo.optics.Plated for a recursive ADT — the immediate same-typed-children self-traversal that powers transform / rewrite / children / universe. Focuses every field whose type is exactly S across all cases; works on enums, sealed hierarchies, and recursive case classes.

Derive a dev.constructive.eo.optics.Plated for a recursive ADT — the immediate same-typed-children self-traversal that powers transform / rewrite / children / universe. Focuses every field whose type is exactly S across all cases; works on enums, sealed hierarchies, and recursive case classes.

Attributes

Example
enum Expr:
 case Var(name: String)
 case App(f: Expr, x: Expr)
 case Lam(bind: String, body: Expr)
given Plated[Expr] = plate[Expr]
Plated.transform { case Expr.Var(n) => Expr.Var(n.toUpperCase); case e => e }(tree)
Source
package.scala
inline def prism[S, A <: S]: Optic[S, S, A, A, Either]

Derive a Prism focusing on one variant of a sum type. Works on Scala 3 enums, sealed traits, and union types via Hearth's Enum.parse[S]. A must be a '''direct child''' of S — anything else is a compile error listing the known children.

Derive a Prism focusing on one variant of a sum type. Works on Scala 3 enums, sealed traits, and union types via Hearth's Enum.parse[S]. A must be a '''direct child''' of S — anything else is a compile error listing the known children.

Attributes

Example
enum Shape:
 case Circle(r: Double)
 case Square(s: Double)
val circleP = prism[Shape, Shape.Circle]
val intP    = prism[Int | String, Int]
Source
package.scala

Type members

Classlikes

object LensMacro

Compile-time derivation of a Lens (or Iso on full coverage) from one or more case-class accessors.

Compile-time derivation of a Lens (or Iso on full coverage) from one or more case-class accessors.

case class Person(age: Int, name: String)

val ageL = lens[Person](_.age)                // SimpleLens, complement = remaining fields NT
val asTuple = lens[Person](_.name, _.age)     // BijectionIso (full cover)
  • Single-selector, partial cover → SimpleLens[S, A, XA] with XA the structural complement (gives transform / place / transfer for free).
  • Multi-selector, partial cover → SimpleLens with NamedTuple focus (SELECTOR order) and NamedTuple complement (DECLARATION order among non-focused fields).
  • Full cover at any arity → BijectionIso[S, S, NT, NT].

Constructor synthesis routes through Hearth's CaseClass.parse[S] + construct[Id], so parameterised / recursive types and Scala 3 enum cases (which lack .copy) work uniformly via new S(...).

Attributes

Source
LensMacro.scala
Supertypes
class Object
trait Matchable
class Any
Self type
LensMacro.type

Quote-context selector-AST helpers shared between LensMacro and the JsonPrismMacro / AvroPrismMacro cursor macros. All parse single-field selector lambdas (_.fieldName) and validate non-duplicates; the per-macro divergence is just the error-message tag.

Quote-context selector-AST helpers shared between LensMacro and the JsonPrismMacro / AvroPrismMacro cursor macros. All parse single-field selector lambdas (_.fieldName) and validate non-duplicates; the per-macro divergence is just the error-message tag.

Attributes

Source
MacroSelectors.scala
Supertypes
class Object
trait Matchable
class Any
Self type
final class PartiallyAppliedLens[S]

Partially-applied witness produced by lens.

Partially-applied witness produced by lens.

Attributes

Source
package.scala
Supertypes
class Object
trait Matchable
class Any
object PlateMacro

Compile-time derivation of a dev.constructive.eo.optics.Plated for a recursive ADT S.

Compile-time derivation of a dev.constructive.eo.optics.Plated for a recursive ADT S.

The derived plate focuses the immediate same-typed children of every case: each field whose declared type is exactly S (the "exact self-type" rule — List[S], Option[S], tuples of S, etc. are not descended in this version; their elements are leftover skeleton). For

enum Expr:
 case Var(name: String)        // 0 children
 case App(f: Expr, x: Expr)    // 2 children
 case Lam(bind: String, body: Expr) // 1 child (bind:String is skeleton)

plate[Expr] gathers App's f/x and Lam's body, leaving Var.name / Lam.bind untouched. Works on Scala 3 enums, sealed hierarchies (via Hearth's Enum.parse), and plain recursive case classes (via CaseClass.parse). Reconstruction routes through CaseClass.construct[Id] (new V(...), never .copy), so enum cases reassemble fine.

children reads the self-typed fields in declaration order; rebuild swaps them back by the same declaration-order index, so the two agree without relying on construct's call order.

Attributes

Source
PlateMacro.scala
Supertypes
class Object
trait Matchable
class Any
Self type
PlateMacro.type
object PrismMacro

Compile-time derivation of a Prism from a sum / enum / union type S to a direct child A a: S. Macro-time validation checks A is a direct child of S.

Compile-time derivation of a Prism from a sum / enum / union type S to a direct child A a: S. Macro-time validation checks A is a direct child of S.

enum Shape:
 case Circle(radius: Double)
 case Square(side: Double)
val circleP = prism[Shape, Shape.Circle]
val intP    = prism[Int | String, Int]

Attributes

Source
PrismMacro.scala
Supertypes
class Object
trait Matchable
class Any
Self type
PrismMacro.type