Skip to content

Commit e9d324e

Browse files
committed
ADT and Serialization test
The test exercises all the improvements made in previous commits of this branch.
1 parent 770ae8b commit e9d324e

File tree

8 files changed

+508
-0
lines changed

8 files changed

+508
-0
lines changed

tests/run/generic/Color.scala

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package generic
2+
3+
import Shapes._
4+
5+
/** enum Color {
6+
* case Red
7+
* case Green
8+
* case Blue
9+
* }
10+
*/
11+
sealed trait Color extends Enum
12+
13+
object Color extends EnumValues[Color](3) {
14+
15+
private def $new(tag: Int, name: String) = new Color {
16+
def enumTag = tag
17+
override def toString = name
18+
registerEnumValue(this)
19+
}
20+
21+
val Red: Color = $new(0, "Red")
22+
val Green: Color = $new(1, "Green")
23+
val Blue: Color = $new(2, "Blue")
24+
25+
implicit val ColorShape: Color `shaped` EnumValue[Color] =
26+
new (Color `shaped` EnumValue[Color]) {
27+
def toShape(x: Color) = EnumValue(x.enumTag)
28+
def fromShape(x: EnumValue[Color]) = Color.value(x.tag)
29+
}
30+
}

tests/run/generic/Enum.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package generic
2+
3+
import Shapes.Singleton
4+
5+
trait Enum {
6+
def enumTag: Int
7+
}
8+
9+
trait FiniteEnum extends Enum
10+
11+
abstract class EnumValues[E <: Enum](numVals: Int) {
12+
private var myValues = new Array[AnyRef](numVals)
13+
14+
def registerEnumValue(v: E) =
15+
myValues(v.enumTag) = v
16+
17+
def value: IndexedSeq[E] = (myValues: IndexedSeq[AnyRef]).asInstanceOf[IndexedSeq[E]]
18+
}

tests/run/generic/List.scala

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package generic
2+
3+
import Shapes._
4+
5+
/** enum List[T] {
6+
* case Cons(x: T, xs: List[T])
7+
* case Nil()
8+
* }
9+
*/
10+
sealed trait List0[T] extends Enum
11+
object List0 {
12+
abstract case class Cons[T](hd: T, tl: List0[T]) extends List0[T] {
13+
def enumTag = 0
14+
}
15+
object Cons {
16+
def apply[T](x: T, xs: List0[T]): List0[T] = new Cons(x, xs) {}
17+
implicit def ConsShape[T]: Cons[T] `shaped` Prod[T, List0[T]] =
18+
new (Cons[T] `shaped` Prod[T, List0[T]]) {
19+
def toShape(x: Cons[T]) = Prod(x.hd, x.tl)
20+
def fromShape(p: Prod[T, List0[T]]) = new Cons(p.fst, p.snd) {}
21+
}
22+
}
23+
24+
abstract case class Nil[T]() extends List0[T] {
25+
def enumTag = 1
26+
}
27+
object Nil {
28+
def apply[T](): List0[T] = new Nil[T]() {}
29+
implicit def NilShape[T]: Nil[T] `shaped` Unit =
30+
new (Nil[T] `shaped` Unit) {
31+
def toShape(x: Nil[T]) = ()
32+
def fromShape(x: Unit) = new Nil[T]() {}
33+
}
34+
}
35+
36+
implicit def List0Shape[T]: List0[T] `shaped` Sum[Cons[T], Nil[T]] =
37+
new (List0[T] `shaped` Sum[Cons[T], Nil[T]]) {
38+
def toShape(x: List0[T]) = x match {
39+
case x: Cons[T] => Fst(x)
40+
case x: Nil[T] => Snd(x)
41+
}
42+
def fromShape(x: Sum[Cons[T], Nil[T]]) = x match {
43+
case Fst(c) => c
44+
case Snd(n) => n
45+
}
46+
}
47+
}
48+
49+
/** enum List[T] {
50+
* case Cons(x: T, xs: List[T])
51+
* case Nil extends List[Nothing]
52+
* }
53+
*/
54+
sealed trait List[+T] extends Enum
55+
object List {
56+
abstract case class Cons[T](hd: T, tl: List[T]) extends List[T] {
57+
def enumTag = 0
58+
}
59+
object Cons {
60+
def apply[T](x: T, xs: List[T]): List[T] = new Cons(x, xs) {}
61+
type Shape[T] = Prod[T, List[T]]
62+
implicit def ConsShape[T]: Cons[T] `shaped` Shape[T] =
63+
new (Cons[T] `shaped` Shape[T]) {
64+
def toShape(x: Cons[T]) = Prod(x.hd, x.tl)
65+
def fromShape(p: Shape[T]) = new Cons(p.fst, p.snd) {}
66+
}
67+
}
68+
69+
val Nil = new List[Nothing] {
70+
def enumTag = 1
71+
override def toString = "Nil"
72+
}
73+
74+
implicit def NilSingleton: Singleton[Nil.type] = new Singleton[Nil.type](Nil)
75+
76+
type Shape[T] = Sum[Cons[T], Nil.type]
77+
78+
implicit def ListShape[T]: List[T] `unfolds` Shape[T] =
79+
new (List[T] `shaped` Shape[T]) {
80+
def toShape(x: List[T]) = x match {
81+
case x: Cons[T] => Fst(x)
82+
case Nil => Snd(Nil)
83+
}
84+
def fromShape(x: Shape[T]): List[T] = x match {
85+
case Fst(c) => c
86+
case Snd(n) => n
87+
}
88+
}
89+
}

