Add support for encoding/decoding custom types
This commit is contained in:
parent
86c8143567
commit
fbdce1712d
2 changed files with 76 additions and 4 deletions
|
|
@ -70,6 +70,10 @@ template increaseBytesRead(amount = 1) =
|
||||||
if (bytesRead > numBytesToRead.get()).unlikely:
|
if (bytesRead > numBytesToRead.get()).unlikely:
|
||||||
raise newException(Exception, &"Number of bytes read ({bytesRead}) exceeded bytes requested ({numBytesToRead})")
|
raise newException(Exception, &"Number of bytes read ({bytesRead}) exceeded bytes requested ({numBytesToRead})")
|
||||||
|
|
||||||
|
proc encodeField*[T: not AnyProtoType](protobuf: var ProtoBuffer, value: T) {.inline.}
|
||||||
|
proc encodeField*[T: not AnyProtoType](protobuf: var ProtoBuffer, fieldNum: int, value: T) {.inline.}
|
||||||
|
proc encodeField[T: not AnyProtoType](stream: OutputStreamVar, fieldNum: int, value: T) {.inline.}
|
||||||
|
|
||||||
proc put(stream: OutputStreamVar, value: SomeVarint) {.inline.} =
|
proc put(stream: OutputStreamVar, value: SomeVarint) {.inline.} =
|
||||||
when value is enum:
|
when value is enum:
|
||||||
var value = cast[type(ord(value))](value)
|
var value = cast[type(ord(value))](value)
|
||||||
|
|
@ -153,6 +157,16 @@ proc encodeField*(protobuf: var ProtoBuffer, value: AnyProtoType) {.inline.} =
|
||||||
protobuf.encodeField(protobuf.fieldNum, value)
|
protobuf.encodeField(protobuf.fieldNum, value)
|
||||||
inc protobuf.fieldNum
|
inc protobuf.fieldNum
|
||||||
|
|
||||||
|
proc encodeField[T: not AnyProtoType](stream: OutputStreamVar, fieldNum: int, value: T) {.inline.} =
|
||||||
|
stream.encodeField(fieldNum, value.toBytes)
|
||||||
|
|
||||||
|
proc encodeField*[T: not AnyProtoType](protobuf: var ProtoBuffer, fieldNum: int, value: T) {.inline.} =
|
||||||
|
protobuf.outstream.encodeField(fieldNum, value.toBytes)
|
||||||
|
|
||||||
|
proc encodeField*[T: not AnyProtoType](protobuf: var ProtoBuffer, value: T) {.inline.} =
|
||||||
|
protobuf.encodeField(protobuf.fieldNum, value.toBytes)
|
||||||
|
inc protobuf.fieldNum
|
||||||
|
|
||||||
proc get*[T: SomeFixed](
|
proc get*[T: SomeFixed](
|
||||||
bytes: var seq[byte],
|
bytes: var seq[byte],
|
||||||
ty: typedesc[T],
|
ty: typedesc[T],
|
||||||
|
|
@ -276,6 +290,24 @@ proc decodeField*[T: object](
|
||||||
numBytesToRead = none(int)
|
numBytesToRead = none(int)
|
||||||
): ProtoField[T] {.inline.}
|
): ProtoField[T] {.inline.}
|
||||||
|
|
||||||
|
proc decodeField*[T: not AnyProtoType](
|
||||||
|
bytes: var seq[byte],
|
||||||
|
ty: typedesc[T],
|
||||||
|
outOffset: var int,
|
||||||
|
outBytesProcessed: var int,
|
||||||
|
numBytesToRead = none(int)
|
||||||
|
): ProtoField[T] {.inline.} =
|
||||||
|
|
||||||
|
var bytesRead = 0
|
||||||
|
|
||||||
|
checkType(bytes[outOffset], seq[byte], outOffset)
|
||||||
|
|
||||||
|
result.index = fieldNumber(bytes[outOffset])
|
||||||
|
increaseBytesRead()
|
||||||
|
|
||||||
|
var value = bytes.get(seq[byte], outOffset, outBytesProcessed, numBytesToRead)
|
||||||
|
result.value = value.to(T)
|
||||||
|
|
||||||
macro setField(obj: typed, fieldNum: int, offset: int, bytesProcessed: int, bytesToRead: Option[int], value: untyped): untyped =
|
macro setField(obj: typed, fieldNum: int, offset: int, bytesProcessed: int, bytesToRead: Option[int], value: untyped): untyped =
|
||||||
let typeFields = obj.getTypeInst.getType
|
let typeFields = obj.getTypeInst.getType
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import protobuf_serialization
|
||||||
type
|
type
|
||||||
MyEnum = enum
|
MyEnum = enum
|
||||||
ME1, ME2, ME3
|
ME1, ME2, ME3
|
||||||
type
|
|
||||||
Test1 = object
|
Test1 = object
|
||||||
a: uint
|
a: uint
|
||||||
b: string
|
b: string
|
||||||
|
|
@ -18,6 +18,30 @@ type
|
||||||
i: Test1
|
i: Test1
|
||||||
j: string
|
j: string
|
||||||
k: bool
|
k: bool
|
||||||
|
l: MyInt
|
||||||
|
|
||||||
|
MyInt = distinct int
|
||||||
|
|
||||||
|
proc to*(bytes: var seq[byte], ty: typedesc[MyInt]): MyInt =
|
||||||
|
|
||||||
|
var value: int
|
||||||
|
|
||||||
|
var shiftAmount = 0
|
||||||
|
|
||||||
|
for i in 0 ..< len(bytes):
|
||||||
|
value += int(bytes[i]) shl shiftAmount
|
||||||
|
shiftAmount += 8
|
||||||
|
|
||||||
|
result = MyInt(value)
|
||||||
|
|
||||||
|
proc toBytes*(value: MyInt): seq[byte] =
|
||||||
|
var value = value.int
|
||||||
|
|
||||||
|
while value > 0:
|
||||||
|
result.add byte(value and 0b1111_1111)
|
||||||
|
value = value shr 8
|
||||||
|
|
||||||
|
proc `==`(a, b: MyInt): bool {.borrow.}
|
||||||
|
|
||||||
suite "Test Varint Encoding":
|
suite "Test Varint Encoding":
|
||||||
test "Can encode/decode enum field":
|
test "Can encode/decode enum field":
|
||||||
|
|
@ -55,6 +79,21 @@ suite "Test Varint Encoding":
|
||||||
assert decoded.value == num
|
assert decoded.value == num
|
||||||
assert decoded.index == 1
|
assert decoded.index == 1
|
||||||
|
|
||||||
|
test "Can encode/decode distinct number field":
|
||||||
|
var proto = newProtoBuffer()
|
||||||
|
let num = 114151.MyInt
|
||||||
|
var bytesProcessed: int
|
||||||
|
|
||||||
|
proto.encodeField(num)
|
||||||
|
|
||||||
|
var output = proto.output
|
||||||
|
assert output == @[10.byte, 3, 231, 189, 1]
|
||||||
|
|
||||||
|
var offset = 0
|
||||||
|
let decoded = decodeField(output, MyInt, offset, bytesProcessed)
|
||||||
|
assert decoded.value.int == num.int
|
||||||
|
assert decoded.index == 1
|
||||||
|
|
||||||
test "Can encode/decode float32 number field":
|
test "Can encode/decode float32 number field":
|
||||||
var proto = newProtoBuffer()
|
var proto = newProtoBuffer()
|
||||||
let num = float32(1234.164423)
|
let num = float32(1234.164423)
|
||||||
|
|
@ -180,7 +219,7 @@ suite "Test Varint Encoding":
|
||||||
test "Can encode/decode object field":
|
test "Can encode/decode object field":
|
||||||
var proto = newProtoBuffer()
|
var proto = newProtoBuffer()
|
||||||
|
|
||||||
let obj = Test3(g: 300, h: 200, i: Test1(a: 100, b: "this is a test", c: 'H'), j: "testing", k: true)
|
let obj = Test3(g: 300, h: 200, i: Test1(a: 100, b: "this is a test", c: 'H'), j: "testing", k: true, l: 124521.MyInt)
|
||||||
|
|
||||||
proto.encodeField(obj)
|
proto.encodeField(obj)
|
||||||
var offset, bytesProcessed: int
|
var offset, bytesProcessed: int
|
||||||
|
|
@ -193,7 +232,7 @@ suite "Test Varint Encoding":
|
||||||
test "Can encode/decode object":
|
test "Can encode/decode object":
|
||||||
var proto = newProtoBuffer()
|
var proto = newProtoBuffer()
|
||||||
|
|
||||||
let obj = Test3(g: 300, h: 200, i: Test1(a: 100, b: "this is a test", c: 'H'), j: "testing", k: true)
|
let obj = Test3(g: 300, h: 200, i: Test1(a: 100, b: "this is a test", c: 'H'), j: "testing", k: true, l: 124521.MyInt)
|
||||||
|
|
||||||
proto.encode(obj)
|
proto.encode(obj)
|
||||||
var output = proto.output
|
var output = proto.output
|
||||||
|
|
@ -203,7 +242,8 @@ suite "Test Varint Encoding":
|
||||||
test "Can encode/decode out of order object":
|
test "Can encode/decode out of order object":
|
||||||
var proto = newProtoBuffer()
|
var proto = newProtoBuffer()
|
||||||
|
|
||||||
let obj = Test3(g: 400, h: 100, i: Test1(a: 100, b: "this is a test", c: 'H'), j: "testing", k: true)
|
let obj = Test3(g: 400, h: 100, i: Test1(a: 100, b: "this is a test", c: 'H'), j: "testing", k: true, l: 14514.MyInt)
|
||||||
|
proto.encodeField(6, 14514.MyInt)
|
||||||
proto.encodeField(2, 100)
|
proto.encodeField(2, 100)
|
||||||
proto.encodeField(4, "testing")
|
proto.encodeField(4, "testing")
|
||||||
proto.encodeField(1, 400)
|
proto.encodeField(1, 400)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue