Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 29 additions & 7 deletions protobuf_serialization/files/type_generator.nim
Original file line number Diff line number Diff line change
Expand Up @@ -78,21 +78,29 @@ proc getMessage(name: string, messages: seq[ProtoNode]): ProtoNode =
return res
return nil

proc isNested(base: string, currentName: string, messages: seq[ProtoNode]): bool =
proc isNested(base: string, currentName: string, messages: seq[ProtoNode], seen: var seq[ProtoNode]): bool =
let msg = currentName.getMessage(messages)
if msg.isNil():
return false
if msg in seen:
return false
seen.add msg
for field in msg.fields:
if field.kind == ProtoType.Field:
if field.presence == Repeated: continue
if base == field.protoType or base.isNested(field.protoType, messages):
if base == field.protoType or base.isNested(field.protoType, messages, seen):
return true
elif field.kind == ProtoType.Oneof:
for f in field.oneof:
if f.presence == Repeated: continue
if base == f.protoType or base.isNested(f.protoType, messages):
if base == f.protoType or base.isNested(f.protoType, messages, seen):
return true

proc isNested(base: string, currentName: string, messages: seq[ProtoNode]): bool =
# XXX use a set
var seen = default(seq[ProtoNode])
isNested(base, currentName, messages, seen)

# Exported for the tests.
proc protoToTypesInternal*(filepath: string, isProto3 = true): NimNode {.compileTime.} =
var
Expand All @@ -102,6 +110,21 @@ proc protoToTypesInternal*(filepath: string, isProto3 = true): NimNode {.compile
for parsed in packages:
for msg in parsed.messages:
queue.add(msg)
if msg.kind != ProtoType.Extend:
for field in msg.fields:
if field.kind == ProtoType.Oneof:
# XXX this should be supported
continue
if field.protoType.startsWith("map<"):
let matches = field.protoType.split({'<', '>', ','})
let entryFields = @[
ProtoNode(kind: Field, number: 1, protoType: matches[1], name: "key"),
ProtoNode(kind: Field, number: 2, protoType: matches[2], name: "value")
]
queue.add ProtoNode(
kind: Message,
messageName: field.name & "Entry",
fields: entryFields)
# TODO: define Enums first to workaround https://github.com/nim-lang/Nim/issues/25651
if msg.kind != ProtoType.Extend:
if (msg.definedEnums.len != 0) or (msg.nested.len != 0):
Expand Down Expand Up @@ -176,10 +199,9 @@ proc protoToTypesInternal*(filepath: string, isProto3 = true): NimNode {.compile
break

if value[2][^1][1].strVal.startsWith("map<"):
var matches = value[2][^1][1].strVal.split({'<', '>', ','})
let (typ1, _) = getTypeAndPragma(matches[1])
let (typ2, _) = getTypeAndPragma(matches[2])
value[2][^1][1] = nnkBracketExpr.newTree(newIdentNode("Table"), typ1, typ2)
value[2][^1][1] = newNimNode(nnkBracketExpr).add(
ident("seq"), ident(field.name & "Entry")
)
else:
let (typ, pragma) = getTypeAndPragma(value[2][^1][1].strVal)
value[2][^1][1] = typ
Expand Down
34 changes: 2 additions & 32 deletions protobuf_serialization/internal.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

{.push raises: [], gcsafe.}

import std/[options, sets, tables]
import std/[options, sets]
import stew/shims/macros
#Depending on the situation, one of these two are used.
#Sometimes, one works where the other doesn't.
Expand Down Expand Up @@ -56,28 +56,6 @@ 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

Expand Down Expand Up @@ -149,8 +127,6 @@ template protoType*(InnerType, RootType, FieldType: untyped, fieldName: untyped)
type InnerType = UnsupportedType[FieldType, RootType, fieldName]

template elementType[T](_: type seq[T]): type = typeof(T)
template elementTypeKey[K, V](_: type Table[K, V]): type = typeof(K)
template elementTypeVal[K, V](_: type Table[K, V]): type = typeof(V)

func verifySerializable*[T](ty: typedesc[T]) {.compileTime.} =
type FlatType = flatType(default(T))
Expand All @@ -164,12 +140,6 @@ func verifySerializable*[T](ty: typedesc[T]) {.compileTime.} =
# type Value = object (list: List)
else:
verifySerializable(elementType(FlatType))
elif FlatType is Table and defined(ConformanceTest):
return # TODO make it work in case of recursivity
# type Struct = object (map: Table[..., Value])
# type Value = object (struct: Struct)
# verifySerializable(elementTypeKey(FlatType))
# verifySerializable(elementTypeVal(FlatType))
elif FlatType is object and T isnot PBOption:
var
inst: T
Expand All @@ -183,7 +153,7 @@ func verifySerializable*[T](ty: typedesc[T]) {.compileTime.} =

enumInstanceSerializedFields(inst, fieldName, fieldVar):
when isProto2 and not T.isRequired(fieldName):
when fieldVar is not (seq or PBOption or Table):
when fieldVar is not (seq or PBOption):
fieldError T, fieldName, "proto2 requires every field to either have the required pragma attached or be a repeated field/PBOption."
when isProto3 and (
T.hasCustomPragmaFixed(fieldName, required) or
Expand Down
15 changes: 2 additions & 13 deletions protobuf_serialization/reader.nim
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{.push raises: [], gcsafe.}

import
std/[typetraits, sets, tables],
std/[typetraits, sets],
stew/assign2,
stew/objects,
stew/shims/macros,
Expand All @@ -18,7 +18,7 @@ proc readValueInternal[T: object](stream: InputStream, value: var T, silent: boo
macro unsupported(T: typed): untyped =
error "Assignment of the type " & humaneTypeName(T) & " is not supported"

proc readFieldInto[T: object and not Table](
proc readFieldInto[T: object](
stream: InputStream,
value: var T,
header: FieldHeader,
Expand Down Expand Up @@ -57,17 +57,6 @@ when defined(ConformanceTest):
if not checkedEnumAssign(value, enumValue.int32):
discard checkedEnumAssign(value, 0)

proc readFieldInto[K, V](
stream: InputStream,
value: var Table[K, V],
header: FieldHeader,
ProtoType: type
) {.raises: [SerializationError, IOError].} =
tableObject(TableObject, K, V)
var tmp = default(TableObject)
stream.readFieldInto(tmp, header, ProtoType)
value[tmp.key] = tmp.value

proc readFieldInto[T: not object and not enum and (seq[byte] or not seq)](
stream: InputStream,
value: var T,
Expand Down
10 changes: 1 addition & 9 deletions protobuf_serialization/sizer.nim
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{.push raises: [], gcsafe.}

import
std/[typetraits, tables],
std/[typetraits],
stew/shims/macros,
serialization,
"."/[codec, internal, types]
Expand Down Expand Up @@ -61,14 +61,6 @@ when defined(ConformanceTest):
{.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 =
Expand Down
16 changes: 2 additions & 14 deletions protobuf_serialization/writer.nim
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{.push raises: [], gcsafe.}

import
std/[typetraits, tables],
std/[typetraits],
stew/shims/macros,
stew/objects,
faststreams/outputs,
Expand All @@ -20,7 +20,7 @@ proc writeField*(
# TODO turn this into an extension point
unsupportedProtoType ProtoType.FieldType, ProtoType.RootType, ProtoType.fieldName

proc writeField*[T: object and not PBOption and not Table](
proc writeField*[T: object and not PBOption](
stream: OutputStream, fieldNum: int, fieldVal: T, ProtoType: type pbytes,
skipDefault: static bool = false) {.raises: [IOError].} =
let
Expand Down Expand Up @@ -84,18 +84,6 @@ when defined(ConformanceTest):
return
stream.writeField(fieldNum, pint32(fieldVal.ord()))

proc writeField[K, V](
stream: OutputStream,
fieldNum: int,
value: Table[K, V],
ProtoType: type,
skipDefault: static bool = false
) {.raises: [IOError].} =
tableObject(TableObject, K, V)
for k, v in value.pairs():
let tmp = TableObject(key: k, value: v)
stream.writeField(fieldNum, tmp, ProtoType)

proc writeField*(
stream: OutputStream, fieldNum: int, fieldVal: PBOption, ProtoType: type,
skipDefault: static bool = false) {.raises: [IOError].} =
Expand Down
Loading
Loading