Skip to content

Commit 3f31087

Browse files
committed
Add a simple product class
1 parent 6b53a8a commit 3f31087

File tree

1 file changed

+50
-14
lines changed

1 file changed

+50
-14
lines changed

tests/run/typeclass-derivation2.scala

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ object Deriving {
1818
abstract class HasShape[T, S <: Shape] extends GenericMapper[T]
1919
}
2020

21-
// A datatype
22-
enum Lst[+T] {
21+
// An algebraic datatype
22+
enum Lst[+T] // derives Eq, Pickler
23+
{
2324
case Cons(hd: T, tl: Lst[T])
2425
case Nil
2526
}
@@ -49,6 +50,27 @@ object Lst {
4950
implicit def LstPickler[T: Pickler]: Pickler[Lst[T]] = Pickler.derived
5051
}
5152

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+
5274
// A typeclass
5375
trait Eq[T] {
5476
def equals(x: T, y: T): Boolean
@@ -93,7 +115,7 @@ object Eq {
93115
def equals(x: T, y: T): Boolean = inline erasedValue[S] match {
94116
case _: Shape.Sum[alts] =>
95117
equalsSum[T, alts](ev, x, y)
96-
case _: Shape.Case[_, elems] =>
118+
case _: Shape.Case[alt, elems] =>
97119
equalsCase[T, elems](ev, x, y)
98120
}
99121
}
@@ -127,18 +149,18 @@ object Pickler {
127149
case _: Unit =>
128150
}
129151

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)
135154

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 =
137156
inline erasedValue[Alts] match {
138157
case _: (Shape.Case[alt, elems] *: alts1) =>
139158
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)
142164
}
143165
case _: Unit =>
144166
}
@@ -173,14 +195,14 @@ object Pickler {
173195
inline def derived[T, S <: Shape](implicit ev: HasShape[T, S]): Pickler[T] = new {
174196
def pickle(buf: mutable.ListBuffer[Int], x: T): Unit = inline erasedValue[S] match {
175197
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] =>
178200
pickleCase[T, elems](ev, buf, x)
179201
}
180202
def unpickle(buf: mutable.ListBuffer[Int]): T = inline erasedValue[S] match {
181203
case _: Shape.Sum[alts] =>
182204
unpickleSum[T, alts](ev, buf, nextInt(buf), 0)
183-
case _: Shape.Case[_, elems] =>
205+
case _: Shape.Case[alt, elems] =>
184206
unpickleCase[T, elems](ev, buf, 0)
185207
}
186208
}
@@ -226,4 +248,18 @@ object Test extends App {
226248
println(xss1)
227249
assert(xss == xss1)
228250
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))
229265
}

0 commit comments

Comments
 (0)