diff --git a/src/main/scala/pbdirect/PBReader.scala b/src/main/scala/pbdirect/PBReader.scala index 5a9fca8..6d64fd9 100644 --- a/src/main/scala/pbdirect/PBReader.scala +++ b/src/main/scala/pbdirect/PBReader.scala @@ -81,6 +81,14 @@ object PBReader extends PBReaderImplicits { implicit object BooleanReader$ extends PBReader[Boolean] { override def read(input: CodedInputStream): Boolean = input.readBool() } + // Stored as variants, but larger in memory: https://groups.google.com/forum/#!topic/protobuf/Er39mNGnRWU + implicit object ByteReader$ extends PBReader[Byte] { + override def read(input: CodedInputStream): Byte = input.readInt32().toByte + } + // Stored as variants, but larger in memory: https://groups.google.com/forum/#!topic/protobuf/Er39mNGnRWU + implicit object ShortReader$ extends PBReader[Short] { + override def read(input: CodedInputStream): Short = input.readInt32().toShort + } implicit object IntReader$ extends PBReader[Int] { override def read(input: CodedInputStream): Int = input.readInt32() } @@ -180,6 +188,14 @@ trait PBParserImplicits extends LowPriorityPBParserImplicits { instance { (index: Int, bytes: Array[Byte]) => parser.parse(index, bytes).toMap } + implicit def collectionMapParser[K, V](implicit parser: PBParser[List[(K, V)]]): PBParser[collection.Map[K, V]] = + instance { (index: Int, bytes: Array[Byte]) => + parser.parse(index, bytes).toMap + } + implicit def seqParser[A](implicit parser: PBParser[List[A]]): PBParser[Seq[A]] = + instance { (index: Int, bytes: Array[Byte]) => + parser.parse(index, bytes) + } } object PBParser extends PBParserImplicits diff --git a/src/main/scala/pbdirect/PBWriter.scala b/src/main/scala/pbdirect/PBWriter.scala index d0bd930..9cd9f51 100644 --- a/src/main/scala/pbdirect/PBWriter.scala +++ b/src/main/scala/pbdirect/PBWriter.scala @@ -83,6 +83,14 @@ trait PBWriterImplicits extends LowPriorityPBWriterImplicits { override def writeTo(index: Int, value: Boolean, out: CodedOutputStream): Unit = out.writeBool(index, value) } + implicit object ByteWriter extends PBWriter[Byte] { + override def writeTo(index: Int, value: Byte, out: CodedOutputStream): Unit = + out.writeInt32(index, value) + } + implicit object ShortWriter extends PBWriter[Short] { + override def writeTo(index: Int, value: Short, out: CodedOutputStream): Unit = + out.writeInt32(index, value) + } implicit object IntWriter extends PBWriter[Int] { override def writeTo(index: Int, value: Int, out: CodedOutputStream): Unit = out.writeInt32(index, value) @@ -120,6 +128,14 @@ trait PBWriterImplicits extends LowPriorityPBWriterImplicits { instance { (index: Int, value: Map[K, V], out: CodedOutputStream) => writer.writeTo(index, value.toList, out) } + implicit def collectionMapWriter[K, V](implicit writer: PBWriter[List[(K, V)]]): PBWriter[collection.Map[K, V]] = + instance { (index: Int, value: collection.Map[K, V], out: CodedOutputStream) => + writer.writeTo(index, value.toList, out) + } + implicit def seqWriter[A](implicit writer: PBWriter[List[A]]): PBWriter[Seq[A]] = + instance { (index: Int, value: Seq[A], out: CodedOutputStream) => + writer.writeTo(index, value.toList, out) + } implicit def enumWriter[E](implicit values: Enum.Values[E], ordering: Ordering[E]): PBWriter[E] = instance { (index: Int, value: E, out: CodedOutputStream) => out.writeInt32(index, Enum.toInt(value)) diff --git a/src/test/scala/pbdirect/PBReaderSpec.scala b/src/test/scala/pbdirect/PBReaderSpec.scala index f97cde8..5655ac1 100644 --- a/src/test/scala/pbdirect/PBReaderSpec.scala +++ b/src/test/scala/pbdirect/PBReaderSpec.scala @@ -30,6 +30,16 @@ class PBReaderSpec extends WordSpecLike with Matchers { val bytes = Array[Byte](8, 1) bytes.pbTo[BooleanMessage] shouldBe BooleanMessage(Some(true)) } + "read a Byte from Protobuf" in { + case class ByteMessage(value: Option[Byte]) + val bytes = Array[Byte](8, 32) + bytes.pbTo[ByteMessage] shouldBe ByteMessage(Some(32)) + } + "read a Short from Protobuf" in { + case class ShortMessage(value: Option[Short]) + val bytes = Array[Byte](8, -1, 63) + bytes.pbTo[ShortMessage] shouldBe ShortMessage(Some(8191)) + } "read an Int from Protobuf" in { case class IntMessage(value: Option[Int]) val bytes = Array[Byte](8, 5) @@ -105,11 +115,21 @@ class PBReaderSpec extends WordSpecLike with Matchers { val bytes = Array[Byte](8, 1, 8, 2, 8, 3, 8, 4) bytes.pbTo[RepeatedMessage] shouldBe RepeatedMessage(1 :: 2 :: 3 :: 4 :: Nil) } + "read a message with Seq from Protobuf" in { + case class RepeatedMessage(values: Seq[Int]) + val bytes = Array[Byte](8, 1, 8, 2, 8, 3, 8, 4) + bytes.pbTo[RepeatedMessage] shouldBe RepeatedMessage(Seq(1, 2, 3, 4)) + } "read a Map from Protobuf" in { case class MapMessage(values: Map[Int, String]) val bytes = Array[Byte](10, 7, 8, 1, 18, 3, 111, 110, 101, 10, 7, 8, 2, 18, 3, 116, 119, 111) bytes.pbTo[MapMessage] shouldBe MapMessage(Map(1 -> "one", 2 -> "two")) } + "read a scala.collection.Map from Protobuf" in { + case class MapMessage(values: collection.Map[Int, String]) + val bytes = Array[Byte](10, 7, 8, 1, 18, 3, 111, 110, 101, 10, 7, 8, 2, 18, 3, 116, 119, 111) + bytes.pbTo[MapMessage] shouldBe MapMessage(collection.Map(1 -> "one", 2 -> "two")) + } "read a nested message from Protobuf" in { case class InnerMessage(value: Option[Int]) case class OuterMessage(text: Option[String], inner: Option[InnerMessage]) diff --git a/src/test/scala/pbdirect/PBWriterSpec.scala b/src/test/scala/pbdirect/PBWriterSpec.scala index caf39a1..992fb02 100644 --- a/src/test/scala/pbdirect/PBWriterSpec.scala +++ b/src/test/scala/pbdirect/PBWriterSpec.scala @@ -32,6 +32,16 @@ class PBWriterSpec extends WordSpecLike with Matchers { val message = BooleanMessage(Some(true)) message.toPB shouldBe Array[Byte](8, 1) } + "write a Byte to Protobuf" in { + case class ByteMessage(value: Option[Byte]) + val message = ByteMessage(Some(32)) + message.toPB shouldBe Array[Byte](8, 32) + } + "write a Short to Protobuf" in { + case class ShortMessage(value: Option[Short]) + val message = ShortMessage(Some(8191)) + message.toPB shouldBe Array[Byte](8, -1, 63) + } "write an Int to Protobuf" in { case class IntMessage(value: Option[Int]) val message = IntMessage(Some(5)) @@ -105,12 +115,22 @@ class PBWriterSpec extends WordSpecLike with Matchers { val message = RepeatedMessage(1 :: 2 :: 3 :: 4 :: Nil) message.toPB shouldBe Array[Byte](8, 1, 8, 2, 8, 3, 8, 4) } + "write a message with Seq to Protobuf" in { + case class RepeatedMessage(values: Seq[Int]) + val message = RepeatedMessage(Seq(1, 2, 3, 4)) + message.toPB shouldBe Array[Byte](8, 1, 8, 2, 8, 3, 8, 4) + } "write a Map to Protobuf" in { case class MapMessage(values: Map[Int, String]) val message = MapMessage(Map(1 -> "one", 2 -> "two")) message.toPB shouldBe Array[Byte](10, 7, 8, 1, 18, 3, 111, 110, 101, 10, 7, 8, 2, 18, 3, 116, 119, 111) } + "write a scala.collection.Map to Protobuf" in { + case class MapMessage(values: collection.Map[Int, String]) + val message = MapMessage(collection.Map(1 -> "one", 2 -> "two")) + message.toPB shouldBe Array[Byte](10, 7, 8, 1, 18, 3, 111, 110, 101, 10, 7, 8, 2, 18, 3, 116, 119, 111) + } "write a nested message to Protobuf" in { case class InnerMessage(value: Option[Int]) case class OuterMessage(text: Option[String], inner: Option[InnerMessage])