@@ -4,72 +4,85 @@ import scala.annotation.tailrec
4
4
trait Deriving {
5
5
import Deriving ._
6
6
7
- protected def caseNames : Array [String ]
7
+ /** A mirror of case with ordinal number `ordinal` and elements as given by `Product` */
8
+ def mirror [T ](ordinal : Int , product : Product ): CaseMirror [T ] =
9
+ new CaseMirror (this , ordinal, product)
10
+
11
+ /** A mirror with elements given as an array */
12
+ def mirror [T ](ordinal : Int , elems : Array [AnyRef ]): CaseMirror [T ] =
13
+ mirror(ordinal, new ArrayProduct (elems))
14
+
15
+ /** A mirror with an initial empty array of `numElems` elements, to be filled in. */
16
+ def mirror [T ](ordinal : Int , numElems : Int ): CaseMirror [T ] =
17
+ mirror(ordinal, new Array [AnyRef ](numElems))
18
+
19
+ /** A mirror of a case with no elements */
20
+ def mirror [T ](ordinal : Int ): CaseMirror [T ] =
21
+ mirror(ordinal, EmptyProduct )
22
+
23
+ /** The case and element labels of the described ADT as encoded strings. */
24
+ protected def caseLabels : Array [String ]
8
25
9
26
private final val separator = '\000 '
10
27
11
- private def cname (ordinal : Int , idx : Int ): String = {
12
- val cnames = caseNames (ordinal)
28
+ private def label (ordinal : Int , idx : Int ): String = {
29
+ val labels = caseLabels (ordinal)
13
30
@ tailrec def separatorPos (from : Int ): Int =
14
- if (from == cnames .length || cnames (from) == separator) from
31
+ if (from == labels .length || labels (from) == separator) from
15
32
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 )
33
+ @ tailrec def findLabel (count : Int , idx : Int ): String =
34
+ if (idx == labels .length) " "
35
+ else if (count == 0 ) labels .substring(idx, separatorPos(idx))
36
+ else findLabel (if (labels (idx) == separator) count - 1 else count, idx + 1 )
37
+ findLabel (idx, 0 )
21
38
}
22
-
23
- def caseName (ordinal : Int ): String = cname(ordinal, 0 )
24
- def elementName (ordinal : Int , idx : Int ) = cname(ordinal, idx + 1 )
25
39
}
26
40
27
41
// Generic deriving infrastructure
28
42
object Deriving {
29
43
30
- /** The shape of an ADT in a sum of products representation */
31
- enum Shape {
32
- /** A sum with alternative types `Alts` */
33
- case Cases [Alts <: Tuple ]
34
-
35
- /** A product type `T` with element types `Elems` */
36
- case Case [T , Elems <: Tuple ]
37
- }
38
-
39
44
/** A generic representation of a case in an ADT
45
+ * @param deriving The companion object of the ADT
40
46
* @param ordinal The ordinal value of the case in the list of the ADT's cases
41
47
* @param elems The elements of the case
42
48
*/
43
49
class CaseMirror [+ T ](val deriving : Deriving , val ordinal : Int , val elems : Product ) {
44
50
45
- /** A generic case with elements given as an array */
46
- def this (deriving : Deriving , ordinal : Int , elems : Array [AnyRef ]) =
47
- this (deriving, ordinal, new ArrayProduct (elems))
48
-
49
- /** A generic case with an initial empty array of `numElems` elements, to be filled in. */
50
- def this (deriving : Deriving , ordinal : Int , numElems : Int ) =
51
- this (deriving, ordinal, new Array [AnyRef ](numElems))
52
-
53
- /** A generic case with no elements */
54
- def this (deriving : Deriving , ordinal : Int ) =
55
- this (deriving, ordinal, EmptyProduct )
56
-
57
51
/** The `n`'th element of this generic case */
58
52
def apply (n : Int ): Any = elems.productElement(n)
59
53
60
- def caseName : String = deriving.caseName(ordinal)
61
- def elementName (idx : Int ) = deriving.elementName(ordinal, idx)
54
+ /** The name of the constructor of the case reflected by this mirror */
55
+ def caseLabel : String = deriving.label(ordinal, 0 )
56
+
57
+ /** The label of the `n`'th element of the case reflected by this mirror */
58
+ def elementLabel (n : Int ) = deriving.label(ordinal, n + 1 )
62
59
}
63
60
64
61
/** A class for mapping between an ADT value and
65
62
* the case mirror that represents the value.
66
63
*/
67
64
abstract class Reflected [T ] {
65
+
66
+ /** The case mirror corresponding to ADT instance `x` */
68
67
def reflect (x : T ): CaseMirror [T ]
69
- def reify (c : CaseMirror [T ]): T
68
+
69
+ /** The ADT instance corresponding to given `mirror` */
70
+ def reify (mirror : CaseMirror [T ]): T
71
+
72
+ /** The companion object of the ADT */
70
73
def deriving : Deriving
71
74
}
72
75
76
+ /** The shape of an ADT in a sum of products representation */
77
+ enum Shape {
78
+
79
+ /** A sum with alternative types `Alts` */
80
+ case Cases [Alts <: Tuple ]
81
+
82
+ /** A product type `T` with element types `Elems` */
83
+ case Case [T , Elems <: Tuple ]
84
+ }
85
+
73
86
/** Every generic derivation starts with a typeclass instance of this type.
74
87
* It informs that type `T` has shape `S` and also allows runtime reflection on `T`.
75
88
*/
@@ -108,11 +121,11 @@ object Lst extends Deriving {
108
121
Shape .Case [Nil .type , Unit ]
109
122
)]
110
123
111
- val NilMirror = new CaseMirror [Nil .type ](Lst , 1 )
124
+ val NilMirror = mirror [Nil .type ](1 )
112
125
113
126
implicit def lstShape [T ]: Shaped [Lst [T ], Shape [T ]] = new {
114
127
def reflect (xs : Lst [T ]): CaseMirror [Lst [T ]] = xs match {
115
- case xs : Cons [T ] => new CaseMirror [Cons [T ]](Lst , 0 , xs)
128
+ case xs : Cons [T ] => mirror [Cons [T ]](0 , xs)
116
129
case Nil => NilMirror
117
130
}
118
131
def reify (c : CaseMirror [Lst [T ]]): Lst [T ] = c.ordinal match {
@@ -122,7 +135,7 @@ object Lst extends Deriving {
122
135
def deriving = Lst
123
136
}
124
137
125
- protected val caseNames = Array (" Cons\000 hd\000 tl" , " Nil" )
138
+ protected val caseLabels = Array (" Cons\000 hd\000 tl" , " Nil" )
126
139
127
140
// three clauses that could be generated from a `derives` clause
128
141
implicit def LstEq [T : Eq ]: Eq [Lst [T ]] = Eq .derived
@@ -141,13 +154,13 @@ object Pair extends Deriving {
141
154
142
155
implicit def pairShape [T ]: Shaped [Pair [T ], Shape [T ]] = new {
143
156
def reflect (xy : Pair [T ]) =
144
- new CaseMirror [Pair [T ]](Pair , 0 , xy)
157
+ mirror [Pair [T ]](0 , xy)
145
158
def reify (c : CaseMirror [Pair [T ]]): Pair [T ] =
146
159
Pair (c(0 ).asInstanceOf , c(1 ).asInstanceOf )
147
160
def deriving = Pair
148
161
}
149
162
150
- protected val caseNames = Array (" Pair\000 x\000 y" )
163
+ protected val caseLabels = Array (" Pair\000 x\000 y" )
151
164
152
165
// two clauses that could be generated from a `derives` clause
153
166
implicit def PairEq [T : Eq ]: Eq [Pair [T ]] = Eq .derived
@@ -263,11 +276,11 @@ object Pickler {
263
276
inline def unpickleCase [T , Elems <: Tuple ](r : Reflected [T ], buf : mutable.ListBuffer [Int ], ordinal : Int ): T = {
264
277
inline val size = constValue[Tuple .Size [Elems ]]
265
278
inline if (size == 0 )
266
- r.reify(new CaseMirror [T ](r.deriving, ordinal))
279
+ r.reify(r.deriving.mirror [T ](ordinal))
267
280
else {
268
281
val elems = new Array [Object ](size)
269
282
unpickleElems[Elems ](buf, elems, 0 )
270
- r.reify(new CaseMirror [T ](r.deriving, ordinal, elems))
283
+ r.reify(r.deriving.mirror [T ](ordinal, elems))
271
284
}
272
285
}
273
286
@@ -301,7 +314,7 @@ object Pickler {
301
314
}
302
315
}
303
316
304
- // A third typeclass, making use of names
317
+ // A third typeclass, making use of labels
305
318
trait Show [T ] {
306
319
def show (x : T ): String
307
320
}
@@ -316,7 +329,7 @@ object Show {
316
329
inline def showElems [Elems <: Tuple ](elems : CaseMirror [_], n : Int ): List [String ] =
317
330
inline erasedValue[Elems ] match {
318
331
case _ : (elem *: elems1) =>
319
- val formal = elems.elementName (n)
332
+ val formal = elems.elementLabel (n)
320
333
val actual = tryShow[elem](elems(n).asInstanceOf )
321
334
s " $formal = $actual" :: showElems[elems1](elems, n + 1 )
322
335
case _ : Unit =>
@@ -326,7 +339,7 @@ object Show {
326
339
inline def showCase [T , Elems <: Tuple ](r : Reflected [T ], x : T ): String = {
327
340
val mirror = r.reflect(x)
328
341
val args = showElems[Elems ](mirror, 0 ).mkString(" , " )
329
- s " ${mirror.caseName }( $args) "
342
+ s " ${mirror.caseLabel }( $args) "
330
343
}
331
344
332
345
inline def showCases [T , Alts <: Tuple ](r : Reflected [T ], x : T ): String =
0 commit comments