Skip to content
This repository has been archived by the owner. It is now read-only.

Commit

Permalink
add bytestring independent coded streams implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
fomkin committed Feb 11, 2019
0 parents commit eb75ba4
Show file tree
Hide file tree
Showing 13 changed files with 1,725 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .gitignore
@@ -0,0 +1,9 @@
.DS_Store
.idea*
target/
.cache
.classpath
.project
.settings/
*.iml

37 changes: 37 additions & 0 deletions build.sbt
@@ -0,0 +1,37 @@
import Dependencies._

ThisBuild / scalaVersion := "2.12.8"
ThisBuild / version := "0.1.0-SNAPSHOT"
ThisBuild / organization := "com.github.fomkin"
ThisBuild / organizationName := "zhukov"

lazy val protobuf = project
.in(file("protobuf"))
.settings(
name := "zhukov-protobuf"
)

lazy val core = project
.in(file("core"))
.settings(
name := "zhukov-core"
)
.dependsOn(protobuf)

lazy val derivation = project
.in(file("derivation"))
.settings(Project.inConfig(Test)(sbtprotoc.ProtocPlugin.protobufConfigSettings):_*)
.settings(
name := "zhukov-derivation",
testFrameworks += new TestFramework("utest.runner.Framework"),
PB.targets in Test := Seq(scalapb.gen() -> (sourceManaged in Test).value),
PB.targets in Compile := Nil,
PB.protoSources in Test := Seq(file("derivation/src/test/protobuf")),
libraryDependencies := Seq(
scalaPb % Test, utest, // testing
macroCompat, macroParadise, scalaCompiler(scalaVersion.value) // macros
)
)
.dependsOn(core)
lazy val root = (project in file("."))
.aggregate(protobuf, core, derivation)
36 changes: 36 additions & 0 deletions core/src/main/scala/zhukov/Marshaller.scala
@@ -0,0 +1,36 @@
package zhukov

import zhukov.protobuf.{CodedOutputStream, WireFormat}

abstract class Marshaller[@specialized T](val wireType: Int) {


def apply[B: Bytes](stream: CodedOutputStream, value: T): Unit
def apply[B: Bytes](value: T, bufferSize: Int = CodedOutputStream.DEFAULT_BUFFER_SIZE): B
}

object Marshaller {

def apply[T](wireType: Int)(f: (CodedOutputStream, T) => Unit): Marshaller[T] = new Marshaller[T](wireType) {
def apply[B: Bytes](stream: CodedOutputStream, value: T): Unit = f(stream, value)
def apply[B](value: T, bufferSize: Int = CodedOutputStream.DEFAULT_BUFFER_SIZE)(implicit bytes: Bytes[B]): B = {
val buffer = new Array[Byte](bufferSize)
val stream = CodedOutputStream.newInstance(buffer)
apply(stream, value)
bytes.copyFromArray(buffer, 0, bufferSize - stream.spaceLeft())
}
}

// Primitives default instances
implicit val int: Marshaller[Int] = Marshaller(WireFormat.WIRETYPE_VARINT)(_.writeInt32NoTag(_))
implicit val long: Marshaller[Long] = Marshaller(WireFormat.WIRETYPE_VARINT)(_.writeInt64NoTag(_))
implicit val float: Marshaller[Float] = Marshaller(WireFormat.WIRETYPE_FIXED32)(_.writeFloatNoTag(_))
implicit val double: Marshaller[Double] = Marshaller(WireFormat.WIRETYPE_FIXED32)(_.writeDoubleNoTag(_))
implicit val string: Marshaller[String] = Marshaller(WireFormat.WIRETYPE_LENGTH_DELIMITED)(_.writeStringNoTag(_))

// // Sequences
// implicit def iterable[T]: Marshaller[Iterable[T]] =
// Marshaller(WireFormat.WIRETYPE_LENGTH_DELIMITED) { (stream, value) =>
//
// }
}
44 changes: 44 additions & 0 deletions core/src/main/scala/zhukov/Unmarshaller.scala
@@ -0,0 +1,44 @@
package zhukov

import zhukov.protobuf.CodedInputStream

sealed trait Unmarshaller[A] {

def read(stream: CodedInputStream): A

def read[B: Bytes](bytes: B): A = {
val stream = CodedInputStream.newInstance(bytes)
read(stream)
}
}


