Skip to content

Commit

Permalink
fixed serialization of maps in CBOR optimized codecs
Browse files Browse the repository at this point in the history
  • Loading branch information
Roman Janusz committed Oct 13, 2021
1 parent 8918c76 commit 2d933f1
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 15 deletions.
Expand Up @@ -27,11 +27,18 @@ trait CborOptimizedCodecs {
implicit fac: JFactory[(K, V), M[K, V]]
): GenObjectCodec[M[K, V]] = mkMapCodec(implicit keyCodec => GenCodec.jMapCodec[M, K, V])

private def mkMapCodec[M[X, Y] <: AnyRef, K: GenCodec : OptGenKeyCodec, V: GenCodec](mkStdCodec: GenKeyCodec[K] => GenObjectCodec[M[K, V]])(
implicit fac: Factory[(K, V), M[K, V]]
private def mkMapCodec[M[X, Y] <: AnyRef, K: GenCodec : OptGenKeyCodec, V: GenCodec](
mkStdCodec: GenKeyCodec[K] => GenObjectCodec[M[K, V]]
)(implicit
fac: Factory[(K, V), M[K, V]]
): GenObjectCodec[M[K, V]] = {
implicit val stdObjectCodec: GenObjectCodec[M[K, V]] =
mkStdCodec(OptGenKeyCodec[K].keyCodecOrFallback)
val hexKeysStdCodec = mkStdCodec(new GenKeyCodec[K] {
def read(key: String): K = CborInput.readRawCbor[K](RawCbor.fromHex(key))
def write(value: K): String = CborOutput.writeRawCbor[K](value).toString
})

val regularStdCodec =
OptGenKeyCodec[K].keyCodec.map(mkStdCodec).getOrElse(hexKeysStdCodec)

val cborKeyCodec = new CborKeyCodec {
def writeFieldKey(fieldName: String, output: CborOutput): Unit =
Expand All @@ -40,7 +47,19 @@ trait CborOptimizedCodecs {
input.readRawCbor().toString
}

new CborRawKeysCodec(stdObjectCodec, cborKeyCodec)
new GenObjectCodec[M[K, V]] {
override def readObject(input: ObjectInput): M[K, V] =
if (input.customEvent(ForceCborKeyCodec, cborKeyCodec))
hexKeysStdCodec.readObject(input)
else
regularStdCodec.readObject(input)

override def writeObject(output: ObjectOutput, value: M[K, V]): Unit =
if (output.customEvent(ForceCborKeyCodec, cborKeyCodec))
hexKeysStdCodec.writeObject(output, value)
else
regularStdCodec.writeObject(output, value)
}
}
}
object CborOptimizedCodecs extends CborOptimizedCodecs
Expand Down Expand Up @@ -78,13 +97,7 @@ class OOOFieldCborRawKeysCodec[T](stdObjectCodec: OOOFieldsObjectCodec[T], keyCo
* type, [[CborRawKeysCodec]] can still work with non-CBOR inputs/outputs by serializing keys into CBOR and taking
* their HEX representation as standard string keys.
*/
case class OptGenKeyCodec[K](keyCodec: Opt[GenKeyCodec[K]]) {
def keyCodecOrFallback(implicit codec: GenCodec[K]): GenKeyCodec[K] =
keyCodec.getOrElse(new GenKeyCodec[K] {
def read(key: String): K = CborInput.readRawCbor[K](RawCbor.fromHex(key))
def write(value: K): String = CborOutput.writeRawCbor[K](value).toString
})
}
case class OptGenKeyCodec[K](keyCodec: Opt[GenKeyCodec[K]])
object OptGenKeyCodec extends OptGenKeyCodecLowPriority {
def apply[K](implicit optGenKeyCodec: OptGenKeyCodec[K]): OptGenKeyCodec[K] = optGenKeyCodec

Expand Down
Expand Up @@ -4,6 +4,7 @@ package serialization.cbor
import com.avsystem.commons.misc.{Bytes, Timestamp}
import com.avsystem.commons.serialization.GenCodec.ReadFailure
import com.avsystem.commons.serialization._
import com.avsystem.commons.serialization.json.JsonStringOutput
import org.scalactic.source.Position
import org.scalatest.funsuite.AnyFunSuite

Expand All @@ -22,7 +23,8 @@ case class CustomKeysRecord(
@cborKey(1) first: Int,
@cborKey(true) second: Boolean,
@cborKey(Vector(1, 2, 3)) third: String,
map: Map[Int, String]
strMap: Map[String, Int],
intMap: Map[Int, String],
)
object CustomKeysRecord extends HasCborCodec[CustomKeysRecord]

Expand Down Expand Up @@ -173,8 +175,8 @@ class CborInputOutputTest extends AnyFunSuite {
)

roundtrip(
CustomKeysRecord(42, second = false, "foo", Map(0 -> "bar")),
"A401182AF5F48301020363666F6F636D6170A10063626172"
CustomKeysRecord(42, second = false, "foo", Map("bar" -> 0), Map(0 -> "bar")),
"A501182AF5F48301020363666F6F667374724D6170A1636261720066696E744D6170A10063626172"
)

roundtrip(
Expand All @@ -197,6 +199,11 @@ class CborInputOutputTest extends AnyFunSuite {
"9FA101A101182AA102A10163666F6FA168426F6F6C43617365A164626F6F6CF5A103A0FF"
)

test("writing with CBOR optimized codec to non-CBOR output") {
assert(JsonStringOutput.write(CustomKeysRecord(42, second = true, "foo", Map("foo" -> 1), Map(1 -> "foo"))) ==
"""{"first":42,"second":true,"third":"foo","strMap":{"foo":1},"intMap":{"1":"foo"}}""")
}

test("chunked text string") {
assert(CborInput.readRawCbor[String](RawCbor.fromHex("7F626162626162626162FF")) == "ababab")
}
Expand Down

0 comments on commit 2d933f1

Please sign in to comment.