tests/run/generic/SearchResult.scala

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package generic
2+
3+
import Shapes._
4+
5+
/** enum SearchResult {
6+
* case Success(result: Color)
7+
* case Diverging
8+
* case NoMatch
9+
* case Ambiguous(alt1: SearchResult, alt2: SearchResult)
10+
* }
11+
*/
12+
sealed trait SearchResult extends Enum
13+
14+
object SearchResult extends EnumValues[SearchResult](2) {
15+
16+
private def $new(tag: Int, name: String) = new SearchResult {
17+
def enumTag = tag
18+
override def toString = name
19+
registerEnumValue(this)
20+
}
21+
22+
abstract case class Success(result: Color) extends SearchResult {
23+
def enumTag = 0
24+
}
25+
object Success {
26+
def apply(result: Color): SearchResult = new Success(result) {}
27+
implicit def SuccessShape: Success `shaped` Color =
28+
new (Success `shaped` Color) {
29+
def toShape(s: Success) = s.result
30+
def fromShape(c: Color) = new Success(c) {}
31+
}
32+
}
33+
34+
val Diverging = $new(1, "Diverging")
35+
val NoMatch = $new(2, "NoMatch")
36+
37+
abstract case class Ambiguous(alt1: SearchResult, alt2: SearchResult) extends SearchResult {
38+
def enumTag = 3
39+
}
40+
object Ambiguous {
41+
def apply(alt1: SearchResult, alt2: SearchResult): SearchResult = new Ambiguous(alt1, alt2) {}
42+
implicit def AmbiguousShape: Ambiguous `shaped` Prod[SearchResult, SearchResult] =
43+
new (Ambiguous `shaped` Prod[SearchResult, SearchResult]) {
44+
def toShape(a: Ambiguous) = Prod(a.alt1, a.alt2)
45+
def fromShape(p: Prod[SearchResult, SearchResult]) = new Ambiguous(p.fst, p.snd) {}
46+
}
47+
}
48+
49+
implicit def SearchResultShape:
50+
SearchResult `shaped` Sum[Success, Sum[Ambiguous, EnumValue[SearchResult]]] =
51+
new (SearchResult `shaped` Sum[Success, Sum[Ambiguous, EnumValue[SearchResult]]]) {
52+
def toShape(x: SearchResult) = x match {
53+
case x: Success => Fst(x)
54+
case x: Ambiguous => Snd(Fst(x))
55+
case x => Snd(Snd(EnumValue(x.enumTag)))
56+
}
57+
def fromShape(x: Sum[Success, Sum[Ambiguous, EnumValue[SearchResult]]]): SearchResult = x match {
58+
case Fst(s) => s
59+
case Snd(Fst(a)) => a
60+
case Snd(Snd(ev)) => value(ev.tag)
61+
}
62+
}
63+
}

