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
|
import serialization
|
||||||
export serialization
|
export serialization
|
||||||
|
|
||||||
import protobuf_serialization/[internal, types, reader, writer]
|
import protobuf_serialization/[internal, types, reader, sizer, writer]
|
||||||
export types, reader, writer
|
export types, reader, sizer, writer
|
||||||
|
|
||||||
serializationFormat Protobuf
|
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
|
# TODO return false when not supporting, instead of crashing compiler
|
||||||
static: supportsCompileTime(T)
|
static: supportsCompileTime(T)
|
||||||
true
|
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] =
|
template toBytes*(header: FieldHeader): openArray[byte] =
|
||||||
toBytes(uint32(header), Leb128).toOpenArray()
|
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.
|
## Returns number of bytes required to encode integer ``x`` as varint.
|
||||||
Leb128.len(toUleb(x))
|
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) =
|
proc writeValue*(output: OutputStream, value: SomeVarint) =
|
||||||
output.write(toBytes(value))
|
output.write(toBytes(value))
|
||||||
|
|
||||||
|
@ -177,8 +193,11 @@ proc writeValue*(output: OutputStream, value: pbytes) =
|
||||||
proc writeValue*(output: OutputStream, value: SomeFixed32) =
|
proc writeValue*(output: OutputStream, value: SomeFixed32) =
|
||||||
output.write(toBytes(value))
|
output.write(toBytes(value))
|
||||||
|
|
||||||
|
proc writeValue*(output: OutputStream, value: FieldHeader) =
|
||||||
|
output.write(toBytes(value))
|
||||||
|
|
||||||
proc writeField*(output: OutputStream, field: int, value: SomeScalar) =
|
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)
|
output.writeValue(value)
|
||||||
|
|
||||||
proc readValue*[T: SomeVarint](input: InputStream, _: type T): T =
|
proc readValue*[T: SomeVarint](input: InputStream, _: type T): T =
|
||||||
|
|
|
@ -54,6 +54,28 @@ proc fieldNumberOf*(T: type, fieldName: static string): int {.compileTime.} =
|
||||||
else:
|
else:
|
||||||
fieldNum
|
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) =
|
template protoType*(InnerType, RootType, FieldType: untyped, fieldName: untyped) =
|
||||||
mixin flatType
|
mixin flatType
|
||||||
|
|
||||||
|
@ -117,8 +139,10 @@ template protoType*(InnerType, RootType, FieldType: untyped, fieldName: untyped)
|
||||||
type InnerType = pbytes
|
type InnerType = pbytes
|
||||||
elif FlatType is enum:
|
elif FlatType is enum:
|
||||||
type InnerType = penum
|
type InnerType = penum
|
||||||
elif FlatType is object or FlatType is ref:
|
elif FlatType is object:
|
||||||
type InnerType = FieldType
|
type InnerType = pbytes
|
||||||
|
elif FlatType is ref and defined(ConformanceTest):
|
||||||
|
type InnerType = pbytes
|
||||||
else:
|
else:
|
||||||
type InnerType = UnsupportedType[FieldType, RootType, fieldName]
|
type InnerType = UnsupportedType[FieldType, RootType, fieldName]
|
||||||
|
|
||||||
|
|
|
@ -64,28 +64,7 @@ when defined(ConformanceTest):
|
||||||
header: FieldHeader,
|
header: FieldHeader,
|
||||||
ProtoType: type
|
ProtoType: type
|
||||||
) =
|
) =
|
||||||
# I know it's ugly, but I cannot find a clean way to do it
|
tableObject(TableObject, K, V)
|
||||||
# ... 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
|
|
||||||
var tmp = default(TableObject)
|
var tmp = default(TableObject)
|
||||||
stream.readFieldInto(tmp, header, ProtoType)
|
stream.readFieldInto(tmp, header, ProtoType)
|
||||||
value[tmp.key] = tmp.value
|
value[tmp.key] = tmp.value
|
||||||
|
@ -146,6 +125,7 @@ proc readFieldPackedInto[T](
|
||||||
elif ProtoType is SomeFixed32:
|
elif ProtoType is SomeFixed32:
|
||||||
WireKind.Fixed32
|
WireKind.Fixed32
|
||||||
else:
|
else:
|
||||||
|
static: doAssert ProtoType is SomeFixed64
|
||||||
WireKind.Fixed64
|
WireKind.Fixed64
|
||||||
|
|
||||||
inner.readFieldInto(value[^1], FieldHeader.init(header.number, kind), ProtoType)
|
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)
|
stream.readFieldPackedInto(fieldVar, header, ProtoType)
|
||||||
else:
|
else:
|
||||||
stream.readFieldInto(fieldVar, header, ProtoType)
|
stream.readFieldInto(fieldVar, header, ProtoType)
|
||||||
elif ProtoType is ref and defined(ConformanceTest):
|
elif typeof(fieldVar) is ref and defined(ConformanceTest):
|
||||||
fieldVar = new ProtoType
|
fieldVar = new typeof(fieldVar)
|
||||||
stream.readFieldInto(fieldVar[], header, ProtoType)
|
stream.readFieldInto(fieldVar[], header, ProtoType)
|
||||||
else:
|
else:
|
||||||
stream.readFieldInto(fieldVar, header, ProtoType)
|
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
|
ProtobufEOFError* = object of ProtobufReadError
|
||||||
ProtobufMessageError* = object of ProtobufReadError
|
ProtobufMessageError* = object of ProtobufReadError
|
||||||
|
|
||||||
ProtobufFlags* = uint8 # enum
|
ProtobufFlags* = enum
|
||||||
# VarIntLengthPrefix, # TODO needs fixing
|
VarIntLengthPrefix
|
||||||
|
|
||||||
ProtobufWriter* = object
|
ProtobufWriter* = object
|
||||||
stream*: OutputStream
|
stream*: OutputStream
|
||||||
|
|
|
@ -6,42 +6,50 @@ import
|
||||||
stew/objects,
|
stew/objects,
|
||||||
faststreams/outputs,
|
faststreams/outputs,
|
||||||
serialization,
|
serialization,
|
||||||
"."/[codec, internal, types]
|
"."/[codec, internal, sizer, types]
|
||||||
|
|
||||||
export outputs, serialization, codec, types
|
export outputs, serialization, codec, types
|
||||||
|
|
||||||
proc writeValue*[T: object](stream: OutputStream, value: T)
|
proc writeObject[T: object](stream: OutputStream, value: T)
|
||||||
|
|
||||||
proc writeField(
|
proc writeField*(
|
||||||
stream: OutputStream, fieldNum: int, fieldVal: auto, ProtoType: type UnsupportedType) =
|
stream: OutputStream, fieldNum: int, fieldVal: auto,
|
||||||
|
ProtoType: type UnsupportedType, _: static bool = false) =
|
||||||
# TODO turn this into an extension point
|
# TODO turn this into an extension point
|
||||||
unsupportedProtoType ProtoType.FieldType, ProtoType.RootType, ProtoType.fieldName
|
unsupportedProtoType ProtoType.FieldType, ProtoType.RootType, ProtoType.fieldName
|
||||||
|
|
||||||
proc writeField*[T: object](stream: OutputStream, fieldNum: int, fieldVal: T) =
|
proc writeField*[T: object and not PBOption and not Table](
|
||||||
# TODO Pre-compute size of inner object then write it without the intermediate
|
stream: OutputStream, fieldNum: int, fieldVal: T, ProtoType: type pbytes,
|
||||||
# memory output
|
skipDefault: static bool = false) =
|
||||||
var inner = memoryOutput()
|
let
|
||||||
inner.writeValue(fieldVal)
|
size = computeObjectSize(fieldVal)
|
||||||
let bytes = inner.getOutput()
|
|
||||||
stream.writeField(fieldNum, pbytes(bytes))
|
|
||||||
|
|
||||||
proc writeField[T: object and not PBOption](
|
when skipDefault:
|
||||||
stream: OutputStream, fieldNum: int, fieldVal: T, ProtoType: type) =
|
if size == 0:
|
||||||
stream.writeField(fieldNum, fieldVal)
|
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))
|
stream.writeField(fieldNum, ProtoType(fieldVal))
|
||||||
|
|
||||||
proc writeField(
|
proc writeField*(
|
||||||
stream: OutputStream, fieldNum: int, fieldVal: PBOption, ProtoType: type) =
|
stream: OutputStream, fieldNum: int, fieldVal: PBOption, ProtoType: type,
|
||||||
if fieldVal.isSome(): # TODO required field checking
|
skipDefault: static bool = false) =
|
||||||
stream.writeField(fieldNum, fieldVal.get(), ProtoType)
|
if fieldVal.isSome():
|
||||||
|
stream.writeField(fieldNum, fieldVal.get(), ProtoType, skipDefault)
|
||||||
|
|
||||||
proc writeFieldPacked*[T: not byte, ProtoType: SomePrimitive](
|
proc writeFieldPacked*[T: not byte, ProtoType: SomePrimitive](
|
||||||
output: OutputStream, field: int, values: openArray[T], _: type ProtoType) =
|
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
|
# 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
|
# byte lengths of each field followed by the header-free contents
|
||||||
output.write(
|
output.write(
|
||||||
|
@ -49,63 +57,44 @@ proc writeFieldPacked*[T: not byte, ProtoType: SomePrimitive](
|
||||||
|
|
||||||
const canCopyMem =
|
const canCopyMem =
|
||||||
ProtoType is SomeFixed32 or ProtoType is SomeFixed64 or ProtoType is pbool
|
ProtoType is SomeFixed32 or ProtoType is SomeFixed64 or ProtoType is pbool
|
||||||
let dlength =
|
let
|
||||||
when canCopyMem:
|
dataSize = computeSizePacked(values, ProtoType)
|
||||||
values.len() * sizeof(T)
|
output.write(toBytes(puint64(dataSize)))
|
||||||
else:
|
|
||||||
var total = 0
|
|
||||||
for item in values:
|
|
||||||
total += vsizeof(ProtoType(item))
|
|
||||||
total
|
|
||||||
output.write(toBytes(puint64(dlength)))
|
|
||||||
|
|
||||||
when canCopyMem:
|
when canCopyMem:
|
||||||
if values.len > 0:
|
if values.len > 0:
|
||||||
output.write(
|
output.write(
|
||||||
cast[ptr UncheckedArray[byte]](
|
cast[ptr UncheckedArray[byte]](
|
||||||
unsafeAddr values[0]).toOpenArray(0, dlength - 1))
|
unsafeAddr values[0]).toOpenArray(0, dataSize - 1))
|
||||||
else:
|
else:
|
||||||
for value in values:
|
for value in values:
|
||||||
output.write(toBytes(ProtoType(value)))
|
output.write(toBytes(ProtoType(value)))
|
||||||
|
|
||||||
when defined(ConformanceTest):
|
when defined(ConformanceTest):
|
||||||
proc writeField[T: enum](
|
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:
|
when 0 notin T:
|
||||||
{.fatal: $T & " definition must contain a constant that maps to zero".}
|
{.fatal: $T & " definition must contain a constant that maps to zero".}
|
||||||
stream.writeField(fieldNum, pint32(fieldVal.ord()))
|
stream.writeField(fieldNum, pint32(fieldVal.ord()))
|
||||||
|
|
||||||
proc writeField*[K, V](
|
proc writeField[K, V](
|
||||||
stream: OutputStream,
|
stream: OutputStream,
|
||||||
fieldNum: int,
|
fieldNum: int,
|
||||||
value: Table[K, V],
|
value: Table[K, V],
|
||||||
ProtoType: type
|
ProtoType: type,
|
||||||
|
skipDefault: static bool = false
|
||||||
) =
|
) =
|
||||||
when K is SomePBInt and V is SomePBInt:
|
tableObject(TableObject, K, V)
|
||||||
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
|
|
||||||
for k, v in value.pairs():
|
for k, v in value.pairs():
|
||||||
let tmp = TableObject(key: k, value: v)
|
let tmp = TableObject(key: k, value: v)
|
||||||
stream.writeField(fieldNum, tmp, ProtoType)
|
stream.writeField(fieldNum, tmp, ProtoType)
|
||||||
|
|
||||||
proc writeValue*[T: object](stream: OutputStream, value: T) =
|
proc writeObject[T: object](stream: OutputStream, value: T) =
|
||||||
const
|
const
|
||||||
isProto2: bool = T.isProto2()
|
isProto2: bool = T.isProto2()
|
||||||
isProto3: bool = T.isProto3()
|
isProto3: bool = T.isProto3()
|
||||||
|
@ -127,54 +116,21 @@ proc writeValue*[T: object](stream: OutputStream, value: T) =
|
||||||
stream.writeFieldPacked(fieldNum, fieldVal, ProtoType)
|
stream.writeFieldPacked(fieldNum, fieldVal, ProtoType)
|
||||||
else:
|
else:
|
||||||
for i in 0..<fieldVal.len:
|
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):
|
elif FlatType is ref and defined(ConformanceTest):
|
||||||
if not fieldVal.isNil():
|
if not fieldVal.isNil():
|
||||||
stream.writeField(fieldNum, fieldVal[], ProtoType)
|
stream.writeField(fieldNum, fieldVal[], ProtoType)
|
||||||
else:
|
else:
|
||||||
when isProto2:
|
stream.writeField(fieldNum, fieldVal, ProtoType, isProto3)
|
||||||
stream.writeField(fieldNum, fieldVal, ProtoType)
|
|
||||||
else:
|
|
||||||
if fieldVal != static(default(typeof(fieldVal))): # TODO make this an extension point?
|
|
||||||
stream.writeField(fieldNum, fieldVal, ProtoType)
|
|
||||||
|
|
||||||
proc writeValue*[T: object](writer: ProtobufWriter, value: T) =
|
proc writeValue*[T: object](writer: ProtobufWriter, value: T) =
|
||||||
static: verifySerializable(T)
|
static: verifySerializable(T)
|
||||||
|
|
||||||
# TODO cursors broken
|
if ProtobufFlags.VarIntLengthPrefix in writer.flags:
|
||||||
# var
|
let
|
||||||
# cursor: VarSizeWriteCursor
|
size = computeObjectSize(value)
|
||||||
# startPos: int
|
writer.stream.writeValue(puint64(size))
|
||||||
|
|
||||||
# if writer.flags.contains(VarIntLengthPrefix):
|
writer.stream.writeObject(value)
|
||||||
# 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)
|
|
||||||
|
|
|
@ -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.ValidDataMap.UINT64.UINT64.Unordered.ProtobufOutput
|
||||||
Required.Proto3.ProtobufInput.ValidDataOneof.BOOL.DefaultValue.ProtobufOutput
|
Required.Proto3.ProtobufInput.ValidDataOneof.BOOL.DefaultValue.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.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.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.DefaultValue.ProtobufOutput
|
Required.Proto3.ProtobufInput.ValidDataOneof.FLOAT.DefaultValue.ProtobufOutput
|
||||||
Required.Proto3.ProtobufInput.ValidDataOneof.FLOAT.MultipleValuesForDifferentField.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.MultipleValuesForSameField.ProtobufOutput
|
||||||
Required.Proto3.ProtobufInput.ValidDataOneof.FLOAT.NonDefaultValue.ProtobufOutput
|
Required.Proto3.ProtobufInput.ValidDataOneof.FLOAT.NonDefaultValue.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.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.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.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.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.PackedInput.ProtobufOutput
|
Required.Proto3.ProtobufInput.ValidDataRepeated.BOOL.PackedInput.ProtobufOutput
|
||||||
Required.Proto3.ProtobufInput.ValidDataRepeated.BOOL.UnpackedInput.ProtobufOutput
|
Required.Proto3.ProtobufInput.ValidDataRepeated.BOOL.UnpackedInput.ProtobufOutput
|
||||||
|
|
|
@ -16,7 +16,10 @@ type
|
||||||
x {.fieldNumber: 1.}: bool
|
x {.fieldNumber: 1.}: bool
|
||||||
|
|
||||||
proc writeRead[W, R](toWrite: W, value: R) =
|
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":
|
suite "Test Boolean Encoding/Decoding":
|
||||||
test "Can encode/decode boolean without subtype specification":
|
test "Can encode/decode boolean without subtype specification":
|
||||||
|
|
|
@ -109,6 +109,8 @@ suite "codec test suite":
|
||||||
let data = getVarintEncodedValue(VarintValues[i])
|
let data = getVarintEncodedValue(VarintValues[i])
|
||||||
check:
|
check:
|
||||||
toHex(data) == VarintVectors[i]
|
toHex(data) == VarintVectors[i]
|
||||||
|
data.len == computeSize(puint64(VarintValues[i]))
|
||||||
|
|
||||||
getVarintDecodedValue(data) == VarintValues[i]
|
getVarintDecodedValue(data) == VarintValues[i]
|
||||||
|
|
||||||
test "[varint] incorrect values test":
|
test "[varint] incorrect values test":
|
||||||
|
@ -125,6 +127,7 @@ suite "codec test suite":
|
||||||
let data = getFixed32EncodedValue(cast[float32](Fixed32Values[i]))
|
let data = getFixed32EncodedValue(cast[float32](Fixed32Values[i]))
|
||||||
check:
|
check:
|
||||||
toHex(data) == Fixed32Vectors[i]
|
toHex(data) == Fixed32Vectors[i]
|
||||||
|
data.len == computeSize(fixed32(Fixed32Values[i]))
|
||||||
getFixed32DecodedValue(data) == Fixed32Values[i]
|
getFixed32DecodedValue(data) == Fixed32Values[i]
|
||||||
|
|
||||||
test "[fixed32] incorrect values test":
|
test "[fixed32] incorrect values test":
|
||||||
|
@ -140,6 +143,7 @@ suite "codec test suite":
|
||||||
let data = getFixed64EncodedValue(cast[float64](Fixed64Values[i]))
|
let data = getFixed64EncodedValue(cast[float64](Fixed64Values[i]))
|
||||||
check:
|
check:
|
||||||
toHex(data) == Fixed64Vectors[i]
|
toHex(data) == Fixed64Vectors[i]
|
||||||
|
data.len == computeSize(fixed64(Fixed64Values[i]))
|
||||||
getFixed64DecodedValue(data) == Fixed64Values[i]
|
getFixed64DecodedValue(data) == Fixed64Values[i]
|
||||||
|
|
||||||
test "[fixed64] incorrect values test":
|
test "[fixed64] incorrect values test":
|
||||||
|
@ -153,10 +157,12 @@ suite "codec test suite":
|
||||||
test "[length] edge values test":
|
test "[length] edge values test":
|
||||||
for i in 0 ..< len(LengthValues):
|
for i in 0 ..< len(LengthValues):
|
||||||
let data1 = getLengthEncodedValue(LengthValues[i])
|
let data1 = getLengthEncodedValue(LengthValues[i])
|
||||||
let data2 = getLengthEncodedValue(cast[seq[byte]](LengthValues[i]))
|
let data2 = getLengthEncodedValue(toBytes(LengthValues[i]))
|
||||||
check:
|
check:
|
||||||
toHex(data1) == LengthVectors[i]
|
toHex(data1) == LengthVectors[i]
|
||||||
|
computeSize(pstring(LengthValues[i])) == data1.len
|
||||||
toHex(data2) == LengthVectors[i]
|
toHex(data2) == LengthVectors[i]
|
||||||
|
computeSize(pbytes(toBytes(LengthValues[i]))) == data2.len
|
||||||
check:
|
check:
|
||||||
getLengthDecodedValue(data1) == LengthValues[i]
|
getLengthDecodedValue(data1) == LengthValues[i]
|
||||||
getLengthDecodedValue(data2) == LengthValues[i]
|
getLengthDecodedValue(data2) == LengthValues[i]
|
||||||
|
|
|
@ -56,7 +56,7 @@ suite "Test Object Encoding/Decoding":
|
||||||
writer = memoryOutput()
|
writer = memoryOutput()
|
||||||
|
|
||||||
writer.writeField(1, sint32(obj.d))
|
writer.writeField(1, sint32(obj.d))
|
||||||
writer.writeField(3, obj.f)
|
writer.writeField(3, obj.f, pbytes)
|
||||||
writer.writeField(4, pstring(obj.g))
|
writer.writeField(4, pstring(obj.g))
|
||||||
|
|
||||||
let result = Protobuf.decode(writer.getOutput(), type(Wrapped))
|
let result = Protobuf.decode(writer.getOutput(), type(Wrapped))
|
||||||
|
@ -77,7 +77,7 @@ suite "Test Object Encoding/Decoding":
|
||||||
)
|
)
|
||||||
writer = memoryOutput()
|
writer = memoryOutput()
|
||||||
|
|
||||||
writer.writeField(3, obj.f)
|
writer.writeField(3, obj.f, pbytes)
|
||||||
#writer.writeField(6, penum(obj.i))
|
#writer.writeField(6, penum(obj.i))
|
||||||
writer.writeField(1, sint64(obj.d))
|
writer.writeField(1, sint64(obj.d))
|
||||||
writer.writeField(2, sint64(obj.e))
|
writer.writeField(2, sint64(obj.e))
|
||||||
|
|
|
@ -34,6 +34,7 @@ z: ["zero", "one", "two"]
|
||||||
"080a080508d80408c7091001100010011001100010001000100110001a047a65726f1a036f6e651a0374776f")
|
"080a080508d80408c7091001100010011001100010001000100110001a047a65726f1a036f6e651a0374776f")
|
||||||
|
|
||||||
check:
|
check:
|
||||||
|
Protobuf.computeSize(v) == encoded.len
|
||||||
Protobuf.encode(v) == encoded
|
Protobuf.encode(v) == encoded
|
||||||
Protobuf.decode(encoded, typeof(v)) == v
|
Protobuf.decode(encoded, typeof(v)) == v
|
||||||
|
|
||||||
|
@ -56,5 +57,6 @@ a: [5, -3, 300, -612]
|
||||||
"0a060a05d804c70912090100010100000001001a1005000000fdffffff2c0100009cfdffff22100000a040000040c000009643000019c4")
|
"0a060a05d804c70912090100010100000001001a1005000000fdffffff2c0100009cfdffff22100000a040000040c000009643000019c4")
|
||||||
|
|
||||||
check:
|
check:
|
||||||
|
Protobuf.computeSize(v) == encoded.len
|
||||||
Protobuf.encode(v) == encoded
|
Protobuf.encode(v) == encoded
|
||||||
Protobuf.decode(encoded, typeof(v)) == v
|
Protobuf.decode(encoded, typeof(v)) == v
|
||||||
|
|
Loading…
Reference in New Issue