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() } } }