11import scala .collection .mutable
2+ import scala .annotation .tailrec
3+
4+ trait Deriving {
5+ import Deriving ._
6+
7+ protected def caseNames : Array [String ]
8+
9+ private final val separator = '\000 '
10+
11+ private def cname (ordinal : Int , idx : Int ): String = {
12+ val cnames = caseNames(ordinal)
13+ @ tailrec def separatorPos (from : Int ): Int =
14+ if (from == cnames.length || cnames(from) == separator) from
15+ else separatorPos(from + 1 )
16+ @ tailrec def findName (count : Int , idx : Int ): String =
17+ if (idx == cnames.length) " "
18+ else if (count == 0 ) cnames.substring(idx, separatorPos(idx))
19+ else findName(if (cnames(idx) == separator) count - 1 else count, idx + 1 )
20+ findName(idx, 0 )
21+ }
22+
23+ def caseName (ordinal : Int ): String = cname(ordinal, 0 )
24+ def elementName (ordinal : Int , idx : Int ) = cname(ordinal, idx + 1 )
25+ }
226
327// Generic deriving infrastructure
428object Deriving {
529
630 /** The shape of an ADT in a sum of products representation */
731 enum Shape {
8-
932 /** A sum with alternative types `Alts` */
1033 case Cases [Alts <: Tuple ]
1134
@@ -17,24 +40,41 @@ object Deriving {
1740 * @param ordinal The ordinal value of the case in the list of the ADT's cases
1841 * @param elems The elements of the case
1942 */
20- class CaseMirror [+ T ](val ordinal : Int , val elems : Product ) {
43+ class CaseMirror [+ T ](val deriving : Deriving , val ordinal : Int , val elems : Product ) {
2144
2245 /** A generic case with elements given as an array */
23- def this (ordinal : Int , elems : Array [AnyRef ]) =
24- this (ordinal, new ArrayProduct (elems))
46+ def this (deriving : Deriving , ordinal : Int , elems : Array [AnyRef ]) =
47+ this (deriving, ordinal, new ArrayProduct (elems))
2548
2649 /** A generic case with an initial empty array of `numElems` elements, to be filled in. */
27- def this (ordinal : Int , numElems : Int ) =
28- this (ordinal, new Array [AnyRef ](numElems))
50+ def this (deriving : Deriving , ordinal : Int , numElems : Int ) =
51+ this (deriving, ordinal, new Array [AnyRef ](numElems))
2952
3053 /** A generic case with no elements */
31- def this (ordinal : Int ) =
32- this (ordinal, EmptyProduct )
54+ def this (deriving : Deriving , ordinal : Int ) =
55+ this (deriving, ordinal, EmptyProduct )
3356
3457 /** The `n`'th element of this generic case */
3558 def apply (n : Int ): Any = elems.productElement(n)
59+
60+ def caseName : String = deriving.caseName(ordinal)
61+ def elementName (idx : Int ) = deriving.elementName(ordinal, idx)
62+ }
63+
64+ /** A class for mapping between an ADT value and
65+ * the case mirror that represents the value.
66+ */
67+ abstract class Reflected [T ] {
68+ def reflect (x : T ): CaseMirror [T ]
69+ def reify (c : CaseMirror [T ]): T
70+ def deriving : Deriving
3671 }
3772
73+ /** Every generic derivation starts with a typeclass instance of this type.
74+ * It informs that type `T` has shape `S` and also allows runtime reflection on `T`.
75+ */
76+ abstract class Shaped [T , S <: Shape ] extends Reflected [T ]
77+
3878 /** Helper class to turn arrays into products */
3979 private class ArrayProduct (val elems : Array [AnyRef ]) extends Product {
4080 def canEqual (that : Any ): Boolean = true
@@ -50,19 +90,6 @@ object Deriving {
5090 def productElement (n : Int ) = throw new IndexOutOfBoundsException
5191 def productArity = 0
5292 }
53-
54- /** A class for mapping between an ADT value and
55- * the generic case that represents the value
56- */
57- abstract class MirrorMapper [T ] {
58- def toMirror (x : T ): CaseMirror [T ]
59- def fromMirror (c : CaseMirror [T ]): T
60- }
61-
62- /** Every generic derivation starts with a typeclass instance of this type.
63- * It informs that type `T` has shape `S` and is backed by the extended generic mapper.
64- */
65- abstract class Shaped [T , S <: Shape ] extends MirrorMapper [T ]
6693}
6794
6895// An algebraic datatype
@@ -72,7 +99,7 @@ enum Lst[+T] // derives Eq, Pickler
7299 case Nil
73100}
74101
75- object Lst {
102+ object Lst extends Deriving {
76103 // common compiler-generated infrastructure
77104 import Deriving ._
78105
@@ -81,40 +108,47 @@ object Lst {
81108 Shape .Case [Nil .type , Unit ]
82109 )]
83110
84- val NilMirror = new CaseMirror [Nil .type ](1 )
111+ val NilMirror = new CaseMirror [Nil .type ](Lst , 1 )
85112
86113 implicit def lstShape [T ]: Shaped [Lst [T ], Shape [T ]] = new {
87- def toMirror (xs : Lst [T ]): CaseMirror [Lst [T ]] = xs match {
88- case xs : Cons [T ] => new CaseMirror [Cons [T ]](0 , xs)
114+ def reflect (xs : Lst [T ]): CaseMirror [Lst [T ]] = xs match {
115+ case xs : Cons [T ] => new CaseMirror [Cons [T ]](Lst , 0 , xs)
89116 case Nil => NilMirror
90117 }
91- def fromMirror (c : CaseMirror [Lst [T ]]): Lst [T ] = c.ordinal match {
118+ def reify (c : CaseMirror [Lst [T ]]): Lst [T ] = c.ordinal match {
92119 case 0 => Cons [T ](c(0 ).asInstanceOf , c(1 ).asInstanceOf )
93120 case 1 => Nil
94121 }
122+ def deriving = Lst
95123 }
96124
97- // two clauses that could be generated from a `derives` clause
125+ protected val caseNames = Array (" Cons\000 hd\000 tl" , " Nil" )
126+
127+ // three clauses that could be generated from a `derives` clause
98128 implicit def LstEq [T : Eq ]: Eq [Lst [T ]] = Eq .derived
99129 implicit def LstPickler [T : Pickler ]: Pickler [Lst [T ]] = Pickler .derived
130+ implicit def LstShow [T : Show ]: Show [Lst [T ]] = Show .derived
100131}
101132
102133// A simple product type
103134case class Pair [T ](x : T , y : T ) // derives Eq, Pickler
104135
105- object Pair {
136+ object Pair extends Deriving {
106137 // common compiler-generated infrastructure
107138 import Deriving ._
108139
109140 type Shape [T ] = Shape .Case [Pair [T ], (T , T )]
110141
111142 implicit def pairShape [T ]: Shaped [Pair [T ], Shape [T ]] = new {
112- def toMirror (xy : Pair [T ]) =
113- new CaseMirror [Pair [T ]](0 , xy)
114- def fromMirror (c : CaseMirror [Pair [T ]]): Pair [T ] =
143+ def reflect (xy : Pair [T ]) =
144+ new CaseMirror [Pair [T ]](Pair , 0 , xy)
145+ def reify (c : CaseMirror [Pair [T ]]): Pair [T ] =
115146 Pair (c(0 ).asInstanceOf , c(1 ).asInstanceOf )
147+ def deriving = Pair
116148 }
117149
150+ protected val caseNames = Array (" Pair\000 x\000 y" )
151+
118152 // two clauses that could be generated from a `derives` clause
119153 implicit def PairEq [T : Eq ]: Eq [Pair [T ]] = Eq .derived
120154 implicit def PairPickler [T : Pickler ]: Pickler [Pair [T ]] = Pickler .derived
@@ -142,25 +176,25 @@ object Eq {
142176 true
143177 }
144178
145- inline def eqlCase [T , Elems <: Tuple ](mapper : MirrorMapper [T ], x : T , y : T ) =
146- eqlElems[Elems ](mapper.toMirror (x), mapper.toMirror (y), 0 )
179+ inline def eqlCase [T , Elems <: Tuple ](r : Reflected [T ], x : T , y : T ) =
180+ eqlElems[Elems ](r.reflect (x), r.reflect (y), 0 )
147181
148- inline def eqlCases [T , Alts <: Tuple ](mapper : MirrorMapper [T ], x : T , y : T ): Boolean =
182+ inline def eqlCases [T , Alts <: Tuple ](r : Reflected [T ], x : T , y : T ): Boolean =
149183 inline erasedValue[Alts ] match {
150184 case _ : (Shape .Case [alt, elems] *: alts1) =>
151185 x match {
152186 case x : `alt` =>
153187 y match {
154- case y : `alt` => eqlCase[T , elems](mapper , x, y)
188+ case y : `alt` => eqlCase[T , elems](r , x, y)
155189 case _ => false
156190 }
157- case _ => eqlCases[T , alts1](mapper , x, y)
191+ case _ => eqlCases[T , alts1](r , x, y)
158192 }
159193 case _ : Unit =>
160194 false
161195 }
162196
163- inline def derived [T , S <: Shape ](implicit ev : Shaped [T , S ]) < : Eq [T ] = new {
197+ inline def derived [T , S <: Shape ](implicit ev : Shaped [T , S ]): Eq [T ] = new {
164198 def eql (x : T , y : T ): Boolean = inline erasedValue[S ] match {
165199 case _ : Shape .Cases [alts] =>
166200 eqlCases[T , alts](ev, x, y)
@@ -198,18 +232,18 @@ object Pickler {
198232 case _ : Unit =>
199233 }
200234
201- inline def pickleCase [T , Elems <: Tuple ](mapper : MirrorMapper [T ], buf : mutable.ListBuffer [Int ], x : T ): Unit =
202- pickleElems[Elems ](buf, mapper.toMirror (x), 0 )
235+ inline def pickleCase [T , Elems <: Tuple ](r : Reflected [T ], buf : mutable.ListBuffer [Int ], x : T ): Unit =
236+ pickleElems[Elems ](buf, r.reflect (x), 0 )
203237
204- inline def pickleCases [T , Alts <: Tuple ](mapper : MirrorMapper [T ], buf : mutable.ListBuffer [Int ], x : T , n : Int ): Unit =
238+ inline def pickleCases [T , Alts <: Tuple ](r : Reflected [T ], buf : mutable.ListBuffer [Int ], x : T , n : Int ): Unit =
205239 inline erasedValue[Alts ] match {
206240 case _ : (Shape .Case [alt, elems] *: alts1) =>
207241 x match {
208242 case x : `alt` =>
209243 buf += n
210- pickleCase[T , elems](mapper , buf, x)
244+ pickleCase[T , elems](r , buf, x)
211245 case _ =>
212- pickleCases[T , alts1](mapper , buf, x, n + 1 )
246+ pickleCases[T , alts1](r , buf, x, n + 1 )
213247 }
214248 case _ : Unit =>
215249 }
@@ -226,22 +260,22 @@ object Pickler {
226260 case _ : Unit =>
227261 }
228262
229- inline def unpickleCase [T , Elems <: Tuple ](mapper : MirrorMapper [T ], buf : mutable.ListBuffer [Int ], ordinal : Int ): T = {
263+ inline def unpickleCase [T , Elems <: Tuple ](r : Reflected [T ], buf : mutable.ListBuffer [Int ], ordinal : Int ): T = {
230264 inline val size = constValue[Tuple .Size [Elems ]]
231265 inline if (size == 0 )
232- mapper.fromMirror (new CaseMirror [T ](ordinal))
266+ r.reify (new CaseMirror [T ](r.deriving, ordinal))
233267 else {
234268 val elems = new Array [Object ](size)
235269 unpickleElems[Elems ](buf, elems, 0 )
236- mapper.fromMirror (new CaseMirror [T ](ordinal, elems))
270+ r.reify (new CaseMirror [T ](r.deriving, ordinal, elems))
237271 }
238272 }
239273
240- inline def unpickleCases [T , Alts <: Tuple ](mapper : MirrorMapper [T ], buf : mutable.ListBuffer [Int ], ordinal : Int , n : Int ): T =
274+ inline def unpickleCases [T , Alts <: Tuple ](r : Reflected [T ], buf : mutable.ListBuffer [Int ], ordinal : Int , n : Int ): T =
241275 inline erasedValue[Alts ] match {
242276 case _ : (Shape .Case [_, elems] *: alts1) =>
243- if (n == ordinal) unpickleCase[T , elems](mapper , buf, ordinal)
244- else unpickleCases[T , alts1](mapper , buf, ordinal, n + 1 )
277+ if (n == ordinal) unpickleCase[T , elems](r , buf, ordinal)
278+ else unpickleCases[T , alts1](r , buf, ordinal, n + 1 )
245279 case _ =>
246280 throw new IndexOutOfBoundsException (s " unexpected ordinal number: $ordinal" )
247281 }
@@ -267,6 +301,59 @@ object Pickler {
267301 }
268302}
269303
304+ // A third typeclass, making use of names
305+ trait Show [T ] {
306+ def show (x : T ): String
307+ }
308+ object Show {
309+ import scala .typelevel ._
310+ import Deriving ._
311+
312+ inline def tryShow [T ](x : T ): String = implicit match {
313+ case s : Show [T ] => s.show(x)
314+ }
315+
316+ inline def showElems [Elems <: Tuple ](elems : CaseMirror [_], n : Int ): List [String ] =
317+ inline erasedValue[Elems ] match {
318+ case _ : (elem *: elems1) =>
319+ val formal = elems.elementName(n)
320+ val actual = tryShow[elem](elems(n).asInstanceOf )
321+ s " $formal = $actual" :: showElems[elems1](elems, n + 1 )
322+ case _ : Unit =>
323+ Nil
324+ }
325+
326+ inline def showCase [T , Elems <: Tuple ](r : Reflected [T ], x : T ): String = {
327+ val mirror = r.reflect(x)
328+ val args = showElems[Elems ](mirror, 0 ).mkString(" , " )
329+ s " ${mirror.caseName}( $args) "
330+ }
331+
332+ inline def showCases [T , Alts <: Tuple ](r : Reflected [T ], x : T ): String =
333+ inline erasedValue[Alts ] match {
334+ case _ : (Shape .Case [alt, elems] *: alts1) =>
335+ x match {
336+ case x : `alt` => showCase[T , elems](r, x)
337+ case _ => showCases[T , alts1](r, x)
338+ }
339+ case _ : Unit =>
340+ throw new MatchError (x)
341+ }
342+
343+ inline def derived [T , S <: Shape ](implicit ev : Shaped [T , S ]): Show [T ] = new {
344+ def show (x : T ): String = inline erasedValue[S ] match {
345+ case _ : Shape .Cases [alts] =>
346+ showCases[T , alts](ev, x)
347+ case _ : Shape .Case [_, elems] =>
348+ showCase[T , elems](ev, x)
349+ }
350+ }
351+
352+ implicit object IntShow extends Show [Int ] {
353+ def show (x : Int ): String = x.toString
354+ }
355+ }
356+
270357// Tests
271358object Test extends App {
272359 import Deriving ._
@@ -317,4 +404,9 @@ object Test extends App {
317404 println(p1a)
318405 assert(p1 == p1a)
319406 assert(eqp.eql(p1, p1a))
407+
408+ def showPrintln [T : Show ](x : T ): Unit =
409+ println(implicitly[Show [T ]].show(x))
410+ showPrintln(xs)
411+ showPrintln(xss)
320412}
0 commit comments