tests/run/generic/Serialization.scala

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package generic
2+
3+
import java.io.{DataInputStream,DataOutputStream}
4+
import scala.collection.generic.GenericCompanion
5+
import scala.collection.mutable.ArrayBuffer
6+
import Shapes._
7+
8+
object Serialization {
9+
10+
trait Serializable[T] {
11+
def write(x: T, out: DataOutputStream): Unit
12+
def read(in: DataInputStream): T
13+
}
14+
15+
implicit val UnitSerializable: Serializable[Unit] =
16+
new Serializable[Unit] {
17+
def write(x: Unit, out: DataOutputStream) = ()
18+
def read(in: DataInputStream) = ()
19+
}
20+
21+
implicit def SingleSerializable[T](implicit
22+
ev1: Singleton[T]
23+
): Serializable[T] = new Serializable[T] {
24+
def write(x: T, out: DataOutputStream) = ()
25+
def read(in: DataInputStream) = ev1.value
26+
}
27+
28+
implicit def EnumValueSerializable[T]: Serializable[EnumValue[T]] =
29+
new Serializable[EnumValue[T]] {
30+
def write(x: EnumValue[T], out: DataOutputStream) = out.writeShort(x.tag)
31+
def read(in: DataInputStream) = EnumValue(in.readShort())
32+
}
33+
34+
implicit val BooleanSerializable: Serializable[Boolean] =
35+
new Serializable[Boolean] {
36+
def write(x: Boolean, out: DataOutputStream) = out.writeBoolean(x)
37+
def read(in: DataInputStream) = in.readBoolean()
38+
}
39+
40+
implicit val IntSerializable: Serializable[Int] =
41+
new Serializable[Int] {
42+
def write(x: Int, out: DataOutputStream) = out.writeInt(x)
43+
def read(in: DataInputStream) = in.readInt()
44+
}
45+
46+
implicit val StringSerializable: Serializable[String] =
47+
new Serializable[String] {
48+
def write(x: String, out: DataOutputStream) = out.writeUTF(x)
49+
def read(in: DataInputStream) = in.readUTF()
50+
}
51+
52+
def RecSerializable[T, U](implicit
53+
ev1: T unfolds U,
54+
ev2: Serializable[U]
55+
): Serializable[T] =
56+
new Serializable[T] {
57+
def write(x: T, out: DataOutputStream) = ev2.write(ev1.toShape(x), out)
58+
def read(in: DataInputStream) = ev1.fromShape(ev2.read(in))
59+
}
60+
61+
implicit def ShapedSerializable[T, U](implicit
62+
ev1: T shaped U,
63+
ev2: Serializable[U]
64+
): Serializable[T] =
65+
new Serializable[T] {
66+
def write(x: T, out: DataOutputStream) = ev2.write(ev1.toShape(x), out)
67+
def read(in: DataInputStream) = ev1.fromShape(ev2.read(in))
68+
}
69+
70+
implicit def SumSerializable[T, U](implicit
71+
// parameters need to be call by name, or we get a recursive lazy val definition in materialized code
72+
ev1: => Serializable[T],
73+
ev2: => Serializable[U]
74+
): Serializable[Sum[T, U]] =
75+
new Serializable[Sum[T, U]] {
76+
def write(x: Sum[T, U], out: DataOutputStream): Unit = x match {
77+
case Fst(y) => out.writeBoolean(false); ev1.write(y, out)
78+
case Snd(y) => out.writeBoolean(true); ev2.write(y, out)
79+
}
80+
def read(in: DataInputStream) = in.readBoolean() match {
81+
case false => Fst(ev1.read(in))
82+
case true => Snd(ev2.read(in))
83+
}
84+
}
85+
86+
implicit def ProdSerializable[T, U](implicit
87+
ev1: Serializable[T],
88+
ev2: Serializable[U]
89+
): Serializable[Prod[T, U]] =
90+
new Serializable[Prod[T, U]] {
91+
def write(x: Prod[T, U], out: DataOutputStream): Unit = {
92+
ev1.write(x.fst, out)
93+
ev2.write(x.snd, out)
94+
}
95+
def read(in: DataInputStream) = {
96+
Prod(ev1.read(in), ev2.read(in))
97+
}
98+
}
99+
100+
implicit def IterableSerializable[I[X] <: Iterable[X], Elem](implicit
101+
ev1: GenericCompanion[I],
102+
ev2: Serializable[Elem]
103+
): Serializable[I[Elem]] =
104+
new Serializable[I[Elem]] {
105+
def write(xs: I[Elem], out: DataOutputStream) = {
106+
out.writeInt(xs.size)
107+
xs.foreach(ev2.write(_, out))
108+
}
109+
def read(in: DataInputStream) = {
110+
val bldr = ev1.newBuilder[Elem]
111+
for (i <- 0 until in.readInt()) bldr += ev2.read(in)
112+
bldr.result()
113+
}
114+
}
115+
}

tests/run/generic/Shapes.scala

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package generic
2+
3+
object Shapes {
4+
5+
trait Sum[+S1, +S2]
6+
case class Fst[+F](x: F) extends Sum[F, Nothing]
7+
case class Snd[+S](x: S) extends Sum[Nothing, S]
8+
9+
case class Prod[+P1, +P2](fst: P1, snd: P2)
10+
11+
case class Singleton[SI](value: SI)
12+
13+
case class EnumValue[E](tag: Int)
14+
15+
trait shaped[SH1, SH2] extends unfolds[SH1, SH2]
16+
17+
trait unfolds[UN1, UN2] {
18+
def toShape(x: UN1): UN2
19+
def fromShape(x: UN2): UN1
20+
}
21+
}
22+

0 commit comments

Comments
 (0)