@@ -27,32 +27,38 @@ object Deriving {
27
27
* enums, case classes and objects, and their sealed parents.
28
28
*/
29
29
sealed abstract class Generic [T ]
30
+ object Generic {
30
31
31
- /** The Generic for a sum type */
32
- abstract class GenericSum [T ] extends Generic [T ] {
32
+ /** The Generic for a sum type */
33
+ abstract class Sum [T ] extends Generic [T ] {
33
34
34
- /** The ordinal number of the case class of `x`. For enums, `ordinal(x) == x.ordinal` */
35
- def ordinal (x : T ): Int
35
+ /** The ordinal number of the case class of `x`. For enums, `ordinal(x) == x.ordinal` */
36
+ def ordinal (x : T ): Int
36
37
37
- /** The number of cases in the sum.
38
- * Implemented by an inline method in concrete subclasses.
39
- */
40
- erased def numberOfCases : Int = ???
38
+ /** The number of cases in the sum.
39
+ * Implemented by an inline method in concrete subclasses.
40
+ */
41
+ erased def numberOfCases : Int = ???
41
42
42
- /** The Generic representations of the sum's alternatives.
43
- * Implemented by an inline method in concrete subclasses.
44
- */
45
- erased def alternative (n : Int ): GenericProduct [_ <: T ] = ???
46
- }
43
+ /** The Generic representations of the sum's alternatives.
44
+ * Implemented by an inline method in concrete subclasses.
45
+ */
46
+ erased def alternative (n : Int ): Generic [_ <: T ] = ???
47
+ }
47
48
48
- /** A Generic for a product type */
49
- abstract class GenericProduct [T ] extends Generic [T ] {
50
- type ElemTypes <: Tuple
51
- type CaseLabel
52
- type ElemLabels <: Tuple
49
+ /** A Generic for a product type */
50
+ abstract class Product [T ] extends Generic [T ] {
51
+ type ElemTypes <: Tuple
52
+ type CaseLabel <: String
53
+ type ElemLabels <: Tuple
53
54
54
- def toProduct (x : T ): Product
55
- def fromProduct (p : Product ): T
55
+ def toProduct (x : T ): scala.Product
56
+ def fromProduct (p : scala.Product ): T
57
+ }
58
+
59
+ class Singleton [T ](val value : T ) extends Generic [T ] {
60
+ type CaseLabel <: String
61
+ }
56
62
}
57
63
}
58
64
@@ -65,13 +71,13 @@ sealed trait Lst[+T] // derives Eq, Pickler, Show
65
71
object Lst {
66
72
import Deriving ._
67
73
68
- class GenericLst [T ] extends GenericSum [Lst [T ]] {
74
+ class GenericLst [T ] extends Generic . Sum [Lst [T ]] {
69
75
def ordinal (x : Lst [T ]) = x match {
70
76
case x : Cons [_] => 0
71
77
case Nil => 1
72
78
}
73
79
inline override def numberOfCases = 2
74
- inline override def alternative (n : Int ) <: GenericProduct [_ <: Lst [T ]] =
80
+ inline override def alternative (n : Int ) <: Generic [_ <: Lst [T ]] =
75
81
inline n match {
76
82
case 0 => Cons .GenericCons [T ]
77
83
case 1 => Nil .GenericNil
@@ -85,7 +91,7 @@ object Lst {
85
91
object Cons {
86
92
def apply [T ](x : T , xs : Lst [T ]): Lst [T ] = new Cons (x, xs)
87
93
88
- class GenericCons [T ] extends GenericProduct [Cons [T ]] {
94
+ class GenericCons [T ] extends Generic . Product [Cons [T ]] {
89
95
type ElemTypes = (T , Lst [T ])
90
96
type CaseLabel = " Cons"
91
97
type ElemLabels = (" hd" , " tl" )
@@ -98,12 +104,8 @@ object Lst {
98
104
}
99
105
100
106
case object Nil extends Lst [Nothing ] {
101
- class GenericNil extends GenericProduct [Nil .type ] {
102
- type ElemTypes = Unit
107
+ class GenericNil extends Generic .Singleton [Nil .type ](Nil ) {
103
108
type CaseLabel = " Nil"
104
- type ElemLabels = Unit
105
- def toProduct (x : Nil .type ): Product = EmptyProduct
106
- def fromProduct (p : Product ): Nil .type = Nil
107
109
}
108
110
implicit def GenericNil : GenericNil = new GenericNil
109
111
}
@@ -121,7 +123,7 @@ object Pair {
121
123
// common compiler-generated infrastructure
122
124
import Deriving ._
123
125
124
- class GenericPair [T ] extends GenericProduct [Pair [T ]] {
126
+ class GenericPair [T ] extends Generic . Product [Pair [T ]] {
125
127
type ElemTypes = (T , T )
126
128
type CaseLabel = " Pair"
127
129
type ElemLabels = (" x" , " y" )
@@ -143,13 +145,13 @@ sealed trait Either[+L, +R] extends Product with Serializable // derives Eq, Pic
143
145
object Either {
144
146
import Deriving ._
145
147
146
- class GenericEither [L , R ] extends GenericSum [Either [L , R ]] {
148
+ class GenericEither [L , R ] extends Generic . Sum [Either [L , R ]] {
147
149
def ordinal (x : Either [L , R ]) = x match {
148
150
case x : Left [L ] => 0
149
151
case x : Right [R ] => 1
150
152
}
151
153
inline override def numberOfCases = 2
152
- inline override def alternative (n : Int ) <: GenericProduct [_ <: Either [L , R ]] =
154
+ inline override def alternative (n : Int ) <: Generic [_ <: Either [L , R ]] =
153
155
inline n match {
154
156
case 0 => Left .GenericLeft [L ]
155
157
case 1 => Right .GenericRight [R ]
@@ -167,7 +169,7 @@ case class Right[R](elem: R) extends Either[Nothing, R]
167
169
168
170
object Left {
169
171
import Deriving ._
170
- class GenericLeft [L ] extends GenericProduct [Left [L ]] {
172
+ class GenericLeft [L ] extends Generic . Product [Left [L ]] {
171
173
type ElemTypes = L *: Unit
172
174
type CaseLabel = " Left"
173
175
type ElemLabels = " x" *: Unit
@@ -179,7 +181,7 @@ object Left {
179
181
180
182
object Right {
181
183
import Deriving ._
182
- class GenericRight [R ] extends GenericProduct [Right [R ]] {
184
+ class GenericRight [R ] extends Generic . Product [Right [R ]] {
183
185
type ElemTypes = R *: Unit
184
186
type CaseLabel = " Right"
185
187
type ElemLabels = " x" *: Unit
@@ -217,26 +219,29 @@ object Eq {
217
219
true
218
220
}
219
221
220
- inline def eqlCase [T ](gp : GenericProduct [T ])(x : T , y : T ): Boolean =
221
- eqlElems[gp .ElemTypes ](0 )(gp .toProduct(x), gp .toProduct(y))
222
+ inline def eqlProduct [T ](g : Generic . Product [T ])(x : T , y : T ): Boolean =
223
+ eqlElems[g .ElemTypes ](0 )(g .toProduct(x), g .toProduct(y))
222
224
223
- inline def eqlCases [T ](gs : GenericSum [T ], n : Int )(x : T , y : T , ord : Int ): Boolean =
224
- inline if (n == gs .numberOfCases)
225
+ inline def eqlCases [T ](g : Generic . Sum [T ], n : Int )(x : T , y : T , ord : Int ): Boolean =
226
+ inline if (n == g .numberOfCases)
225
227
false
226
228
else if (ord == n)
227
- inline gs.alternative(n) match {
228
- case gp : GenericProduct [p] => eqlCase[p](gp)(x.asInstanceOf [p], y.asInstanceOf [p])
229
+ inline g.alternative(n) match {
230
+ case g : Generic .Product [p] => eqlProduct[p](g)(x.asInstanceOf [p], y.asInstanceOf [p])
231
+ case g : Generic .Singleton [_] => true
229
232
}
230
- else eqlCases[T ](gs , n + 1 )(x, y, ord)
233
+ else eqlCases[T ](g , n + 1 )(x, y, ord)
231
234
232
235
inline def derived [T ](implicit ev : Generic [T ]): Eq [T ] = new Eq [T ] {
233
236
def eql (x : T , y : T ): Boolean =
234
237
inline ev match {
235
- case gs : GenericSum [T ] =>
236
- val ord = gs.ordinal(x)
237
- ord == gs.ordinal(y) && eqlCases[T ](gs, 0 )(x, y, ord)
238
- case gp : GenericProduct [T ] =>
239
- eqlCase[T ](gp)(x, y)
238
+ case g : Generic .Sum [T ] =>
239
+ val ord = g.ordinal(x)
240
+ ord == g.ordinal(y) && eqlCases[T ](g, 0 )(x, y, ord)
241
+ case g : Generic .Product [T ] =>
242
+ eqlProduct[T ](g)(x, y)
243
+ case g : Generic .Singleton [_] =>
244
+ true
240
245
}
241
246
}
242
247
@@ -269,17 +274,18 @@ object Pickler {
269
274
case _ : Unit =>
270
275
}
271
276
272
- inline def pickleCase [T ](gp : GenericProduct [T ])(buf : mutable.ListBuffer [Int ], x : T ): Unit =
273
- pickleElems[gp .ElemTypes ](0 )(buf, gp .toProduct(x))
277
+ inline def pickleProduct [T ](g : Generic . Product [T ])(buf : mutable.ListBuffer [Int ], x : T ): Unit =
278
+ pickleElems[g .ElemTypes ](0 )(buf, g .toProduct(x))
274
279
275
- inline def pickleCases [T ](gs : GenericSum [T ], inline n : Int )(buf : mutable.ListBuffer [Int ], x : T , ord : Int ): Unit =
276
- inline if (n == gs .numberOfCases)
280
+ inline def pickleCases [T ](g : Generic . Sum [T ], inline n : Int )(buf : mutable.ListBuffer [Int ], x : T , ord : Int ): Unit =
281
+ inline if (n == g .numberOfCases)
277
282
()
278
283
else if (ord == n)
279
- inline gs.alternative(n) match {
280
- case gp : GenericProduct [p] => pickleCase(gp)(buf, x.asInstanceOf [p])
284
+ inline g.alternative(n) match {
285
+ case g : Generic .Product [p] => pickleProduct(g)(buf, x.asInstanceOf [p])
286
+ case g : Generic .Singleton [s] =>
281
287
}
282
- else pickleCases[T ](gs , n + 1 )(buf, x, ord)
288
+ else pickleCases[T ](g , n + 1 )(buf, x, ord)
283
289
284
290
inline def tryUnpickle [T ](buf : mutable.ListBuffer [Int ]): T = implicit match {
285
291
case pkl : Pickler [T ] => pkl.unpickle(buf)
@@ -293,42 +299,46 @@ object Pickler {
293
299
case _ : Unit =>
294
300
}
295
301
296
- inline def unpickleCase [T ](gp : GenericProduct [T ])(buf : mutable.ListBuffer [Int ]): T = {
297
- inline val size = constValue[Tuple .Size [gp .ElemTypes ]]
302
+ inline def unpickleProduct [T ](g : Generic . Product [T ])(buf : mutable.ListBuffer [Int ]): T = {
303
+ inline val size = constValue[Tuple .Size [g .ElemTypes ]]
298
304
inline if (size == 0 )
299
- gp .fromProduct(EmptyProduct )
305
+ g .fromProduct(EmptyProduct )
300
306
else {
301
307
val elems = new Array [Object ](size)
302
- unpickleElems[gp .ElemTypes ](0 )(buf, elems)
303
- gp .fromProduct(ArrayProduct (elems))
308
+ unpickleElems[g .ElemTypes ](0 )(buf, elems)
309
+ g .fromProduct(ArrayProduct (elems))
304
310
}
305
311
}
306
312
307
- inline def unpickleCases [T ](gs : GenericSum [T ], n : Int )(buf : mutable.ListBuffer [Int ], ord : Int ): T =
308
- inline if (n == gs .numberOfCases)
313
+ inline def unpickleCases [T ](g : Generic . Sum [T ], n : Int )(buf : mutable.ListBuffer [Int ], ord : Int ): T =
314
+ inline if (n == g .numberOfCases)
309
315
throw new IndexOutOfBoundsException (s " unexpected ordinal number: $ord" )
310
316
else if (ord == n)
311
- inline gs.alternative(n) match {
312
- case gp : GenericProduct [p] => unpickleCase(gp)(buf)
317
+ inline g.alternative(n) match {
318
+ case g : Generic .Product [p] => unpickleProduct(g)(buf)
319
+ case g : Generic .Singleton [s] => g.value
313
320
}
314
- else unpickleCases[T ](gs , n + 1 )(buf, ord)
321
+ else unpickleCases[T ](g , n + 1 )(buf, ord)
315
322
316
323
inline def derived [T ](implicit ev : Generic [T ]): Pickler [T ] = new {
317
324
def pickle (buf : mutable.ListBuffer [Int ], x : T ): Unit =
318
325
inline ev match {
319
- case gs : GenericSum [T ] =>
320
- val ord = gs .ordinal(x)
326
+ case g : Generic . Sum [T ] =>
327
+ val ord = g .ordinal(x)
321
328
buf += ord
322
- pickleCases[T ](gs, 0 )(buf, x, ord)
323
- case gp : GenericProduct [p] =>
324
- pickleCase(gp)(buf, x)
329
+ pickleCases[T ](g, 0 )(buf, x, ord)
330
+ case g : Generic .Product [p] =>
331
+ pickleProduct(g)(buf, x)
332
+ case g : Generic .Singleton [_] =>
325
333
}
326
334
def unpickle (buf : mutable.ListBuffer [Int ]): T =
327
335
inline ev match {
328
- case gs : GenericSum [T ] =>
329
- unpickleCases[T ](gs, 0 )(buf, nextInt(buf))
330
- case gp : GenericProduct [T ] =>
331
- unpickleCase[T ](gp)(buf)
336
+ case g : Generic .Sum [T ] =>
337
+ unpickleCases[T ](g, 0 )(buf, nextInt(buf))
338
+ case g : Generic .Product [T ] =>
339
+ unpickleProduct[T ](g)(buf)
340
+ case g : Generic .Singleton [s] =>
341
+ constValue[s]
332
342
}
333
343
}
334
344
@@ -363,27 +373,30 @@ object Show {
363
373
Nil
364
374
}
365
375
366
- inline def showCase [T ](gp : GenericProduct [T ])(x : T ): String = {
367
- val labl = constValue[gp .CaseLabel ]
368
- showElems[gp .ElemTypes , gp .ElemLabels ](0 )(gp .toProduct(x)).mkString(s " $labl( " , " , " , " )" )
376
+ inline def showProduct [T ](g : Generic . Product [T ])(x : T ): String = {
377
+ val labl = constValue[g .CaseLabel ]
378
+ showElems[g .ElemTypes , g .ElemLabels ](0 )(g .toProduct(x)).mkString(s " $labl( " , " , " , " )" )
369
379
}
370
380
371
- inline def showCases [T ](gs : GenericSum [T ], n : Int )(x : T , ord : Int ): String =
372
- inline if (n == gs .numberOfCases)
381
+ inline def showCases [T ](g : Generic . Sum [T ], n : Int )(x : T , ord : Int ): String =
382
+ inline if (n == g .numberOfCases)
373
383
" "
374
384
else if (ord == n)
375
- inline gs.alternative(n) match {
376
- case gp : GenericProduct [p] => showCase(gp)(x.asInstanceOf [p])
385
+ inline g.alternative(n) match {
386
+ case g : Generic .Product [p] => showProduct(g)(x.asInstanceOf [p])
387
+ case g : Generic .Singleton [s] => constValue[g.CaseLabel ]
377
388
}
378
- else showCases[T ](gs , n + 1 )(x, ord)
389
+ else showCases[T ](g , n + 1 )(x, ord)
379
390
380
391
inline def derived [T ](implicit ev : Generic [T ]): Show [T ] = new {
381
392
def show (x : T ): String =
382
393
inline ev match {
383
- case gs : GenericSum [T ] =>
384
- showCases(gs, 0 )(x, gs.ordinal(x))
385
- case gp : GenericProduct [p] =>
386
- showCase(gp)(x)
394
+ case g : Generic .Sum [T ] =>
395
+ showCases(g, 0 )(x, g.ordinal(x))
396
+ case g : Generic .Product [p] =>
397
+ showProduct(g)(x)
398
+ case g : Generic .Singleton [s] =>
399
+ constValue[g.CaseLabel ]
387
400
}
388
401
}
389
402
0 commit comments