@@ -18,8 +18,9 @@ object Deriving {
18
18
abstract class HasShape [T , S <: Shape ] extends GenericMapper [T ]
19
19
}
20
20
21
- // A datatype
22
- enum Lst [+ T ] {
21
+ // An algebraic datatype
22
+ enum Lst [+ T ] // derives Eq, Pickler
23
+ {
23
24
case Cons (hd : T , tl : Lst [T ])
24
25
case Nil
25
26
}
@@ -49,6 +50,27 @@ object Lst {
49
50
implicit def LstPickler [T : Pickler ]: Pickler [Lst [T ]] = Pickler .derived
50
51
}
51
52
53
+ // A simple product type
54
+ case class Pair [T ](x : T , y : T ) // derives Eq, Pickler
55
+
56
+ object Pair {
57
+ // common compiler-generated infrastructure
58
+ import Deriving ._
59
+
60
+ type PairShape [T ] = Shape .Case [Pair [T ], (T , T )]
61
+
62
+ implicit def pairShape [T ]: HasShape [Pair [T ], PairShape [T ]] = new {
63
+ def toGenericCase (xy : Pair [T ]) =
64
+ GenericCase [Pair [T ]](0 , Array (xy._1.asInstanceOf , xy._2.asInstanceOf ))
65
+ def fromGenericCase (c : GenericCase [Pair [T ]]): Pair [T ] =
66
+ Pair (c.elems(0 ).asInstanceOf , c.elems(1 ).asInstanceOf )
67
+ }
68
+
69
+ // two clauses that could be generated from a `derives` clause
70
+ implicit def PairEq [T : Eq ]: Eq [Pair [T ]] = Eq .derived
71
+ implicit def PairPickler [T : Pickler ]: Pickler [Pair [T ]] = Pickler .derived
72
+ }
73
+
52
74
// A typeclass
53
75
trait Eq [T ] {
54
76
def equals (x : T , y : T ): Boolean
@@ -93,7 +115,7 @@ object Eq {
93
115
def equals (x : T , y : T ): Boolean = inline erasedValue[S ] match {
94
116
case _ : Shape .Sum [alts] =>
95
117
equalsSum[T , alts](ev, x, y)
96
- case _ : Shape .Case [_ , elems] =>
118
+ case _ : Shape .Case [alt , elems] =>
97
119
equalsCase[T , elems](ev, x, y)
98
120
}
99
121
}
@@ -127,18 +149,18 @@ object Pickler {
127
149
case _ : Unit =>
128
150
}
129
151
130
- inline def pickleCase [T , Elems <: Tuple ](mapper : GenericMapper [T ], buf : mutable.ListBuffer [Int ], x : T ): Unit = {
131
- val c = mapper.toGenericCase(x)
132
- buf += c.ordinal
133
- pickleElems[Elems ](buf, c.elems, 0 )
134
- }
152
+ inline def pickleCase [T , Elems <: Tuple ](mapper : GenericMapper [T ], buf : mutable.ListBuffer [Int ], x : T ): Unit =
153
+ pickleElems[Elems ](buf, mapper.toGenericCase(x).elems, 0 )
135
154
136
- inline def pickleSum [T , Alts <: Tuple ](mapper : GenericMapper [T ], buf : mutable.ListBuffer [Int ], x : T ): Unit =
155
+ inline def pickleSum [T , Alts <: Tuple ](mapper : GenericMapper [T ], buf : mutable.ListBuffer [Int ], x : T , n : Int ): Unit =
137
156
inline erasedValue[Alts ] match {
138
157
case _ : (Shape .Case [alt, elems] *: alts1) =>
139
158
x match {
140
- case x : `alt` => pickleCase[T , elems](mapper, buf, x)
141
- case _ => pickleSum[T , alts1](mapper, buf, x)
159
+ case x : `alt` =>
160
+ buf += n
161
+ pickleCase[T , elems](mapper, buf, x)
162
+ case _ =>
163
+ pickleSum[T , alts1](mapper, buf, x, n + 1 )
142
164
}
143
165
case _ : Unit =>
144
166
}
@@ -173,14 +195,14 @@ object Pickler {
173
195
inline def derived [T , S <: Shape ](implicit ev : HasShape [T , S ]): Pickler [T ] = new {
174
196
def pickle (buf : mutable.ListBuffer [Int ], x : T ): Unit = inline erasedValue[S ] match {
175
197
case _ : Shape .Sum [alts] =>
176
- pickleSum[T , alts](ev, buf, x)
177
- case _ : Shape .Case [_ , elems] =>
198
+ pickleSum[T , alts](ev, buf, x, 0 )
199
+ case _ : Shape .Case [alt , elems] =>
178
200
pickleCase[T , elems](ev, buf, x)
179
201
}
180
202
def unpickle (buf : mutable.ListBuffer [Int ]): T = inline erasedValue[S ] match {
181
203
case _ : Shape .Sum [alts] =>
182
204
unpickleSum[T , alts](ev, buf, nextInt(buf), 0 )
183
- case _ : Shape .Case [_ , elems] =>
205
+ case _ : Shape .Case [alt , elems] =>
184
206
unpickleCase[T , elems](ev, buf, 0 )
185
207
}
186
208
}
@@ -226,4 +248,18 @@ object Test extends App {
226
248
println(xss1)
227
249
assert(xss == xss1)
228
250
assert(eq2.equals(xss, xss1))
251
+
252
+ val p1 = Pair (1 , 2 )
253
+ val p2 = Pair (1 , 2 )
254
+ val p3 = Pair (2 , 1 )
255
+ val eqp = implicitly[Eq [Pair [Int ]]]
256
+ assert(eqp.equals(p1, p2))
257
+ assert(! eqp.equals(p2, p3))
258
+
259
+ val pklp = implicitly[Pickler [Pair [Int ]]]
260
+ pklp.pickle(buf, p1)
261
+ println(buf)
262
+ val p1a = pklp.unpickle(buf)
263
+ assert(p1 == p1a)
264
+ assert(eqp.equals(p1, p1a))
229
265
}
0 commit comments