Add object field decoding. Refactor proc names to be inline with behavior
This commit is contained in:
parent
5f2219bae7
commit
2db4d48802
2 changed files with 61 additions and 42 deletions
|
|
@ -65,7 +65,7 @@ template increaseBytesRead(amount = 1) =
|
||||||
outBytesProcessed += amount
|
outBytesProcessed += amount
|
||||||
if numBytesToRead.isSome():
|
if numBytesToRead.isSome():
|
||||||
if (bytesRead > numBytesToRead.get()).unlikely:
|
if (bytesRead > numBytesToRead.get()).unlikely:
|
||||||
raise newException(Exception, "Number of bytes read exceeded")
|
raise newException(Exception, &"Number of bytes read ({bytesRead}) exceeded bytes requested ({numBytesToRead})")
|
||||||
|
|
||||||
proc put(stream: OutputStreamVar, value: SomeVarint) {.inline.} =
|
proc put(stream: OutputStreamVar, value: SomeVarint) {.inline.} =
|
||||||
when value is enum:
|
when value is enum:
|
||||||
|
|
@ -87,30 +87,30 @@ proc put(stream: OutputStreamVar, value: SomeVarint) {.inline.} =
|
||||||
value = value shr 7
|
value = value shr 7
|
||||||
stream.append byte(value and 0b1111_1111)
|
stream.append byte(value and 0b1111_1111)
|
||||||
|
|
||||||
proc encode(stream: OutputStreamVar, fieldNum: int, value: SomeVarint) {.inline.} =
|
proc encodeField(stream: OutputStreamVar, fieldNum: int, value: SomeVarint) {.inline.} =
|
||||||
stream.append protoHeader(fieldNum, Varint)
|
stream.append protoHeader(fieldNum, Varint)
|
||||||
stream.put(value)
|
stream.put(value)
|
||||||
|
|
||||||
proc encode*(protobuf: var ProtoBuffer, value: SomeVarint) {.inline.} =
|
proc encodeField*(protobuf: var ProtoBuffer, value: SomeVarint) {.inline.} =
|
||||||
protobuf.outstream.encode(protobuf.fieldNum, value)
|
protobuf.outstream.encodeField(protobuf.fieldNum, value)
|
||||||
inc protobuf.fieldNum
|
inc protobuf.fieldNum
|
||||||
|
|
||||||
proc put(stream: OutputStreamVar, value: SomeLengthDelimited) {.inline.} =
|
proc put(stream: OutputStreamVar, value: SomeLengthDelimited) {.inline.} =
|
||||||
for b in value:
|
for b in value:
|
||||||
stream.append byte(b)
|
stream.append byte(b)
|
||||||
|
|
||||||
proc encode(stream: OutputStreamVar, fieldNum: int, value: SomeLengthDelimited) {.inline.} =
|
proc encodeField(stream: OutputStreamVar, fieldNum: int, value: SomeLengthDelimited) {.inline.} =
|
||||||
stream.append protoHeader(fieldNum, LengthDelimited)
|
stream.append protoHeader(fieldNum, LengthDelimited)
|
||||||
stream.put(len(value).uint)
|
stream.put(len(value).uint)
|
||||||
stream.put(value)
|
stream.put(value)
|
||||||
|
|
||||||
proc encode*(protobuf: var ProtoBuffer, value: SomeLengthDelimited) {.inline.} =
|
proc encodeField*(protobuf: var ProtoBuffer, value: SomeLengthDelimited) {.inline.} =
|
||||||
protobuf.outstream.encode(protobuf.fieldNum, value)
|
protobuf.outstream.encodeField(protobuf.fieldNum, value)
|
||||||
inc protobuf.fieldNum
|
inc protobuf.fieldNum
|
||||||
|
|
||||||
proc put(stream: OutputStreamVar, value: object) {.inline.}
|
proc put(stream: OutputStreamVar, value: object) {.inline.}
|
||||||
|
|
||||||
proc encode(stream: OutputStreamVar, fieldNum: int, value: object) {.inline.} =
|
proc encodeField(stream: OutputStreamVar, fieldNum: int, value: object) {.inline.} =
|
||||||
#TODO Encode generic objects
|
#TODO Encode generic objects
|
||||||
stream.append protoHeader(fieldNum, LengthDelimited)
|
stream.append protoHeader(fieldNum, LengthDelimited)
|
||||||
let objStream = OutputStream.init()
|
let objStream = OutputStream.init()
|
||||||
|
|
@ -119,14 +119,14 @@ proc encode(stream: OutputStreamVar, fieldNum: int, value: object) {.inline.} =
|
||||||
stream.put(len(objOutput).uint)
|
stream.put(len(objOutput).uint)
|
||||||
stream.put(objOutput)
|
stream.put(objOutput)
|
||||||
|
|
||||||
proc encode*(protobuf: var ProtoBuffer, value: object) {.inline.} =
|
proc encodeField*(protobuf: var ProtoBuffer, value: object) {.inline.} =
|
||||||
protobuf.outstream.encode(protobuf.fieldNum, value)
|
protobuf.outstream.encodeField(protobuf.fieldNum, value)
|
||||||
inc protobuf.fieldNum
|
inc protobuf.fieldNum
|
||||||
|
|
||||||
proc put(stream: OutputStreamVar, value: object) {.inline.} =
|
proc put(stream: OutputStreamVar, value: object) {.inline.} =
|
||||||
var fieldNum = 1
|
var fieldNum = 1
|
||||||
for field, val in value.fieldPairs:
|
for field, val in value.fieldPairs:
|
||||||
stream.encode(fieldNum, val)
|
stream.encodeField(fieldNum, val)
|
||||||
fieldNum += 1
|
fieldNum += 1
|
||||||
|
|
||||||
proc getVarint[T: SomeVarint](
|
proc getVarint[T: SomeVarint](
|
||||||
|
|
@ -160,7 +160,7 @@ proc getVarint[T: SomeVarint](
|
||||||
else:
|
else:
|
||||||
result = value
|
result = value
|
||||||
|
|
||||||
proc decode*[T: SomeVarint](
|
proc decodeField*[T: SomeVarint](
|
||||||
bytes: var seq[byte],
|
bytes: var seq[byte],
|
||||||
ty: typedesc[T],
|
ty: typedesc[T],
|
||||||
outOffset: var int,
|
outOffset: var int,
|
||||||
|
|
@ -205,7 +205,7 @@ proc getLengthDelimited*[T: SomeLengthDelimited](
|
||||||
|
|
||||||
increaseBytesRead(length)
|
increaseBytesRead(length)
|
||||||
|
|
||||||
proc decode*[T: SomeLengthDelimited](
|
proc decodeField*[T: SomeLengthDelimited](
|
||||||
bytes: var seq[byte],
|
bytes: var seq[byte],
|
||||||
ty: typedesc[T],
|
ty: typedesc[T],
|
||||||
outOffset: var int,
|
outOffset: var int,
|
||||||
|
|
@ -283,7 +283,7 @@ macro setField(obj: typed, fieldNum: int, offset: int, bytesProcessed: int, byte
|
||||||
ofBranch.add(newLit(i+1))
|
ofBranch.add(newLit(i+1))
|
||||||
ofBranch.add(
|
ofBranch.add(
|
||||||
quote do:
|
quote do:
|
||||||
`obj`.`field` = decode(`value`, type(`obj`.`field`), `offset`, `bytesProcessed`, `bytesToRead`).value
|
`obj`.`field` = decodeField(`value`, type(`obj`.`field`), `offset`, `bytesProcessed`, `bytesToRead`).value
|
||||||
)
|
)
|
||||||
caseStmt.add(ofBranch)
|
caseStmt.add(ofBranch)
|
||||||
|
|
||||||
|
|
@ -292,14 +292,13 @@ macro setField(obj: typed, fieldNum: int, offset: int, bytesProcessed: int, byte
|
||||||
elseBranch.add(
|
elseBranch.add(
|
||||||
nnkStmtList.newTree(
|
nnkStmtList.newTree(
|
||||||
quote do:
|
quote do:
|
||||||
`obj`.`field` = decode(`value`, type(`obj`.`field`), `offset`, `bytesProcessed`, `bytesToRead`).value
|
`obj`.`field` = decodeField(`value`, type(`obj`.`field`), `offset`, `bytesProcessed`, `bytesToRead`).value
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
caseStmt.add(elseBranch)
|
caseStmt.add(elseBranch)
|
||||||
|
|
||||||
result.add(caseStmt)
|
result.add(caseStmt)
|
||||||
|
|
||||||
proc decode*[T: object](
|
proc decodeField*[T: object](
|
||||||
bytes: var seq[byte],
|
bytes: var seq[byte],
|
||||||
ty: typedesc[T],
|
ty: typedesc[T],
|
||||||
outOffset: var int,
|
outOffset: var int,
|
||||||
|
|
@ -309,15 +308,28 @@ proc decode*[T: object](
|
||||||
var bytesRead = 0
|
var bytesRead = 0
|
||||||
|
|
||||||
let wireTy = wireType(bytes[outOffset])
|
let wireTy = wireType(bytes[outOffset])
|
||||||
|
assert wireTy == LengthDelimited
|
||||||
|
|
||||||
result.index = fieldNumber(bytes[outOffset])
|
result.index = fieldNumber(bytes[outOffset])
|
||||||
|
|
||||||
if wireTy == LengthDelimited:
|
# read LD header
|
||||||
# read LD header
|
# then read only amount of bytes needed
|
||||||
# then read only amount of bytes needed
|
increaseBytesRead()
|
||||||
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)
|
||||||
|
index += 1
|
||||||
|
|
||||||
let decodedSize = getVarint(bytes, uint, outOffset, outBytesProcessed, numBytesToRead)
|
proc decode*[T: object](
|
||||||
let bytesToRead = some(decodedSize.int)
|
bytes: var seq[byte],
|
||||||
setField(result.value, result.index, outOffset, outBytesProcessed, bytesToRead, bytes)
|
ty: typedesc[T],
|
||||||
else:
|
): T {.inline.} =
|
||||||
setField(result.value, result.index, outOffset, outBytesProcessed, numBytesToRead, bytes)
|
var bytesRead = 0
|
||||||
|
var offset = 0
|
||||||
|
|
||||||
|
var fieldNum = 1
|
||||||
|
for field, val in result.fieldPairs:
|
||||||
|
setField(result, fieldNum, offset, bytesRead, none(int), bytes)
|
||||||
|
fieldNum += 1
|
||||||
|
|
@ -18,17 +18,20 @@ suite "Test Varint Encoding":
|
||||||
test "Can encode/decode enum":
|
test "Can encode/decode enum":
|
||||||
var proto = newProtoBuffer()
|
var proto = newProtoBuffer()
|
||||||
var bytesProcessed: int
|
var bytesProcessed: int
|
||||||
proto.encode(ME3)
|
|
||||||
proto.encode(ME2)
|
proto.encodeField(ME3)
|
||||||
|
proto.encodeField(ME2)
|
||||||
|
|
||||||
var output = proto.output
|
var output = proto.output
|
||||||
assert output == @[8.byte, 4, 16, 2]
|
assert output == @[8.byte, 4, 16, 2]
|
||||||
|
|
||||||
var offset = 0
|
var offset = 0
|
||||||
|
|
||||||
let decodedME3 = decode(output, MyEnum, offset, bytesProcessed)
|
let decodedME3 = decodeField(output, MyEnum, offset, bytesProcessed)
|
||||||
assert decodedME3.value == ME3
|
assert decodedME3.value == ME3
|
||||||
assert decodedME3.index == 1
|
assert decodedME3.index == 1
|
||||||
|
|
||||||
let decodedME2 = decode(output, MyEnum, offset, bytesProcessed)
|
let decodedME2 = decodeField(output, MyEnum, offset, bytesProcessed)
|
||||||
assert decodedME2.value == ME2
|
assert decodedME2.value == ME2
|
||||||
assert decodedME2.index == 2
|
assert decodedME2.index == 2
|
||||||
|
|
||||||
|
|
@ -36,12 +39,14 @@ suite "Test Varint Encoding":
|
||||||
var proto = newProtoBuffer()
|
var proto = newProtoBuffer()
|
||||||
let num = -153452
|
let num = -153452
|
||||||
var bytesProcessed: int
|
var bytesProcessed: int
|
||||||
proto.encode(num)
|
|
||||||
|
proto.encodeField(num)
|
||||||
|
|
||||||
var output = proto.output
|
var output = proto.output
|
||||||
assert output == @[8.byte, 215, 221, 18]
|
assert output == @[8.byte, 215, 221, 18]
|
||||||
|
|
||||||
var offset = 0
|
var offset = 0
|
||||||
let decoded = decode(output, int, offset, bytesProcessed)
|
let decoded = decodeField(output, int, offset, bytesProcessed)
|
||||||
assert decoded.value == num
|
assert decoded.value == num
|
||||||
assert decoded.index == 1
|
assert decoded.index == 1
|
||||||
|
|
||||||
|
|
@ -49,12 +54,14 @@ suite "Test Varint Encoding":
|
||||||
var proto = newProtoBuffer()
|
var proto = newProtoBuffer()
|
||||||
let num = 123151.uint
|
let num = 123151.uint
|
||||||
var bytesProcessed: int
|
var bytesProcessed: int
|
||||||
proto.encode(num)
|
|
||||||
|
proto.encodeField(num)
|
||||||
|
|
||||||
var output = proto.output
|
var output = proto.output
|
||||||
assert output == @[8.byte, 143, 194, 7]
|
assert output == @[8.byte, 143, 194, 7]
|
||||||
var offset = 0
|
var offset = 0
|
||||||
|
|
||||||
let decoded = decode(output, uint, offset, bytesProcessed)
|
let decoded = decodeField(output, uint, offset, bytesProcessed)
|
||||||
assert decoded.value == num
|
assert decoded.value == num
|
||||||
assert decoded.index == 1
|
assert decoded.index == 1
|
||||||
|
|
||||||
|
|
@ -62,12 +69,14 @@ suite "Test Varint Encoding":
|
||||||
var proto = newProtoBuffer()
|
var proto = newProtoBuffer()
|
||||||
let str = "hey this is a string"
|
let str = "hey this is a string"
|
||||||
var bytesProcessed: int
|
var bytesProcessed: int
|
||||||
proto.encode(str)
|
|
||||||
|
proto.encodeField(str)
|
||||||
|
|
||||||
var output = proto.output
|
var output = proto.output
|
||||||
assert output == @[10.byte, 20, 104, 101, 121, 32, 116, 104, 105, 115, 32, 105, 115, 32, 97, 32, 115, 116, 114, 105, 110, 103]
|
assert output == @[10.byte, 20, 104, 101, 121, 32, 116, 104, 105, 115, 32, 105, 115, 32, 97, 32, 115, 116, 114, 105, 110, 103]
|
||||||
|
|
||||||
var offset = 0
|
var offset = 0
|
||||||
let decoded = decode(output, string, offset, bytesProcessed)
|
let decoded = decodeField(output, string, offset, bytesProcessed)
|
||||||
assert decoded.value == str
|
assert decoded.value == str
|
||||||
assert decoded.index == 1
|
assert decoded.index == 1
|
||||||
|
|
||||||
|
|
@ -76,12 +85,10 @@ suite "Test Varint Encoding":
|
||||||
|
|
||||||
let obj = Test3(g: 300, h: 200, i: Test1(a: 100))
|
let obj = Test3(g: 300, h: 200, i: Test1(a: 100))
|
||||||
|
|
||||||
proto.encode(obj)
|
proto.encodeField(obj)
|
||||||
var offset, bytesProcessed: int
|
var offset, bytesProcessed: int
|
||||||
|
|
||||||
var output = proto.output
|
var output = proto.output
|
||||||
let decoded = decode(output, Test3, offset, bytesProcessed)
|
let decoded = decodeField(output, Test3, offset, bytesProcessed)
|
||||||
echo decoded
|
assert decoded.value == obj
|
||||||
|
assert decoded.index == 1
|
||||||
echo output
|
|
||||||
assert false
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue