size computations (#40)
* size computations * add `Protobuf.computeSize` to compute the encoded size of an object * readd `VarIntLengthPrefix` support * don't expose loosely typed `writeValue` for objects that might conflict with other serializers * ensure all `writeValue` and `writeField` are tagged with a `codec` type * avoid writing all-defaults proto3 object fields * Fix sizer for reference * Create TableObject in a template --------- Co-authored-by: Ludovic Chenut <ludovic@status.im>
This commit is contained in:
parent
43f77303bb
commit
0ef1a14564
|
@ -3,8 +3,8 @@ import sets
|
|||
import serialization
|
||||
export serialization
|
||||
|
||||
import protobuf_serialization/[internal, types, reader, writer]
|
||||
export types, reader, writer
|
||||
import protobuf_serialization/[internal, types, reader, sizer, writer]
|
||||
export types, reader, sizer, writer
|
||||
|
||||
serializationFormat Protobuf
|
||||
|
||||
|
@ -27,3 +27,7 @@ func supports*[T](_: type Protobuf, ty: typedesc[T]): bool =
|
|||
# TODO return false when not supporting, instead of crashing compiler
|
||||
static: supportsCompileTime(T)
|
||||
true
|
||||
|
||||
func computeSize*[T: object](_: type Protobuf, value: T): int =
|
||||
## Return the encoded size of the given value
|
||||
computeObjectSize(value)
|
||||
|
|
|
@ -156,10 +156,26 @@ template toBytes*(x: pfloat): openArray[byte] =
|
|||
template toBytes*(header: FieldHeader): openArray[byte] =
|
||||
toBytes(uint32(header), Leb128).toOpenArray()
|
||||
|
||||
proc vsizeof*(x: SomeVarint): int =
|
||||
func computeSize*(x: SomeVarint): int =
|
||||
## Returns number of bytes required to encode integer ``x`` as varint.
|
||||
Leb128.len(toUleb(x))
|
||||
|
||||
func computeSize*(x: SomeFixed64 | SomeFixed32): int =
|
||||
## Returns number of bytes required to encode integer ``x`` as varint.
|
||||
sizeof(x)
|
||||
|
||||
func computeSize*(x: pstring | pbytes): int =
|
||||
let len = distinctBase(x).len()
|
||||
computeSize(puint64(len)) + len
|
||||
|
||||
func computeSize*(x: FieldHeader): int =
|
||||
## Returns number of bytes required to encode integer ``x`` as varint.
|
||||
computeSize(puint32(x))
|
||||
|
||||
func computeSize*(field: int, x: SomeScalar): int =
|
||||
computeSize(FieldHeader.init(field, wireKind(typeof(x)))) +
|
||||
computeSize(x)
|
||||
|
||||
proc writeValue*(output: OutputStream, value: SomeVarint) =
|
||||
output.write(toBytes(value))
|
||||
|
||||
|
@ -177,8 +193,11 @@ proc writeValue*(output: OutputStream, value: pbytes) =
|
|||
proc writeValue*(output: OutputStream, value: SomeFixed32) =
|
||||
output.write(toBytes(value))
|
||||
|
||||
proc writeValue*(output: OutputStream, value: FieldHeader) =
|
||||
output.write(toBytes(value))
|
||||
|
||||
proc writeField*(output: OutputStream, field: int, value: SomeScalar) =
|
||||
output.write(toBytes(FieldHeader.init(field, wireKind(typeof(value)))))
|
||||
output.writeValue(FieldHeader.init(field, wireKind(typeof(value))))
|
||||
output.writeValue(value)
|
||||
|
||||
proc readValue*[T: SomeVarint](input: InputStream, _: type T): T =
|
||||
|
|
|
@ -54,6 +54,28 @@ proc fieldNumberOf*(T: type, fieldName: static string): int {.compileTime.} =
|
|||
else:
|
||||
fieldNum
|
||||
|
||||
template tableObject*(TableObject, K, V) =
|
||||
when K is SomePBInt and V is SomePBInt:
|
||||
type
|
||||
TableObject {.proto3.} = object
|
||||
key {.fieldNumber: 1, pint.}: K
|
||||
value {.fieldNumber: 2, pint.}: V
|
||||
elif K is SomePBInt:
|
||||
type
|
||||
TableObject {.proto3.} = object
|
||||
key {.fieldNumber: 1, pint.}: K
|
||||
value {.fieldNumber: 2.}: V
|
||||
elif V is SomePBInt:
|
||||
type
|
||||
TableObject {.proto3.} = object
|
||||
key {.fieldNumber: 1.}: K
|
||||
value {.fieldNumber: 2, pint.}: V
|
||||
else:
|
||||
type
|
||||
TableObject {.proto3.} = object
|
||||
key {.fieldNumber: 1.}: K
|
||||
value {.fieldNumber: 2.}: V
|
||||
|
||||
template protoType*(InnerType, RootType, FieldType: untyped, fieldName: untyped) =
|
||||
mixin flatType
|
||||
|
||||
|
@ -117,8 +139,10 @@ template protoType*(InnerType, RootType, FieldType: untyped, fieldName: untyped)
|
|||
type InnerType = pbytes
|
||||
elif FlatType is enum:
|
||||
type InnerType = penum
|
||||
elif FlatType is object or FlatType is ref:
|
||||
type InnerType = FieldType
|
||||
elif FlatType is object:
|
||||
type InnerType = pbytes
|
||||
elif FlatType is ref and defined(ConformanceTest):
|
||||
type InnerType = pbytes
|
||||
else:
|
||||
type InnerType = UnsupportedType[FieldType, RootType, fieldName]
|
||||
|
||||
|
|
|
@ -64,28 +64,7 @@ when defined(ConformanceTest):
|
|||
header: FieldHeader,
|
||||
ProtoType: type
|
||||
) =
|
||||
# I know it's ugly, but I cannot find a clean way to do it
|
||||
# ... And nobody cares about map
|
||||
when K is SomePBInt and V is SomePBInt:
|
||||
type
|
||||
TableObject {.proto3.} = object
|
||||
key {.fieldNumber: 1, pint.}: K
|
||||
value {.fieldNumber: 2, pint.}: V
|
||||
elif K is SomePBInt:
|
||||
type
|
||||
TableObject {.proto3.} = object
|
||||
key {.fieldNumber: 1, pint.}: K
|
||||
value {.fieldNumber: 2.}: V
|
||||
elif V is SomePBInt:
|
||||
type
|
||||
TableObject {.proto3.} = object
|
||||
key {.fieldNumber: 1.}: K
|
||||
value {.fieldNumber: 2, pint.}: V
|
||||
else:
|
||||
type
|
||||
TableObject {.proto3.} = object
|
||||
key {.fieldNumber: 1.}: K
|
||||
value {.fieldNumber: 2.}: V
|
||||
tableObject(TableObject, K, V)
|
||||
var tmp = default(TableObject)
|
||||
stream.readFieldInto(tmp, header, ProtoType)
|
||||
value[tmp.key] = tmp.value
|
||||
|
@ -146,6 +125,7 @@ proc readFieldPackedInto[T](
|
|||
elif ProtoType is SomeFixed32:
|
||||
WireKind.Fixed32
|
||||
else:
|
||||
static: doAssert ProtoType is SomeFixed64
|
||||
WireKind.Fixed64
|
||||
|
||||
inner.readFieldInto(value[^1], FieldHeader.init(header.number, kind), ProtoType)
|
||||
|
@ -184,8 +164,8 @@ proc readValueInternal[T: object](stream: InputStream, value: var T, silent: boo
|
|||
stream.readFieldPackedInto(fieldVar, header, ProtoType)
|
||||
else:
|
||||
stream.readFieldInto(fieldVar, header, ProtoType)
|
||||
elif ProtoType is ref and defined(ConformanceTest):
|
||||
fieldVar = new ProtoType
|
||||
elif typeof(fieldVar) is ref and defined(ConformanceTest):
|
||||
fieldVar = new typeof(fieldVar)
|
||||
stream.readFieldInto(fieldVar[], header, ProtoType)
|
||||
else:
|
||||
stream.readFieldInto(fieldVar, header, ProtoType)
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
import
|
||||
std/[typetraits, tables],
|
||||
stew/shims/macros,
|
||||
serialization,
|
||||
"."/[codec, internal, types]
|
||||
|
||||
func computeObjectSize*[T: object](value: T): int
|
||||
|
||||
func computeFieldSize(
|
||||
fieldNum: int, fieldVal: auto, ProtoType: type UnsupportedType,
|
||||
_: static bool) =
|
||||
# TODO turn this into an extension point
|
||||
unsupportedProtoType ProtoType.FieldType, ProtoType.RootType, ProtoType.fieldName
|
||||
|
||||
func computeFieldSize[T: object and not PBOption](
|
||||
fieldNum: int, fieldVal: T, ProtoType: type pbytes,
|
||||
skipDefault: static bool): int =
|
||||
let
|
||||
size = computeObjectSize(fieldVal)
|
||||
|
||||
when skipDefault:
|
||||
if size == 0:
|
||||
return 0
|
||||
|
||||
computeSize(FieldHeader.init(fieldNum, ProtoType.wireKind())) +
|
||||
computeSize(puint64(size)) +
|
||||
size
|
||||
|
||||
proc computeFieldSize*[T: not object](
|
||||
fieldNum: int, fieldVal: T,
|
||||
ProtoType: type SomeScalar, skipDefault: static bool): int =
|
||||
when skipDefault:
|
||||
const def = default(typeof(fieldVal))
|
||||
if fieldVal == def:
|
||||
return
|
||||
|
||||
computeSize(fieldNum, ProtoType(fieldVal))
|
||||
|
||||
proc computeFieldSize*(
|
||||
fieldNum: int, fieldVal: PBOption, ProtoType: type,
|
||||
skipDefault: static bool): int =
|
||||
if fieldVal.isSome(): # TODO required field checking
|
||||
computeFieldSize(fieldNum, fieldVal.get(), ProtoType, skipDefault)
|
||||
else:
|
||||
0
|
||||
|
||||
when defined(ConformanceTest):
|
||||
proc computeFieldSize*[T](
|
||||
fieldNum: int, fieldVal: ref T,
|
||||
ProtoType: type pbytes, skipDefault: static bool): int =
|
||||
if not fieldVal.isNil():
|
||||
computeFieldSize(fieldNum, fieldVal[], ProtoType, skipDefault)
|
||||
else:
|
||||
0
|
||||
|
||||
proc writeField[T: enum](
|
||||
stream: OutputStream, fieldNum: int, fieldVal: T, ProtoType: type) =
|
||||
when 0 notin T:
|
||||
{.fatal: $T & " definition must contain a constant that maps to zero".}
|
||||
stream.writeField(fieldNum, pint32(fieldVal.ord()))
|
||||
|
||||
proc computeFieldSize*[K, V](
|
||||
fieldNum: int, fieldVal: Table[K, V], ProtoType: type pbytes,
|
||||
skipDefault: static bool): int =
|
||||
tableObject(TableObject, K, V)
|
||||
for k, v in fieldVal.pairs():
|
||||
let tmp = TableObject(key: k, value: v)
|
||||
result += computeFieldSize(fieldNum, tmp, ProtoType, false)
|
||||
|
||||
proc computeSizePacked*[T: not byte, ProtoType: SomePrimitive](
|
||||
values: openArray[T], _: type ProtoType): int =
|
||||
const canCopyMem =
|
||||
ProtoType is SomeFixed32 or ProtoType is SomeFixed64 or ProtoType is pbool
|
||||
when canCopyMem:
|
||||
values.len() * sizeof(T)
|
||||
else:
|
||||
var total = 0
|
||||
for item in values:
|
||||
total += computeSize(ProtoType(item))
|
||||
total
|
||||
|
||||
proc computeFieldSizePacked*[ProtoType: SomePrimitive](
|
||||
field: int, values: openArray, _: type ProtoType): int =
|
||||
# Packed encoding uses a length-delimited field byte length of the sum of the
|
||||
# byte lengths of each field followed by the header-free contents
|
||||
let
|
||||
dataSize = computeSizePacked(values, ProtoType)
|
||||
|
||||
computeSize(FieldHeader.init(field, WireKind.LengthDelim)) +
|
||||
computeSize(puint64(dataSize)) +
|
||||
dataSize
|
||||
|
||||
func computeObjectSize*[T: object](value: T): int =
|
||||
const
|
||||
isProto2: bool = T.isProto2()
|
||||
isProto3: bool = T.isProto3()
|
||||
static:
|
||||
doAssert isProto2 xor isProto3
|
||||
|
||||
var total = 0
|
||||
enumInstanceSerializedFields(value, fieldName, fieldVal):
|
||||
const
|
||||
fieldNum = T.fieldNumberOf(fieldName)
|
||||
|
||||
type
|
||||
FlatType = flatType(fieldVal)
|
||||
|
||||
protoType(ProtoType, T, FlatType, fieldName)
|
||||
|
||||
let fieldSize = when FlatType is seq and FlatType isnot seq[byte]:
|
||||
const
|
||||
isPacked = T.isPacked(fieldName).get(isProto3)
|
||||
when isPacked and ProtoType is SomePrimitive:
|
||||
computeFieldSizePacked(fieldNum, fieldVal, ProtoType)
|
||||
else:
|
||||
var dataSize = 0
|
||||
for i in 0..<fieldVal.len:
|
||||
# don't skip defaults so as to preserve length
|
||||
dataSize += computeFieldSize(fieldNum, fieldVal[i], ProtoType, false)
|
||||
dataSize
|
||||
|
||||
else:
|
||||
computeFieldSize(fieldNum, fieldVal, ProtoType, isProto3)
|
||||
|
||||
total += fieldSize
|
||||
|
||||
total
|
|
@ -13,8 +13,8 @@ type
|
|||
ProtobufEOFError* = object of ProtobufReadError
|
||||
ProtobufMessageError* = object of ProtobufReadError
|
||||
|
||||
ProtobufFlags* = uint8 # enum
|
||||
# VarIntLengthPrefix, # TODO needs fixing
|
||||
ProtobufFlags* = enum
|
||||
VarIntLengthPrefix
|
||||
|
||||
ProtobufWriter* = object
|
||||
stream*: OutputStream
|
||||
|
|
|
@ -6,42 +6,50 @@ import
|
|||
stew/objects,
|
||||
faststreams/outputs,
|
||||
serialization,
|
||||
"."/[codec, internal, types]
|
||||
"."/[codec, internal, sizer, types]
|
||||
|
||||
export outputs, serialization, codec, types
|
||||
|
||||
proc writeValue*[T: object](stream: OutputStream, value: T)
|
||||
proc writeObject[T: object](stream: OutputStream, value: T)
|
||||
|
||||
proc writeField(
|
||||
stream: OutputStream, fieldNum: int, fieldVal: auto, ProtoType: type UnsupportedType) =
|
||||
proc writeField*(
|
||||
stream: OutputStream, fieldNum: int, fieldVal: auto,
|
||||
ProtoType: type UnsupportedType, _: static bool = false) =
|
||||
# TODO turn this into an extension point
|
||||
unsupportedProtoType ProtoType.FieldType, ProtoType.RootType, ProtoType.fieldName
|
||||
|
||||
proc writeField*[T: object](stream: OutputStream, fieldNum: int, fieldVal: T) =
|
||||
# TODO Pre-compute size of inner object then write it without the intermediate
|
||||
# memory output
|
||||
var inner = memoryOutput()
|
||||
inner.writeValue(fieldVal)
|
||||
let bytes = inner.getOutput()
|
||||
stream.writeField(fieldNum, pbytes(bytes))
|
||||
proc writeField*[T: object and not PBOption and not Table](
|
||||
stream: OutputStream, fieldNum: int, fieldVal: T, ProtoType: type pbytes,
|
||||
skipDefault: static bool = false) =
|
||||
let
|
||||
size = computeObjectSize(fieldVal)
|
||||
|
||||
proc writeField[T: object and not PBOption](
|
||||
stream: OutputStream, fieldNum: int, fieldVal: T, ProtoType: type) =
|
||||
stream.writeField(fieldNum, fieldVal)
|
||||
when skipDefault:
|
||||
if size == 0:
|
||||
return
|
||||
|
||||
stream.writeValue(FieldHeader.init(fieldNum, ProtoType.wireKind()))
|
||||
stream.writeValue(puint64(size))
|
||||
stream.writeObject(fieldVal)
|
||||
|
||||
proc writeField*[T: not object and not enum](
|
||||
stream: OutputStream, fieldNum: int, fieldVal: T,
|
||||
ProtoType: type SomeScalar, skipDefault: static bool = false) =
|
||||
when skipDefault:
|
||||
const def = default(typeof(fieldVal))
|
||||
if fieldVal == def:
|
||||
return
|
||||
|
||||
proc writeField[T: not object and not enum](
|
||||
stream: OutputStream, fieldNum: int, fieldVal: T, ProtoType: type) =
|
||||
stream.writeField(fieldNum, ProtoType(fieldVal))
|
||||
|
||||
proc writeField(
|
||||
stream: OutputStream, fieldNum: int, fieldVal: PBOption, ProtoType: type) =
|
||||
if fieldVal.isSome(): # TODO required field checking
|
||||
stream.writeField(fieldNum, fieldVal.get(), ProtoType)
|
||||
proc writeField*(
|
||||
stream: OutputStream, fieldNum: int, fieldVal: PBOption, ProtoType: type,
|
||||
skipDefault: static bool = false) =
|
||||
if fieldVal.isSome():
|
||||
stream.writeField(fieldNum, fieldVal.get(), ProtoType, skipDefault)
|
||||
|
||||
proc writeFieldPacked*[T: not byte, ProtoType: SomePrimitive](
|
||||
output: OutputStream, field: int, values: openArray[T], _: type ProtoType) =
|
||||
doAssert validFieldNumber(field)
|
||||
|
||||
# Packed encoding uses a length-delimited field byte length of the sum of the
|
||||
# byte lengths of each field followed by the header-free contents
|
||||
output.write(
|
||||
|
@ -49,63 +57,44 @@ proc writeFieldPacked*[T: not byte, ProtoType: SomePrimitive](
|
|||
|
||||
const canCopyMem =
|
||||
ProtoType is SomeFixed32 or ProtoType is SomeFixed64 or ProtoType is pbool
|
||||
let dlength =
|
||||
when canCopyMem:
|
||||
values.len() * sizeof(T)
|
||||
else:
|
||||
var total = 0
|
||||
for item in values:
|
||||
total += vsizeof(ProtoType(item))
|
||||
total
|
||||
output.write(toBytes(puint64(dlength)))
|
||||
let
|
||||
dataSize = computeSizePacked(values, ProtoType)
|
||||
output.write(toBytes(puint64(dataSize)))
|
||||
|
||||
when canCopyMem:
|
||||
if values.len > 0:
|
||||
output.write(
|
||||
cast[ptr UncheckedArray[byte]](
|
||||
unsafeAddr values[0]).toOpenArray(0, dlength - 1))
|
||||
unsafeAddr values[0]).toOpenArray(0, dataSize - 1))
|
||||
else:
|
||||
for value in values:
|
||||
output.write(toBytes(ProtoType(value)))
|
||||
|
||||
when defined(ConformanceTest):
|
||||
proc writeField[T: enum](
|
||||
stream: OutputStream, fieldNum: int, fieldVal: T, ProtoType: type) =
|
||||
stream: OutputStream,
|
||||
fieldNum: int,
|
||||
fieldVal: T,
|
||||
ProtoType: type,
|
||||
skipDefault: static bool = false
|
||||
) =
|
||||
when 0 notin T:
|
||||
{.fatal: $T & " definition must contain a constant that maps to zero".}
|
||||
stream.writeField(fieldNum, pint32(fieldVal.ord()))
|
||||
|
||||
proc writeField*[K, V](
|
||||
proc writeField[K, V](
|
||||
stream: OutputStream,
|
||||
fieldNum: int,
|
||||
value: Table[K, V],
|
||||
ProtoType: type
|
||||
ProtoType: type,
|
||||
skipDefault: static bool = false
|
||||
) =
|
||||
when K is SomePBInt and V is SomePBInt:
|
||||
type
|
||||
TableObject {.proto3.} = object
|
||||
key {.fieldNumber: 1, pint.}: K
|
||||
value {.fieldNumber: 2, pint.}: V
|
||||
elif K is SomePBInt:
|
||||
type
|
||||
TableObject {.proto3.} = object
|
||||
key {.fieldNumber: 1, pint.}: K
|
||||
value {.fieldNumber: 2.}: V
|
||||
elif V is SomePBInt:
|
||||
type
|
||||
TableObject {.proto3.} = object
|
||||
key {.fieldNumber: 1.}: K
|
||||
value {.fieldNumber: 2, pint.}: V
|
||||
else:
|
||||
type
|
||||
TableObject {.proto3.} = object
|
||||
key {.fieldNumber: 1.}: K
|
||||
value {.fieldNumber: 2.}: V
|
||||
tableObject(TableObject, K, V)
|
||||
for k, v in value.pairs():
|
||||
let tmp = TableObject(key: k, value: v)
|
||||
stream.writeField(fieldNum, tmp, ProtoType)
|
||||
|
||||
proc writeValue*[T: object](stream: OutputStream, value: T) =
|
||||
proc writeObject[T: object](stream: OutputStream, value: T) =
|
||||
const
|
||||
isProto2: bool = T.isProto2()
|
||||
isProto3: bool = T.isProto3()
|
||||
|
@ -127,54 +116,21 @@ proc writeValue*[T: object](stream: OutputStream, value: T) =
|
|||
stream.writeFieldPacked(fieldNum, fieldVal, ProtoType)
|
||||
else:
|
||||
for i in 0..<fieldVal.len:
|
||||
stream.writeField(fieldNum, fieldVal[i], ProtoType)
|
||||
# don't skip defaults so as to preserve length
|
||||
stream.writeField(fieldNum, fieldVal[i], ProtoType, false)
|
||||
|
||||
elif FlatType is object:
|
||||
# TODO avoid writing empty objects in proto3
|
||||
stream.writeField(fieldNum, fieldVal, ProtoType)
|
||||
elif FlatType is ref and defined(ConformanceTest):
|
||||
if not fieldVal.isNil():
|
||||
stream.writeField(fieldNum, fieldVal[], ProtoType)
|
||||
else:
|
||||
when isProto2:
|
||||
stream.writeField(fieldNum, fieldVal, ProtoType)
|
||||
else:
|
||||
if fieldVal != static(default(typeof(fieldVal))): # TODO make this an extension point?
|
||||
stream.writeField(fieldNum, fieldVal, ProtoType)
|
||||
stream.writeField(fieldNum, fieldVal, ProtoType, isProto3)
|
||||
|
||||
proc writeValue*[T: object](writer: ProtobufWriter, value: T) =
|
||||
static: verifySerializable(T)
|
||||
|
||||
# TODO cursors broken
|
||||
# var
|
||||
# cursor: VarSizeWriteCursor
|
||||
# startPos: int
|
||||
if ProtobufFlags.VarIntLengthPrefix in writer.flags:
|
||||
let
|
||||
size = computeObjectSize(value)
|
||||
writer.stream.writeValue(puint64(size))
|
||||
|
||||
# if writer.flags.contains(VarIntLengthPrefix):
|
||||
# cursor = writer.stream.delayVarSizeWrite(10)
|
||||
# startPos = writer.stream.pos
|
||||
|
||||
writer.stream.writeValue(value)
|
||||
|
||||
# if writer.flags.contains(VarIntLengthPrefix):
|
||||
# var len = uint32(writer.stream.pos - startPos)
|
||||
# if len == 0:
|
||||
# cursor.finalWrite([])
|
||||
# elif writer.flags.contains(VarIntLengthPrefix):
|
||||
# var viLen = encodeVarInt(PInt(len))
|
||||
# if viLen.len == 0:
|
||||
# cursor.finalWrite([byte(0)])
|
||||
# else:
|
||||
# cursor.finalWrite(viLen)
|
||||
# elif writer.flags.contains(UIntLELengthPrefix):
|
||||
# var temp: array[sizeof(len), byte]
|
||||
# for i in 0 ..< sizeof(len):
|
||||
# temp[i] = byte(len and LAST_BYTE)
|
||||
# len = len shr 8
|
||||
# cursor.finalWrite(temp)
|
||||
# elif writer.flags.contains(UIntBELengthPrefix):
|
||||
# var temp: array[sizeof(len), byte]
|
||||
# for i in 0 ..< sizeof(len):
|
||||
# temp[i] = byte(len shr ((sizeof(len) - 1) * 8))
|
||||
# len = len shl 8
|
||||
# cursor.finalWrite(temp)
|
||||
writer.stream.writeObject(value)
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
switch("threads", "on")
|
|
@ -942,36 +942,10 @@ Required.Proto3.ProtobufInput.ValidDataMap.UINT64.UINT64.Unordered.ProtobufOutpu
|
|||
Required.Proto3.ProtobufInput.ValidDataMap.UINT64.UINT64.Unordered.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.BOOL.DefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.BOOL.DefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.BOOL.MultipleValuesForDifferentField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.BOOL.MultipleValuesForDifferentField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.BOOL.MultipleValuesForSameField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.BOOL.MultipleValuesForSameField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.BOOL.NonDefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.BOOL.NonDefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.BYTES.DefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.BYTES.DefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.BYTES.MultipleValuesForDifferentField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.BYTES.MultipleValuesForDifferentField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.BYTES.MultipleValuesForSameField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.BYTES.MultipleValuesForSameField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.BYTES.NonDefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.BYTES.NonDefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.DOUBLE.DefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.DOUBLE.DefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.DOUBLE.MultipleValuesForDifferentField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.DOUBLE.MultipleValuesForDifferentField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.DOUBLE.MultipleValuesForSameField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.DOUBLE.MultipleValuesForSameField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.DOUBLE.NonDefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.DOUBLE.NonDefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.ENUM.DefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.ENUM.DefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.ENUM.MultipleValuesForDifferentField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.ENUM.MultipleValuesForDifferentField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.ENUM.MultipleValuesForSameField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.ENUM.MultipleValuesForSameField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.ENUM.NonDefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.ENUM.NonDefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.FLOAT.DefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.FLOAT.DefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.FLOAT.MultipleValuesForDifferentField.ProtobufOutput
|
||||
|
@ -980,40 +954,14 @@ Required.Proto3.ProtobufInput.ValidDataOneof.FLOAT.MultipleValuesForSameField.Pr
|
|||
Required.Proto3.ProtobufInput.ValidDataOneof.FLOAT.MultipleValuesForSameField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.FLOAT.NonDefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.FLOAT.NonDefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.MESSAGE.DefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.MESSAGE.DefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.MESSAGE.Merge.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.MESSAGE.Merge.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.MESSAGE.MultipleValuesForDifferentField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.MESSAGE.MultipleValuesForDifferentField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.MESSAGE.MultipleValuesForSameField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.MESSAGE.MultipleValuesForSameField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.MESSAGE.NonDefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.MESSAGE.NonDefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.STRING.DefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.STRING.DefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.STRING.MultipleValuesForDifferentField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.STRING.MultipleValuesForDifferentField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.STRING.MultipleValuesForSameField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.STRING.MultipleValuesForSameField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.STRING.NonDefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.STRING.NonDefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.UINT32.DefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.UINT32.DefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.UINT32.MultipleValuesForDifferentField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.UINT32.MultipleValuesForDifferentField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.UINT32.MultipleValuesForSameField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.UINT32.MultipleValuesForSameField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.UINT32.NonDefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.UINT32.NonDefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.UINT64.DefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.UINT64.DefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.UINT64.MultipleValuesForDifferentField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.UINT64.MultipleValuesForDifferentField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.UINT64.MultipleValuesForSameField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.UINT64.MultipleValuesForSameField.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.UINT64.NonDefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataOneof.UINT64.NonDefaultValue.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataRepeated.BOOL.PackedInput.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataRepeated.BOOL.PackedInput.ProtobufOutput
|
||||
Required.Proto3.ProtobufInput.ValidDataRepeated.BOOL.UnpackedInput.ProtobufOutput
|
||||
|
|
|
@ -16,7 +16,10 @@ type
|
|||
x {.fieldNumber: 1.}: bool
|
||||
|
||||
proc writeRead[W, R](toWrite: W, value: R) =
|
||||
check Protobuf.decode(Protobuf.encode(toWrite), R) == value
|
||||
let encoded = Protobuf.encode(toWrite)
|
||||
check:
|
||||
encoded.len == Protobuf.computeSize(toWrite)
|
||||
Protobuf.decode(encoded, R) == value
|
||||
|
||||
suite "Test Boolean Encoding/Decoding":
|
||||
test "Can encode/decode boolean without subtype specification":
|
||||
|
|
|
@ -109,6 +109,8 @@ suite "codec test suite":
|
|||
let data = getVarintEncodedValue(VarintValues[i])
|
||||
check:
|
||||
toHex(data) == VarintVectors[i]
|
||||
data.len == computeSize(puint64(VarintValues[i]))
|
||||
|
||||
getVarintDecodedValue(data) == VarintValues[i]
|
||||
|
||||
test "[varint] incorrect values test":
|
||||
|
@ -125,6 +127,7 @@ suite "codec test suite":
|
|||
let data = getFixed32EncodedValue(cast[float32](Fixed32Values[i]))
|
||||
check:
|
||||
toHex(data) == Fixed32Vectors[i]
|
||||
data.len == computeSize(fixed32(Fixed32Values[i]))
|
||||
getFixed32DecodedValue(data) == Fixed32Values[i]
|
||||
|
||||
test "[fixed32] incorrect values test":
|
||||
|
@ -140,6 +143,7 @@ suite "codec test suite":
|
|||
let data = getFixed64EncodedValue(cast[float64](Fixed64Values[i]))
|
||||
check:
|
||||
toHex(data) == Fixed64Vectors[i]
|
||||
data.len == computeSize(fixed64(Fixed64Values[i]))
|
||||
getFixed64DecodedValue(data) == Fixed64Values[i]
|
||||
|
||||
test "[fixed64] incorrect values test":
|
||||
|
@ -153,10 +157,12 @@ suite "codec test suite":
|
|||
test "[length] edge values test":
|
||||
for i in 0 ..< len(LengthValues):
|
||||
let data1 = getLengthEncodedValue(LengthValues[i])
|
||||
let data2 = getLengthEncodedValue(cast[seq[byte]](LengthValues[i]))
|
||||
let data2 = getLengthEncodedValue(toBytes(LengthValues[i]))
|
||||
check:
|
||||
toHex(data1) == LengthVectors[i]
|
||||
computeSize(pstring(LengthValues[i])) == data1.len
|
||||
toHex(data2) == LengthVectors[i]
|
||||
computeSize(pbytes(toBytes(LengthValues[i]))) == data2.len
|
||||
check:
|
||||
getLengthDecodedValue(data1) == LengthValues[i]
|
||||
getLengthDecodedValue(data2) == LengthValues[i]
|
||||
|
|
|
@ -56,7 +56,7 @@ suite "Test Object Encoding/Decoding":
|
|||
writer = memoryOutput()
|
||||
|
||||
writer.writeField(1, sint32(obj.d))
|
||||
writer.writeField(3, obj.f)
|
||||
writer.writeField(3, obj.f, pbytes)
|
||||
writer.writeField(4, pstring(obj.g))
|
||||
|
||||
let result = Protobuf.decode(writer.getOutput(), type(Wrapped))
|
||||
|
@ -77,7 +77,7 @@ suite "Test Object Encoding/Decoding":
|
|||
)
|
||||
writer = memoryOutput()
|
||||
|
||||
writer.writeField(3, obj.f)
|
||||
writer.writeField(3, obj.f, pbytes)
|
||||
#writer.writeField(6, penum(obj.i))
|
||||
writer.writeField(1, sint64(obj.d))
|
||||
writer.writeField(2, sint64(obj.e))
|
||||
|
|
|
@ -34,6 +34,7 @@ z: ["zero", "one", "two"]
|
|||
"080a080508d80408c7091001100010011001100010001000100110001a047a65726f1a036f6e651a0374776f")
|
||||
|
||||
check:
|
||||
Protobuf.computeSize(v) == encoded.len
|
||||
Protobuf.encode(v) == encoded
|
||||
Protobuf.decode(encoded, typeof(v)) == v
|
||||
|
||||
|
@ -56,5 +57,6 @@ a: [5, -3, 300, -612]
|
|||
"0a060a05d804c70912090100010100000001001a1005000000fdffffff2c0100009cfdffff22100000a040000040c000009643000019c4")
|
||||
|
||||
check:
|
||||
Protobuf.computeSize(v) == encoded.len
|
||||
Protobuf.encode(v) == encoded
|
||||
Protobuf.decode(encoded, typeof(v)) == v
|
||||
|
|
Loading…
Reference in New Issue