1- abstract class Lens [S , T ] {
1+ trait Lens [S , T ] {
22 def get (s : S ): T
33 def set (t : T , s : S ) : S
44}
@@ -19,15 +19,15 @@ object Lens {
1919
2020
2121 // obj.copy(a = obj.a.copy(b = a.b.copy(c = v)))
22- def setterBody (obj : Term , value : Term , fields : List [String ]): Term = {
22+ def setterBody (obj : Term , value : Term , parts : List [String ]): Term = {
2323 // o.copy(field = value)
2424 def helper (obj : Term , value : Term , field : String ): Term =
2525 Term .Select .overloaded(obj, " copy" , Nil , Term .NamedArg (field, value) :: Nil )
2626
27- fields match {
27+ parts match {
2828 case field :: Nil => helper(obj, value, field)
29- case field :: fields =>
30- helper(obj, setterBody(Term .Select .unique(obj, field), value, fields ), field)
29+ case field :: parts =>
30+ helper(obj, setterBody(Term .Select .unique(obj, field), value, parts ), field)
3131 }
3232 }
3333
@@ -56,9 +56,9 @@ object Lens {
5656
5757 // exception: getter.unseal.underlyingArgument
5858 getter.unseal match {
59- case Function (param :: Nil , Path (o, fields )) if o.symbol == param.symbol =>
59+ case Function (param :: Nil , Path (o, parts )) if o.symbol == param.symbol =>
6060 ' {
61- val setter = (t : T ) => (s : S ) => ~ setterBody(('(s)).unseal, ( ' (t)).unseal, fields ).seal[S ]
61+ val setter = (t : T ) => (s : S ) => ~ setterBody(('(s)).unseal, ( ' (t)).unseal, parts ).seal[S ]
6262 apply(~ getter)(setter)
6363 }
6464 case _ =>
@@ -79,4 +79,93 @@ object GenLens {
7979 class MkGenLens [S ] {
8080 inline def apply [T ](get : => (S => T )): Lens [S , T ] = ~ Lens .impl('(get))
8181 }
82+ }
83+
84+ trait Iso [S , A ] {
85+ def from (a : A ): S
86+ def to (s : S ): A
87+ }
88+
89+ object Iso {
90+ def apply [S , A ](_from : A => S )(_to : S => A ): Iso [S , A ] = new Iso {
91+ def from (a : A ): S = _from(a)
92+ def to (s : S ): A = _to(s)
93+ }
94+
95+ def impl [S : Type , A : Type ](implicit refl : Reflection ): Expr [Iso [S , A ]] = {
96+ import refl ._
97+ import util ._
98+ import quoted .Toolbox .Default ._
99+
100+ val tpS = typeOf[S ]
101+ val tpA = typeOf[A ]
102+
103+ // 1. S must be a case class
104+ // 2. A must be a tuple
105+ // 3. The parameters of S must match A
106+ if (tpS.classSymbol.flatMap(cls => if (cls.flags.is(Flags .Case )) Some (true ) else None ).isEmpty)
107+ throw new QuoteError (" Only support generation for case classes" )
108+
109+ val cls = tpS.classSymbol.get
110+
111+ val companion = tpS match {
112+ case Type .SymRef (sym, prefix) => Type .TermRef (prefix, sym.name)
113+ case Type .TypeRef (name, prefix) => Type .TermRef (prefix, name)
114+ }
115+
116+ if (cls.caseFields.size != 1 )
117+ throw new QuoteError (" Use GenIso.fields for case classes more than one parameter" )
118+
119+ val fieldTp = tpS.memberType(cls.caseFields.head)
120+ if (! (fieldTp =:= tpA))
121+ throw new QuoteError (s " The type of case class field $fieldTp does not match $tpA" )
122+
123+ ' {
124+ // (p: S) => p._1
125+ val to = (p : S ) => ~ { Term .Select .unique(('(p)).unseal, "_1").seal[A] }
126+ // (p: A) => S(p)
127+ val from = (p : A ) => ~ { Term .Select .overloaded(Term .Ident (companion), " apply" , Nil , ('(p)).unseal :: Nil).seal[S] }
128+ apply(from)(to)
129+ }
130+ }
131+ }
132+
133+ object GenIso {
134+ /**
135+ * GenIso[Person, String] ~~>
136+ *
137+ * Iso[Person, String]
138+ * { p => p._1 }
139+ * { p => Person(p) }
140+ */
141+ inline def apply [S , A ]: Iso [S , A ] = ~ Iso .impl[S , A ]
142+
143+ inline def fields [S , A ]: Iso [S , A ] = ???
144+ inline def unit [S ]: Iso [S , Unit ] = ???
145+ }
146+
147+ trait Prism [S , A ] {
148+ def getOption (s : S ): Option [A ]
149+ def apply (a : A ): S
150+ }
151+
152+ object Prism {
153+ def apply [S , A ](getOpt : S => Option [A ])(app : A => S ): Prism [S , A ] = new Prism {
154+ def getOption (s : S ): Option [A ] = getOpt(s)
155+ def apply (a : A ): S = app(a)
156+ }
157+
158+ def impl [S : Type , A : Type ](implicit refl : Reflection ): Expr [Prism [S , A ]] = ???
159+ }
160+
161+ object GenPrism {
162+ /**
163+ * GenPrism[Json, JStr] ~~>
164+ *
165+ * Prism[Json, JStr]{
166+ * case JStr(v) => Some(v)
167+ * case _ => None
168+ * }(jstr => jstr)
169+ */
170+ inline def apply [S , A ]: Prism [S , A ] = ~ Prism .impl[S , A ]
82171}
0 commit comments