Add support for float32 and float64
This commit is contained in:
parent
d750cac498
commit
f26b941bd7
2 changed files with 99 additions and 38 deletions
|
|
@ -35,6 +35,11 @@ type
|
||||||
SomeUVarint* = uint | uint64 | uint32 | uint16 | SomeByte
|
SomeUVarint* = uint | uint64 | uint32 | uint16 | SomeByte
|
||||||
SomeVarint* = SomeSVarint | SomeUVarint
|
SomeVarint* = SomeSVarint | SomeUVarint
|
||||||
SomeLengthDelimited* = string | seq[SomeByte] | cstring
|
SomeLengthDelimited* = string | seq[SomeByte] | cstring
|
||||||
|
SomeFixed64* = float64
|
||||||
|
SomeFixed32* = float32
|
||||||
|
SomeFixed* = SomeFixed32 | SomeFixed64
|
||||||
|
|
||||||
|
AnyProtoType* = SomeVarint | SomeLengthDelimited | SomeFixed | object
|
||||||
|
|
||||||
proc newProtoBuffer*(): ProtoBuffer =
|
proc newProtoBuffer*(): ProtoBuffer =
|
||||||
ProtoBuffer(outstream: OutputStream.init(), fieldNum: 1)
|
ProtoBuffer(outstream: OutputStream.init(), fieldNum: 1)
|
||||||
|
|
@ -87,12 +92,23 @@ proc encodeField(stream: OutputStreamVar, fieldNum: int, value: SomeVarint) {.in
|
||||||
stream.append protoHeader(fieldNum, Varint)
|
stream.append protoHeader(fieldNum, Varint)
|
||||||
stream.put(value)
|
stream.put(value)
|
||||||
|
|
||||||
proc encodeField*(protobuf: var ProtoBuffer, value: SomeVarint) {.inline.} =
|
proc put(stream: OutputStreamVar, value: SomeFixed) {.inline.} =
|
||||||
protobuf.outstream.encodeField(protobuf.fieldNum, value)
|
when typeof(value) is SomeFixed64:
|
||||||
inc protobuf.fieldNum
|
var value = cast[int64](value)
|
||||||
|
else:
|
||||||
|
var value = cast[int32](value)
|
||||||
|
|
||||||
proc encodeField*(protobuf: var ProtoBuffer, fieldNum: int, value: SomeVarint) {.inline.} =
|
for _ in 0 ..< sizeof(value):
|
||||||
protobuf.outstream.encodeField(fieldNum, value)
|
stream.append byte(value and 0b1111_1111)
|
||||||
|
value = value shr 8
|
||||||
|
|
||||||
|
proc encodeField(stream: OutputStreamVar, fieldNum: int, value: SomeFixed64) {.inline.} =
|
||||||
|
stream.append protoHeader(fieldNum, Fixed64)
|
||||||
|
stream.put(value)
|
||||||
|
|
||||||
|
proc encodeField(stream: OutputStreamVar, fieldNum: int, value: SomeFixed32) {.inline.} =
|
||||||
|
stream.append protoHeader(fieldNum, Fixed32)
|
||||||
|
stream.put(value)
|
||||||
|
|
||||||
proc put(stream: OutputStreamVar, value: SomeLengthDelimited) {.inline.} =
|
proc put(stream: OutputStreamVar, value: SomeLengthDelimited) {.inline.} =
|
||||||
for b in value:
|
for b in value:
|
||||||
|
|
@ -103,13 +119,6 @@ proc encodeField(stream: OutputStreamVar, fieldNum: int, value: SomeLengthDelimi
|
||||||
stream.put(len(value).uint)
|
stream.put(len(value).uint)
|
||||||
stream.put(value)
|
stream.put(value)
|
||||||
|
|
||||||
proc encodeField*(protobuf: var ProtoBuffer, value: SomeLengthDelimited) {.inline.} =
|
|
||||||
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 put(stream: OutputStreamVar, value: object) {.inline.}
|
||||||
|
|
||||||
proc encodeField(stream: OutputStreamVar, fieldNum: int, value: object) {.inline.} =
|
proc encodeField(stream: OutputStreamVar, fieldNum: int, value: object) {.inline.} =
|
||||||
|
|
@ -125,21 +134,6 @@ proc encodeField(stream: OutputStreamVar, fieldNum: int, value: object) {.inline
|
||||||
stream.put(len(objOutput).uint)
|
stream.put(len(objOutput).uint)
|
||||||
stream.put(objOutput)
|
stream.put(objOutput)
|
||||||
|
|
||||||
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 _, 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.} =
|
proc put(stream: OutputStreamVar, value: object) {.inline.} =
|
||||||
var fieldNum = 1
|
var fieldNum = 1
|
||||||
for _, val in value.fieldPairs:
|
for _, val in value.fieldPairs:
|
||||||
|
|
@ -148,6 +142,37 @@ proc put(stream: OutputStreamVar, value: object) {.inline.} =
|
||||||
stream.encodeField(fieldNum, val)
|
stream.encodeField(fieldNum, val)
|
||||||
inc fieldNum
|
inc fieldNum
|
||||||
|
|
||||||
|
proc encode*(protobuf: var ProtoBuffer, value: object) {.inline.} =
|
||||||
|
protobuf.outstream.put(value)
|
||||||
|
|
||||||
|
proc encodeField*(protobuf: var ProtoBuffer, value: AnyProtoType) {.inline.} =
|
||||||
|
protobuf.outstream.encodeField(protobuf.fieldNum, value)
|
||||||
|
inc protobuf.fieldNum
|
||||||
|
|
||||||
|
proc encodeField*(protobuf: var ProtoBuffer, fieldNum: int, value: AnyProtoType) {.inline.} =
|
||||||
|
protobuf.outstream.encodeField(fieldNum, value)
|
||||||
|
|
||||||
|
proc getFixed*[T: SomeFixed](
|
||||||
|
bytes: var seq[byte],
|
||||||
|
ty: typedesc[T],
|
||||||
|
outOffset: var int,
|
||||||
|
outBytesProcessed: var int,
|
||||||
|
numBytesToRead = none(int)
|
||||||
|
): T {.inline.} =
|
||||||
|
var bytesRead = 0
|
||||||
|
when T is SomeFixed64:
|
||||||
|
var value: int64
|
||||||
|
else:
|
||||||
|
var value: int32
|
||||||
|
var shiftAmount = 0
|
||||||
|
|
||||||
|
for _ in 0 ..< sizeof(T):
|
||||||
|
value += type(value)(bytes[outOffset]) shl shiftAmount
|
||||||
|
shiftAmount += 8
|
||||||
|
increaseBytesRead()
|
||||||
|
|
||||||
|
result = cast[T](value)
|
||||||
|
|
||||||
proc getVarint[T: SomeVarint](
|
proc getVarint[T: SomeVarint](
|
||||||
bytes: var seq[byte],
|
bytes: var seq[byte],
|
||||||
ty: typedesc[T],
|
ty: typedesc[T],
|
||||||
|
|
@ -202,6 +227,23 @@ proc decodeField*[T: SomeVarint](
|
||||||
|
|
||||||
result.value = getVarint(bytes, ty, outOffset, outBytesProcessed, numBytesToRead)
|
result.value = getVarint(bytes, ty, outOffset, outBytesProcessed, numBytesToRead)
|
||||||
|
|
||||||
|
proc decodeField*[T: SomeFixed](
|
||||||
|
bytes: var seq[byte],
|
||||||
|
ty: typedesc[T],
|
||||||
|
outOffset: var int,
|
||||||
|
outBytesProcessed: var int,
|
||||||
|
numBytesToRead = none(int)
|
||||||
|
): ProtoField[T] {.inline.} =
|
||||||
|
var bytesRead = 0
|
||||||
|
|
||||||
|
let wireTy = wireType(bytes[outOffset])
|
||||||
|
if wireTy notin {Fixed32, Fixed64}:
|
||||||
|
raise newException(Exception, fmt"Not a fixed32 or fixed64 at offset {outOffset}! Received a {wireTy}")
|
||||||
|
|
||||||
|
result.index = fieldNumber(bytes[outOffset])
|
||||||
|
increaseBytesRead()
|
||||||
|
|
||||||
|
result.value = getFixed(bytes, ty, outOffset, outBytesProcessed, numBytesToRead)
|
||||||
|
|
||||||
proc getLengthDelimited*[T: SomeLengthDelimited](
|
proc getLengthDelimited*[T: SomeLengthDelimited](
|
||||||
bytes: var seq[byte],
|
bytes: var seq[byte],
|
||||||
|
|
@ -243,15 +285,6 @@ proc decodeField*[T: SomeLengthDelimited](
|
||||||
|
|
||||||
result.value = getLengthDelimited(bytes, ty, outOffset, outBytesProcessed, numBytesToRead)
|
result.value = getLengthDelimited(bytes, ty, outOffset, outBytesProcessed, numBytesToRead)
|
||||||
|
|
||||||
type
|
|
||||||
Test1 = object
|
|
||||||
a: uint
|
|
||||||
|
|
||||||
Test3 = object
|
|
||||||
g {.sfixed32.}: int
|
|
||||||
h: int
|
|
||||||
i: Test1
|
|
||||||
|
|
||||||
macro getField(obj: typed, fieldNum: int, ty: typedesc): untyped =
|
macro getField(obj: typed, fieldNum: int, ty: typedesc): untyped =
|
||||||
template fieldTypeCheck(obj, field, fieldNum, ty) =
|
template fieldTypeCheck(obj, field, fieldNum, ty) =
|
||||||
when type(obj.field) is type(ty):
|
when type(obj.field) is type(ty):
|
||||||
|
|
@ -260,7 +293,6 @@ macro getField(obj: typed, fieldNum: int, ty: typedesc): untyped =
|
||||||
let fnum {.inject.} = fieldNum
|
let fnum {.inject.} = fieldNum
|
||||||
raise newException(Exception, fmt"Could not find field at position {fnum}.")
|
raise newException(Exception, fmt"Could not find field at position {fnum}.")
|
||||||
|
|
||||||
let typeImpl = obj.getTypeInst.getImpl
|
|
||||||
let typeFields = obj.getTypeInst.getType
|
let typeFields = obj.getTypeInst.getType
|
||||||
|
|
||||||
let objFields = typeFields[2]
|
let objFields = typeFields[2]
|
||||||
|
|
@ -287,7 +319,6 @@ macro getField(obj: typed, fieldNum: int, ty: typedesc): untyped =
|
||||||
result.add(caseStmt)
|
result.add(caseStmt)
|
||||||
|
|
||||||
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 typeImpl = obj.getTypeInst.getImpl
|
|
||||||
let typeFields = obj.getTypeInst.getType
|
let typeFields = obj.getTypeInst.getType
|
||||||
|
|
||||||
let objFields = typeFields[2]
|
let objFields = typeFields[2]
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,36 @@ suite "Test Varint Encoding":
|
||||||
assert decoded.value == num
|
assert decoded.value == num
|
||||||
assert decoded.index == 1
|
assert decoded.index == 1
|
||||||
|
|
||||||
|
test "Can encode/decode float32 number field":
|
||||||
|
var proto = newProtoBuffer()
|
||||||
|
let num = float32(1234.164423)
|
||||||
|
var bytesProcessed: int
|
||||||
|
|
||||||
|
proto.encodeField(num)
|
||||||
|
|
||||||
|
var output = proto.output
|
||||||
|
assert output == @[13.byte, 67, 69, 154, 68]
|
||||||
|
|
||||||
|
var offset = 0
|
||||||
|
let decoded = decodeField(output, float32, offset, bytesProcessed)
|
||||||
|
assert decoded.value == num
|
||||||
|
assert decoded.index == 1
|
||||||
|
|
||||||
|
test "Can encode/decode float64 number field":
|
||||||
|
var proto = newProtoBuffer()
|
||||||
|
let num = 12343121537452.1644232341'f64
|
||||||
|
var bytesProcessed: int
|
||||||
|
|
||||||
|
proto.encodeField(num)
|
||||||
|
|
||||||
|
var output = proto.output
|
||||||
|
assert output == @[9.byte, 84, 88, 211, 191, 182, 115, 166, 66]
|
||||||
|
|
||||||
|
var offset = 0
|
||||||
|
let decoded = decodeField(output, float64, offset, bytesProcessed)
|
||||||
|
assert decoded.value == num
|
||||||
|
assert decoded.index == 1
|
||||||
|
|
||||||
test "Can encode/decode bool field":
|
test "Can encode/decode bool field":
|
||||||
var proto = newProtoBuffer()
|
var proto = newProtoBuffer()
|
||||||
let boolean = true
|
let boolean = true
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue