From e1905e13cef567d1ddbe3fd407077dced2aa6b42 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Fri, 3 Apr 2020 22:18:21 -0600 Subject: [PATCH] Actually fix out of order decoding --- protobuf_serialization.nim | 32 +++++++++++++++++++++++--------- tests/test_serialization.nim | 13 +++++++++++++ 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/protobuf_serialization.nim b/protobuf_serialization.nim index ff3ff9a..32489f3 100644 --- a/protobuf_serialization.nim +++ b/protobuf_serialization.nim @@ -90,6 +90,9 @@ proc encodeField*(protobuf: var ProtoBuffer, value: SomeVarint) {.inline.} = protobuf.outstream.encodeField(protobuf.fieldNum, value) inc protobuf.fieldNum +proc encodeField*(protobuf: var ProtoBuffer, fieldNum: int, value: SomeVarint) {.inline.} = + protobuf.outstream.encodeField(fieldNum, value) + proc put(stream: OutputStreamVar, value: SomeLengthDelimited) {.inline.} = for b in value: stream.append byte(b) @@ -103,6 +106,9 @@ proc encodeField*(protobuf: var ProtoBuffer, value: SomeLengthDelimited) {.inlin protobuf.outstream.encodeField(protobuf.fieldNum, value) inc protobuf.fieldNum +proc encodeField*(protobuf: var ProtoBuffer, fieldNum: int, value: SomeLengthDelimited) {.inline.} = + protobuf.outstream.encodeField(fieldNum, value) + proc put(stream: OutputStreamVar, value: object) {.inline.} proc encodeField(stream: OutputStreamVar, fieldNum: int, value: object) {.inline.} = @@ -122,17 +128,24 @@ proc encodeField*(protobuf: var ProtoBuffer, value: object) {.inline.} = protobuf.outstream.encodeField(protobuf.fieldNum, value) inc protobuf.fieldNum +proc encodeField*(protobuf: var ProtoBuffer, fieldNum: int, value: object) {.inline.} = + protobuf.outstream.encodeField(fieldNum, value) + proc encode*(protobuf: var ProtoBuffer, value: object) {.inline.} = var fieldNum = 1 - for field, val in value.fieldPairs: - protobuf.outstream.encodeField(fieldNum, val) + for _, val in value.fieldPairs: + # Only store the value + if default(type(val)) != val: + protobuf.outstream.encodeField(fieldNum, val) inc fieldNum proc put(stream: OutputStreamVar, value: object) {.inline.} = var fieldNum = 1 - for field, val in value.fieldPairs: + for _, val in value.fieldPairs: + # Only store the value + if default(type(val)) != val: stream.encodeField(fieldNum, val) - inc fieldNum + inc fieldNum proc getVarint[T: SomeVarint]( bytes: var seq[byte], @@ -320,12 +333,13 @@ proc decodeField*[T: object]( # read LD header # then read only amount of bytes needed increaseBytesRead() - var index = 1 let decodedSize = getVarint(bytes, uint, outOffset, outBytesProcessed, numBytesToRead) let bytesToRead = some(decodedSize.int) - for field, val in result.value.fieldPairs: - setField(result.value, index, outOffset, outBytesProcessed, bytesToRead, bytes) - inc index + + let oldOffset = outOffset + while outOffset < oldOffset + bytesToRead.get(): + let fieldNum = fieldNumber(bytes[outOffset]) + setField(result.value, fieldNum, outOffset, outBytesProcessed, bytesToRead, bytes) proc decode*[T: object]( bytes: var seq[byte], @@ -334,6 +348,6 @@ proc decode*[T: object]( var bytesRead = 0 var offset = 0 - while bytesRead < bytes.len: + while offset < bytes.len - 1: let fieldNum = fieldNumber(bytes[offset]) setField(result, fieldNum, offset, bytesRead, none(int), bytes) \ No newline at end of file diff --git a/tests/test_serialization.nim b/tests/test_serialization.nim index 16278d4..0247586 100644 --- a/tests/test_serialization.nim +++ b/tests/test_serialization.nim @@ -101,6 +101,19 @@ suite "Test Varint Encoding": let obj = Test3(g: 300, h: 200, i: Test1(a: 100, b: "this is a test"), j: "testing") proto.encode(obj) + var output = proto.output + let decoded = output.decode(Test3) + assert decoded == obj + + test "Can encode/decode out of order object": + var proto = newProtoBuffer() + + let obj = Test3(g: 400, h: 100, i: Test1(a: 100, b: "this is a test"), j: "testing") + proto.encodeField(2, 100) + proto.encodeField(4, "testing") + proto.encodeField(1, 400) + proto.encodeField(3, Test1(a: 100, b: "this is a test")) + var output = proto.output let decoded = output.decode(Test3) assert decoded == obj \ No newline at end of file