object Unmarshaller {

trait LengthDelimitedUnmarshaller[A] extends Unmarshaller[A] { self =>
def map[B](f: A => B): LengthDelimitedUnmarshaller[B] =
(stream: CodedInputStream) => f(self.read(stream))
}

trait VarintUnmarshaller[A] extends Unmarshaller[A] { self =>
def map[B](f: A => B): VarintUnmarshaller[B] =
(stream: CodedInputStream) => f(self.read(stream))
}

trait Fixed32Unmarshaller[A] extends Unmarshaller[A] { self =>
def map[B](f: A => B): Fixed32Unmarshaller[B] =
(stream: CodedInputStream) => f(self.read(stream))
}

trait Fixed64Unmarshaller[A] extends Unmarshaller[A] { self =>
def map[B](f: A => B): Fixed64Unmarshaller[B] =
(stream: CodedInputStream) => f(self.read(stream))
}

def apply[T](implicit unmarshaller: Unmarshaller[T]): Unmarshaller[T] =
unmarshaller

implicit val int: VarintUnmarshaller[Int] = _.readRawVarint32()
implicit val long: VarintUnmarshaller[Long] = _.readRawVarint64()
implicit val string: LengthDelimitedUnmarshaller[String] = _.readString()
}
11 changes: 11 additions & 0 deletions project/Dependencies.scala
@@ -0,0 +1,11 @@
import sbt._

object Dependencies {

lazy val scalaPb = "com.thesamet.scalapb" %% "scalapb-runtime" % scalapb.compiler.Version.scalapbVersion
lazy val utest = "com.lihaoyi" %% "utest" % "0.6.6" % Test
lazy val macroCompat = "org.typelevel" %% "macro-compat" % "1.1.1"
lazy val macroParadise = compilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.patch)

def scalaCompiler(scalaVersion: String): ModuleID = "org.scala-lang" % "scala-compiler" % scalaVersion % "provided"
}
1 change: 1 addition & 0 deletions project/build.properties
@@ -0,0 +1 @@
sbt.version=1.2.8
3 changes: 3 additions & 0 deletions project/plugins.sbt
@@ -0,0 +1,3 @@
addSbtPlugin("com.thesamet" % "sbt-protoc" % "0.99.19")

libraryDependencies += "com.thesamet.scalapb" %% "compilerplugin" % "0.8.2"
68 changes: 68 additions & 0 deletions protobuf/src/main/scala/zhukov/Bytes.scala
@@ -0,0 +1,68 @@
package zhukov

import java.nio.ByteBuffer

trait Bytes[T] {
def empty: T
def copyFromArray(bytes: Array[Byte]): T
def copyFromArray(bytes: Array[Byte], offset: Long, size: Long): T
def copyToArray(value: T, array: Array[Byte], sourceOffset: Int, targetOffset: Int, length: Int): Unit
def wrapArray(bytes: Array[Byte]): T
def copyBuffer(buffer: ByteBuffer): T
def toArray(bytes: T): Array[Byte]
def toBuffer(bytes: T): ByteBuffer
def get(bytes: T, i: Long): Int
def size(bytes: T): Long
def concat(left: T, right: T): T
def slice(value: T, start: Long, end: Long): T
}

object Bytes {

def apply[T: Bytes]: Bytes[T] = implicitly[Bytes[T]]

implicit final class BytesOps[T](bytes: T)(implicit instance: Bytes[T]) {
def apply(i: Int): Int = apply(i.toLong)
def apply(i: Long): Int = instance.get(bytes, i)
def concat(right: T): T = instance.concat(bytes, right)
}

implicit object ArrayInstance extends Bytes[Array[Byte]] {

val empty: Array[Byte] =
Array()

def copyFromArray(bytes: Array[Byte]): Array[Byte] =
bytes.clone()

def copyFromArray(bytes: Array[Byte], offset: Long, size: Long): Array[Byte] =
bytes.slice(offset.toInt, (offset + size).toInt)

def copyToArray(value: Array[Byte], array: Array[Byte], sourceOffset: Int, targetOffset: Int, length: Int): Unit =
System.arraycopy(value, sourceOffset, array, targetOffset, length)

def wrapArray(bytes: Array[Byte]): Array[Byte] =
bytes

def copyBuffer(buffer: ByteBuffer): Array[Byte] =
buffer.array()

def toArray(bytes: Array[Byte]): Array[Byte] =
bytes

def toBuffer(bytes: Array[Byte]): ByteBuffer =
ByteBuffer.wrap(bytes)

def get(bytes: Array[Byte], i: Long): Int =
bytes(i.toInt)

def size(bytes: Array[Byte]): Long =
bytes.length.toLong

def concat(left: Array[Byte], right: Array[Byte]): Array[Byte] =
left ++ right

def slice(value: Array[Byte], start: Long, end: Long): Array[Byte] =
value.slice(start.toInt, end.toInt)
}
}

0 comments on commit eb75ba4

Please sign in to comment.