1
1
import scala .collection .mutable
2
2
import scala .annotation .tailrec
3
3
4
- trait Deriving {
5
- import Deriving ._
6
-
7
- /** A mirror of case with ordinal number `ordinal` and elements as given by `Product` */
8
- def mirror (ordinal : Int , product : Product ): Mirror =
9
- new Mirror (this , ordinal, product)
10
-
11
- /** A mirror with elements given as an array */
12
- def mirror (ordinal : Int , elems : Array [AnyRef ]): Mirror =
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 (ordinal : Int , numElems : Int ): Mirror =
17
- mirror(ordinal, new Array [AnyRef ](numElems))
18
-
19
- /** A mirror of a case with no elements */
20
- def mirror (ordinal : Int ): Mirror =
21
- mirror(ordinal, EmptyProduct )
22
-
23
- /** The case and element labels of the described ADT as encoded strings. */
24
- protected def caseLabels : Array [String ]
25
-
26
- private final val separator = '\000 '
27
-
28
- private def label (ordinal : Int , idx : Int ): String = {
29
- val labels = caseLabels(ordinal)
30
- @ tailrec def separatorPos (from : Int ): Int =
31
- if (from == labels.length || labels(from) == separator) from
32
- else separatorPos(from + 1 )
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 )
4
+ object TypeLevel {
5
+ /** @param caseLabels The case and element labels of the described ADT as encoded strings.
6
+ */
7
+ class ReflectedClass (labelsStr : String ) {
8
+ import ReflectedClass ._
9
+
10
+ /** A mirror of case with ordinal number `ordinal` and elements as given by `Product` */
11
+ def mirror (ordinal : Int , product : Product ): Mirror =
12
+ new Mirror (this , ordinal, product)
13
+
14
+ /** A mirror with elements given as an array */
15
+ def mirror (ordinal : Int , elems : Array [AnyRef ]): Mirror =
16
+ mirror(ordinal, new ArrayProduct (elems))
17
+
18
+ /** A mirror with an initial empty array of `numElems` elements, to be filled in. */
19
+ def mirror (ordinal : Int , numElems : Int ): Mirror =
20
+ mirror(ordinal, new Array [AnyRef ](numElems))
21
+
22
+ /** A mirror of a case with no elements */
23
+ def mirror (ordinal : Int ): Mirror =
24
+ mirror(ordinal, EmptyProduct )
25
+
26
+ val label : Array [Array [String ]] =
27
+ initLabels(0 , 0 , new mutable.ArrayBuffer [String ], new mutable.ArrayBuffer [Array [String ]])
28
+
29
+ private final val elemSeparator = '\000 '
30
+ private final val caseSeparator = '\001 '
31
+
32
+ private def initLabels (start : Int , cur : Int ,
33
+ elems : mutable.ArrayBuffer [String ],
34
+ cases : mutable.ArrayBuffer [Array [String ]]): Array [Array [String ]] = {
35
+ def addElem = elems += labelsStr.substring(start, cur)
36
+ def addCase = cases += addElem.toArray
37
+ if (cur == labelsStr.length)
38
+ addCase.toArray
39
+ else if (labelsStr(cur) == caseSeparator)
40
+ initLabels(cur + 1 , cur + 1 , new mutable.ArrayBuffer , addCase)
41
+ else if (labelsStr(cur) == elemSeparator)
42
+ initLabels(cur + 1 , cur + 1 , addElem, cases)
43
+ else
44
+ initLabels(start, cur + 1 , elems, cases)
45
+ }
38
46
}
39
- }
40
47
41
- // Generic deriving infrastructure
42
- object Deriving {
48
+ object ReflectedClass {
49
+ /** Helper class to turn arrays into products */
50
+ private class ArrayProduct (val elems : Array [AnyRef ]) extends Product {
51
+ def canEqual (that : Any ): Boolean = true
52
+ def productElement (n : Int ) = elems(n)
53
+ def productArity = elems.length
54
+ override def productIterator : Iterator [Any ] = elems.iterator
55
+ def update (n : Int , x : Any ) = elems(n) = x.asInstanceOf [AnyRef ]
56
+ }
57
+
58
+ /** Helper object */
59
+ private object EmptyProduct extends Product {
60
+ def canEqual (that : Any ): Boolean = true
61
+ def productElement (n : Int ) = throw new IndexOutOfBoundsException
62
+ def productArity = 0
63
+ }
64
+ }
43
65
44
66
/** A generic representation of a case in an ADT
45
- * @param deriving The companion object of the ADT
46
- * @param ordinal The ordinal value of the case in the list of the ADT's cases
47
- * @param elems The elements of the case
48
- */
49
- class Mirror (val deriving : Deriving , val ordinal : Int , val elems : Product ) {
67
+ * @param deriving The companion object of the ADT
68
+ * @param ordinal The ordinal value of the case in the list of the ADT's cases
69
+ * @param elems The elements of the case
70
+ */
71
+ class Mirror (val reflected : ReflectedClass , val ordinal : Int , val elems : Product ) {
50
72
51
73
/** The `n`'th element of this generic case */
52
74
def apply (n : Int ): Any = elems.productElement(n)
53
75
54
76
/** The name of the constructor of the case reflected by this mirror */
55
- def caseLabel : String = deriving .label(ordinal, 0 )
77
+ def caseLabel : String = reflected .label(ordinal)( 0 )
56
78
57
79
/** The label of the `n`'th element of the case reflected by this mirror */
58
- def elementLabel (n : Int ) = deriving .label(ordinal, n + 1 )
80
+ def elementLabel (n : Int ) = reflected .label(ordinal)( n + 1 )
59
81
}
60
82
61
83
/** A class for mapping between an ADT value and
62
- * the case mirror that represents the value.
63
- */
84
+ * the case mirror that represents the value.
85
+ */
64
86
abstract class Reflected [T ] {
65
87
66
88
/** The case mirror corresponding to ADT instance `x` */
@@ -70,7 +92,7 @@ object Deriving {
70
92
def reify (mirror : Mirror ): T
71
93
72
94
/** The companion object of the ADT */
73
- def deriving : Deriving
95
+ def common : ReflectedClass
74
96
}
75
97
76
98
/** The shape of an ADT.
@@ -89,22 +111,6 @@ object Deriving {
89
111
* It informs that type `T` has shape `S` and also implements runtime reflection on `T`.
90
112
*/
91
113
abstract class Shaped [T , S <: Shape ] extends Reflected [T ]
92
-
93
- /** Helper class to turn arrays into products */
94
- private class ArrayProduct (val elems : Array [AnyRef ]) extends Product {
95
- def canEqual (that : Any ): Boolean = true
96
- def productElement (n : Int ) = elems(n)
97
- def productArity = elems.length
98
- override def productIterator : Iterator [Any ] = elems.iterator
99
- def update (n : Int , x : Any ) = elems(n) = x.asInstanceOf [AnyRef ]
100
- }
101
-
102
- /** Helper object */
103
- private object EmptyProduct extends Product {
104
- def canEqual (that : Any ): Boolean = true
105
- def productElement (n : Int ) = throw new IndexOutOfBoundsException
106
- def productArity = 0
107
- }
108
114
}
109
115
110
116
// An algebraic datatype
@@ -113,15 +119,18 @@ enum Lst[+T] {
113
119
case Nil
114
120
}
115
121
116
- object Lst extends Deriving {
122
+ object Lst {
117
123
// common compiler-generated infrastructure
118
- import Deriving ._
124
+ import TypeLevel ._
119
125
120
126
type Shape [T ] = Shape .Cases [(
121
127
Shape .Case [Cons [T ], (T , Lst [T ])],
122
128
Shape .Case [Nil .type , Unit ]
123
129
)]
124
130
131
+ val reflectedClass = new ReflectedClass (" Cons\000 hd\000 tl\001 Nil" )
132
+ import reflectedClass .mirror
133
+
125
134
val NilMirror = mirror(1 )
126
135
127
136
implicit def lstShape [T ]: Shaped [Lst [T ], Shape [T ]] = new {
@@ -133,47 +142,49 @@ object Lst extends Deriving {
133
142
case 0 => Cons [T ](c(0 ).asInstanceOf , c(1 ).asInstanceOf )
134
143
case 1 => Nil
135
144
}
136
- def deriving = Lst
145
+ def common = reflectedClass
137
146
}
138
147
139
- protected val caseLabels = Array (" Cons\000 hd\000 tl" , " Nil" )
140
-
141
148
// three clauses that could be generated from a `derives` clause
142
149
implicit def LstShow [T : Show ]: Show [Lst [T ]] = Show .derived
143
150
}
144
151
145
152
// A simple product type
146
- case class Pair [T ](x : T , y : T )
153
+ case class Pair [T ](x : T , y : T ) // derives Eq, Pickler, Show
147
154
148
- object Pair extends Deriving {
155
+ object Pair {
149
156
// common compiler-generated infrastructure
150
- import Deriving ._
157
+ import TypeLevel ._
151
158
152
159
type Shape [T ] = Shape .Case [Pair [T ], (T , T )]
153
160
161
+ val reflectedClass = new ReflectedClass (" Pair\000 x\000 y" )
162
+ import reflectedClass .mirror
163
+
154
164
implicit def pairShape [T ]: Shaped [Pair [T ], Shape [T ]] = new {
155
165
def reflect (xy : Pair [T ]) =
156
166
mirror(0 , xy)
157
167
def reify (c : Mirror ): Pair [T ] =
158
168
Pair (c(0 ).asInstanceOf , c(1 ).asInstanceOf )
159
- def deriving = Pair
169
+ def common = reflectedClass
160
170
}
161
-
162
- protected val caseLabels = Array (" Pair\000 x\000 y" )
163
171
}
164
172
165
- sealed trait Either [+ L , + R ] extends Product
173
+ sealed trait Either [+ L , + R ] extends Product // derives Eq, Pickler, Show
166
174
case class Left [L ](x : L ) extends Either [L , Nothing ]
167
175
case class Right [R ](x : R ) extends Either [Nothing , R ]
168
176
169
- object Either extends Deriving {
170
- import Deriving ._
177
+ object Either {
178
+ import TypeLevel ._
171
179
172
180
type Shape [L , R ] = Shape .Cases [(
173
181
Shape .Case [Left [L ], L *: Unit ],
174
182
Shape .Case [Right [R ], R *: Unit ]
175
183
)]
176
184
185
+ val reflectedClass = new ReflectedClass (" Left\000 x\001 Right\000 x" )
186
+ import reflectedClass .mirror
187
+
177
188
implicit def eitherShape [L , R ]: Shaped [Either [L , R ], Shape [L , R ]] = new {
178
189
def reflect (e : Either [L , R ]): Mirror = e match {
179
190
case e : Left [L ] => mirror(0 , e)
@@ -183,20 +194,17 @@ object Either extends Deriving {
183
194
case 0 => Left [L ](c(0 ).asInstanceOf )
184
195
case 1 => Right [R ](c(0 ).asInstanceOf )
185
196
}
186
- def deriving = Either
197
+ def common = reflectedClass
187
198
}
188
-
189
- protected val caseLabels = Array (" Left\000 x" , " Right\000 x" )
190
-
191
199
implicit def EitherShow [L : Show , R : Show ]: Show [Either [L , R ]] = Show .derived
192
200
}
193
201
194
202
trait Show [T ] {
195
203
def show (x : T ): String
196
204
}
197
205
object Show {
198
- import scala .typelevel ._
199
- import Deriving ._
206
+ import scala .typelevel .erasedValue
207
+ import TypeLevel ._
200
208
201
209
inline def tryShow [T ](x : T ): String = implicit match {
202
210
case s : Show [T ] => s.show(x)
@@ -245,7 +253,7 @@ object Show {
245
253
246
254
// Tests
247
255
object Test extends App {
248
- import Deriving ._
256
+ import TypeLevel ._
249
257
250
258
def showPrintln [T : Show ](x : T ): Unit =
251
259
println(implicitly[Show [T ]].show(x))
0 commit comments