aboutsummaryrefslogtreecommitdiff
path: root/tests/run/generic/Serialization.scala
blob: a82d6bc7a1006648dafd270a5b43daad0a3a16a7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package generic

import java.io.{DataInputStream,DataOutputStream}
import scala.collection.generic.GenericCompanion
import scala.collection.mutable.ArrayBuffer
import Shapes._

object Serialization {

  trait Serializable[T] {
    def write(x: T, out: DataOutputStream): Unit
    def read(in: DataInputStream): T
  }

  implicit val UnitSerializable: Serializable[Unit] =
    new Serializable[Unit] {
      def write(x: Unit, out: DataOutputStream) = ()
      def read(in: DataInputStream) = ()
    }

  implicit def SingleSerializable[T](implicit
      ev1: Singleton[T]
  ): Serializable[T] = new Serializable[T] {
    def write(x: T, out: DataOutputStream) = ()
    def read(in: DataInputStream) = ev1.value
  }

  implicit def EnumValueSerializable[T]: Serializable[EnumValue[T]] =
    new Serializable[EnumValue[T]] {
      def write(x: EnumValue[T], out: DataOutputStream) = out.writeShort(x.tag)
      def read(in: DataInputStream) = EnumValue(in.readShort())
    }

  implicit val BooleanSerializable: Serializable[Boolean] =
    new Serializable[Boolean] {
      def write(x: Boolean, out: DataOutputStream) = out.writeBoolean(x)
      def read(in: DataInputStream) = in.readBoolean()
    }

  implicit val IntSerializable: Serializable[Int] =
    new Serializable[Int] {
      def write(x: Int, out: DataOutputStream) = out.writeInt(x)
      def read(in: DataInputStream) = in.readInt()
    }

  implicit val StringSerializable: Serializable[String] =
    new Serializable[String] {
      def write(x: String, out: DataOutputStream) = out.writeUTF(x)
      def read(in: DataInputStream) = in.readUTF()
    }

  def RecSerializable[T, U](implicit
      ev1: T unfolds U,
      ev2: Serializable[U]
    ): Serializable[T]  =
    new Serializable[T] {
      def write(x: T, out: DataOutputStream) = ev2.write(ev1.toShape(x), out)
      def read(in: DataInputStream) = ev1.fromShape(ev2.read(in))
    }

  implicit def ShapedSerializable[T, U](implicit
      ev1: T shaped U,
      ev2: Serializable[U]
    ): Serializable[T]  =
    new Serializable[T] {
      def write(x: T, out: DataOutputStream) = ev2.write(ev1.toShape(x), out)
      def read(in: DataInputStream) = ev1.fromShape(ev2.read(in))
    }

  implicit def SumSerializable[T, U](implicit
    // parameters need to be call by name, or we get a recursive lazy val definition in materialized code
    ev1: => Serializable[T],
    ev2: => Serializable[U]
  ): Serializable[Sum[T, U]] =
    new Serializable[Sum[T, U]] {
      def write(x: Sum[T, U], out: DataOutputStream): Unit = x match {
        case Fst(y) => out.writeBoolean(false); ev1.write(y, out)
        case Snd(y) => out.writeBoolean(true); ev2.write(y, out)
      }
      def read(in: DataInputStream) = in.readBoolean() match {
        case false => Fst(ev1.read(in))
        case true => Snd(ev2.read(in))
      }
    }

  implicit def ProdSerializable[T, U](implicit
    ev1: Serializable[T],
    ev2: Serializable[U]
  ): Serializable[Prod[T, U]] =
    new Serializable[Prod[T, U]] {
      def write(x: Prod[T, U], out: DataOutputStream): Unit = {
        ev1.write(x.fst, out)
        ev2.write(x.snd, out)
      }
    def read(in: DataInputStream) = {
      Prod(ev1.read(in), ev2.read(in))
    }
  }

  implicit def IterableSerializable[I[X] <: Iterable[X], Elem](implicit
    ev1: GenericCompanion[I],
    ev2: Serializable[Elem]
  ): Serializable[I[Elem]] =
    new Serializable[I[Elem]] {
      def write(xs: I[Elem], out: DataOutputStream) = {
        out.writeInt(xs.size)
        xs.foreach(ev2.write(_, out))
      }
      def read(in: DataInputStream) = {
        val bldr = ev1.newBuilder[Elem]
        for (i <- 0 until in.readInt()) bldr += ev2.read(in)
        bldr.result()
      }
    }
}