Lightweight and fast serialization library for Scala 2/3 based on Protocol Buffers with macros magic.
Serialization library for Scala that can be used either for long term store models and short term models. With easy to migrate possibility.
- Lightweight
- Fast
- Protocol Buffers compatible
- No .proto files
- No model convertation
- Type safe
- Serialization/deserialization without changes in models
- Possibility to use specific types in model
Add dependency:
libraryDependencies += "io.github.zero-deps" %% "proto" % "latest.integration"
Dependency as a git-submodule is also supported.
data | library | scala-2 | scala-3 | |
---|---|---|---|---|
data | decode | java | 44079.139 |
38979.697 |
data | decode | jackson | 176941.468 |
188555.562 |
data | decode | jsoniter-scala | 483788.001 |
no support for Scala 3 |
data | decode | boopickle | 2885610.648 |
no support for Scala 3 |
data | decode | proto | 3383845.458 |
3776688.591 |
data | decode | scalapb | 3270691.564 |
3893847.420 |
data | library | scala-2 | scala-3 | |
---|---|---|---|---|
data | encode | java | 220444.268 |
217484.396 |
data | encode | jackson | 431318.803 |
384863.249 |
data | encode | jsoniter-scala | 1054650.233 |
no support for Scala 3 |
data | encode | boopickle | 1520834.519 |
no support for Scala 3 |
data | encode | proto | 3186951.441 |
2965427.382 |
data | encode | scalapb | 3628779.864 |
3972905.402 |
data | library | scala-2 | scala-3 | |
---|---|---|---|---|
msg | decode | jsoniter-scala | 3486552.303 |
no support for Scala 3 |
msg | decode | proto | 5825174.170 |
6395557.251 |
msg | decode | scalapb | 4898257.671 |
6902064.854 |
data | library | scala-2 | scala-3 | |
---|---|---|---|---|
msg | encode | jsoniter-scala | 6372602.760 |
no support for Scala 3 |
msg | encode | proto | 6487748.959 |
6745673.393 |
msg | encode | scalapb | 9202135.451 |
9056962.541 |
Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz
16 GB 2133 MHz LPDDR3
Java 15
sbt
project bench
++ 3.0.0
jmh:run -i 2 -wi 1 -f1 -t1
data | library | scala-3 | |
---|---|---|---|
data | decode | java | 92130,460 |
data | decode | jackson | 517036,354 |
data | decode | proto | 6716619,956 |
data | library | scala-3 | |
---|---|---|---|
data | encode | java | 537462,511 |
data | encode | jackson | 882065,311 |
data | encode | proto | 9380874,587 |
data | library | scala-3 | |
---|---|---|---|
msg | decode | proto | 11733555,275 |
data | library | scala-3 | |
---|---|---|---|
msg | encode | proto | 18486833,582 |
Apple M1
16 GB
Java 21
sbt
project bench
++ 3.0.0
jmh:run -i 2 -wi 1 -f1 -t1
You can pick one of the way how to define field number:
- with annotation
@proto.N
and usecaseCodecAuto
- explicitly specify nums
caseCodecNums(Symbol("field1")->1, Symbol("field2")->2)
- field numbers by index
caseCodecIdx
You can use annotation @proto.RestrictedN
to restrict usage of specified field numbers. Can be used with classes or traits.
import scala.collection.immutable.TreeMap
import proto.{encode, decode, N}
import proto.{caseCodecIdx, caseCodecNums, caseCodecAuto}
final case class VectorClock(versions: TreeMap[String, Long])
@RestrictedN(3,4)
final case class Equipment(@N(1) id: String, @N(2) tpe: String)
final case class Car(id: String, color: Int, equipment: List[Equipment], vc: VectorClock)
implicit val tuple2Codec = caseCodecIdx[Tuple2[String, Long]] //codec for TreeMap[String, Long]
implicit val vectorClockCodec = caseCodecIdx[VectorClock]
implicit val equipmentCodec = caseCodecAuto[Equipment]
implicit val carCodec = caseCodecNums[Car]('id->1, 'color->4, 'equipment->2, 'vc->3)
val vc = VectorClock(versions=TreeMap.empty)
val equipment = List(Equipment(id="1", tpe="123"), Equipment(id="2", tpe="456"))
val car = Car(id="1", color=16416882, equipment=equipment, vc=vc)
//encode
val bytes: Array[Byte] = encode(car)
//decode
val car2: Car = decode[Car](bytes)
More examples in testing.scala