diff options
Diffstat (limited to 'generator/protoc_gen_nim.nim')
| -rw-r--r-- | generator/protoc_gen_nim.nim | 161 |
1 files changed, 85 insertions, 76 deletions
diff --git a/generator/protoc_gen_nim.nim b/generator/protoc_gen_nim.nim index 1304ed9..3680de7 100644 --- a/generator/protoc_gen_nim.nim +++ b/generator/protoc_gen_nim.nim @@ -510,6 +510,9 @@ iterator genProcs(e: Enum): string = yield &"proc write{e.names}*(stream: ProtobufStream, value: {e.names}) =" yield indent(&"writeUInt32(stream, uint32(value))", 4) yield "" + yield &"proc write{e.names}*(stream: ProtobufStream, value: {e.names}, fieldNumber: int) =" + yield indent(&"writeUInt32(stream, uint32(value), fieldNumber)", 4) + yield "" yield &"proc sizeOf{e.names}*(value: {e.names}): uint64 =" yield indent(&"sizeOfUInt32(uint32(value))", 4) @@ -531,23 +534,33 @@ iterator oneofSiblings(field: Field): Field = iterator genClearFieldProc(msg: Message, field: Field): string = yield &"proc clear{field.name}*(message: {msg.names}) =" yield indent(&"message.{field.accessor} = {defaultValue(field)}", 4) - yield indent(&"excl(message.hasField, {field.number})", 4) + var numbers: seq[int] = @[field.number] for sibling in oneofSiblings(field): - yield indent(&"excl(message.hasField, {sibling.number})", 4) + add(numbers, sibling.number) + yield indent(&"excl(message.hasField, [{join(numbers, \", \")}])", 4) yield "" iterator genHasFieldProc(msg: Message, field: Field): string = # TODO: if map/seq, check also if there are values! yield &"proc has{field.name}*(message: {msg.names}): bool =" - yield indent(&"result = contains(message.hasField, {field.number})", 4) + var check = indent(&"result = contains(message.hasField, {field.number})", 4) + if isRepeated(field) or isMapEntry(field): + check = &"{check} or (len(message.{field.accessor}) > 0)" + yield check + # elif isMapEntry(field): + # base = &"{base} or (len(message.{}" + # yield indent(&"result = contains(message.hasField, {field.number})", 4) yield "" iterator genSetFieldProc(msg: Message, field: Field): string = yield &"proc set{field.name}*(message: {msg.names}, value: {field.fullType}) =" yield indent(&"message.{field.accessor} = value", 4) yield indent(&"incl(message.hasField, {field.number})", 4) + var numbers: seq[int] = @[] for sibling in oneofSiblings(field): - yield indent(&"excl(message.hasField, {sibling.number})", 4) + add(numbers, sibling.number) + if len(numbers) > 0: + yield indent(&"excl(message.hasField, [{join(numbers, \", \")}])", 4) yield "" iterator genAddToFieldProc(msg: Message, field: Field): string = @@ -572,13 +585,12 @@ iterator genWriteMapKVProc(msg: Message): string = yield &"proc write{msg.names}KV(stream: ProtobufStream, key: {key.fullType}, value: {value.fullType}) =" - yield indent(&"writeTag(stream, {key.number}, {wiretypeStr(key)})", 4) - yield indent(&"write{key.typeName}(stream, key)", 4) + yield indent(&"write{key.typeName}(stream, key, {key.number})", 4) - yield indent(&"writeTag(stream, {value.number}, {wiretypeStr(value)})", 4) if isMessage(value): - yield indent(&"writeVarint(stream, sizeOf{value.typeName}(value))", 4) - yield indent(&"write{value.typeName}(stream, value)", 4) + yield indent(&"writeMessage(stream, value, {value.number})", 4) + else: + yield indent(&"write{value.typeName}(stream, value, {value.number})", 4) yield "" @@ -600,16 +612,16 @@ iterator genWriteMessageProc(msg: Message): string = yield indent(&"{writer}(stream, value)", 12) else: yield indent(&"for value in message.{field.name}:", 4) - yield indent(&"writeTag(stream, {field.number}, {wiretypeStr(field)})", 8) if isMessage(field): - yield indent(&"writeVarint(stream, sizeOf{field.typeName}(value))", 8) - yield indent(&"{writer}(stream, value)", 8) + yield indent(&"writeMessage(stream, value, {field.number})", 8) + else: + yield indent(&"{writer}(stream, value, {field.number})", 8) else: yield indent(&"if has{field.name}(message):", 4) - yield indent(&"writeTag(stream, {field.number}, {wiretypeStr(field)})", 8) if isMessage(field): - yield indent(&"writeVarint(stream, sizeOf{field.typeName}(message.{field.accessor}))", 8) - yield indent(&"{writer}(stream, message.{field.accessor})", 8) + yield indent(&"writeMessage(stream, message.{field.accessor}, {field.number})", 8) + else: + yield indent(&"{writer}(stream, message.{field.accessor}, {field.number})", 8) if len(msg.fields) == 0: yield indent("discard", 4) @@ -725,13 +737,18 @@ iterator genSizeOfMapKVProc(message: Message): string = value = mapValueField(message) yield &"proc sizeOf{message.names}KV(key: {key.fullType}, value: {value.fullType}): uint64 =" + + # Key (cannot be message or other complex field) + yield indent(&"result = result + sizeOfTag({key.number}, {key.wiretypeStr})", 4) yield indent(&"result = result + sizeOf{key.typeName}(key)", 4) - yield indent(&"result = result + sizeOfUInt32(uint32(makeTag({key.number}, {key.wiretypeStr})))", 4) - yield indent(&"let valueSize = sizeOf{value.typeName}(value)", 4) - yield indent(&"result = result + valueSize", 4) - yield indent(&"result = result + sizeOfUInt32(uint32(makeTag({value.number}, {value.wiretypeStr})))", 4) + + # Value + yield indent(&"result = result + sizeOfTag({value.number}, {value.wiretypeStr})", 4) if isMessage(value): - yield indent(&"result = result + sizeOfUInt64(valueSize)", 4) + yield indent(&"result = result + sizeOfLengthDelimited(sizeOf{value.typeName}(value))", 4) + else: + yield indent(&"result = result + sizeOf{value.typeName}(value)", 4) + yield "" iterator genSizeOfMessageProc(msg: Message): string = @@ -742,36 +759,27 @@ iterator genSizeOfMessageProc(msg: Message): string = yield indent(&"var sizeOfKV = 0'u64", 8) yield indent(&"for key, value in message.{field.name}:", 8) yield indent(&"sizeOfKV = sizeOfKV + sizeOf{field.typeName}KV(key, value)", 12) - yield indent(&"let sizeOfTag = sizeOfUInt32(uint32(makeTag({field.number}, {wiretypeStr(field)})))", 8) - yield indent("result = result + sizeOfKV + sizeOfTag + sizeOfUInt64(sizeOfKV)", 8) + yield indent(&"result = result + sizeOfTag({field.number}, {field.wiretypeStr})", 8) + yield indent(&"result = result + sizeOfLengthDelimited(sizeOfKV)", 8) elif isRepeated(field): if isNumeric(field): - yield indent(&""" -if has{field.name}(message): - let - sizeOfTag = sizeOfUInt32(uint32(makeTag({field.number}, WireType.LengthDelimited))) - sizeOfData = packedFieldSize(message.{field.name}, {field.fieldTypeStr}) - sizeOfSize = sizeOfUInt64(sizeOfData) - result = sizeOfTag + sizeOfData + sizeOfSize""", 4) + yield indent(&"if has{field.name}(message):", 4) + yield indent(&"result = result + sizeOfTag({field.number}, WireType.LengthDelimited)", 8) + yield indent(&"result = result + sizeOfLengthDelimited(packedFieldSize(message.{field.name}, {field.fieldTypeStr}))", 8) else: - yield indent(&""" -for value in message.{field.name}: - let - sizeOfValue = sizeOf{field.typeName}(value) - sizeOfTag = sizeOfUInt32(uint32(makeTag({field.number}, {wiretypeStr(field)}))) - result = result + sizeOfValue + sizeOfTag -""", 4) + yield indent(&"for value in message.{field.name}:", 4) + yield indent(&"result = result + sizeOfTag({field.number}, {field.wiretypeStr})", 8) if isMessage(field): - yield indent("result = result + sizeOfUInt64(sizeOfValue)", 8) + yield indent(&"result = result + sizeOfLengthDelimited(sizeOf{field.typeName}(value))", 8) + else: + yield indent(&"result = result + sizeOf{field.typeName}(value)", 8) else: - yield indent(&""" -if has{field.name}(message): - let - sizeOfField = sizeOf{field.typeName}(message.{field.accessor}) - sizeOfTag = sizeOfUInt32(uint32(makeTag({field.number}, {wiretypeStr(field)}))) - result = result + sizeOfField + sizeOfTag""", 4) + yield indent(&"if has{field.name}(message):", 4) + yield indent(&"result = result + sizeOfTag({field.number}, {field.wiretypeStr})", 8) if isMessage(field): - yield indent("result = result + sizeOfUInt64(sizeOfField)", 8) + yield indent(&"result = result + sizeOfLengthDelimited(sizeOf{field.typeName}(message.{field.accessor}))", 8) + else: + yield indent(&"result = result + sizeOf{field.typeName}(message.{field.accessor})", 8) if len(msg.fields) == 0: yield indent("result = 0", 4) @@ -779,10 +787,11 @@ if has{field.name}(message): yield "" iterator genMessageProcForwards(msg: Message): string = - yield &"proc new{msg.names}*(): {msg.names}" - yield &"proc write{msg.names}*(stream: ProtobufStream, message: {msg.names})" - yield &"proc read{msg.names}*(stream: ProtobufStream): {msg.names}" - yield &"proc sizeOf{msg.names}*(message: {msg.names}): uint64" + if not isMapEntry(msg): + yield &"proc new{msg.names}*(): {msg.names}" + yield &"proc write{msg.names}*(stream: ProtobufStream, message: {msg.names})" + yield &"proc read{msg.names}*(stream: ProtobufStream): {msg.names}" + yield &"proc sizeOf{msg.names}*(message: {msg.names}): uint64" if isMapEntry(msg): let @@ -794,41 +803,41 @@ iterator genMessageProcForwards(msg: Message): string = yield &"proc sizeOf{msg.names}KV(key: {key.fullType}, value: {value.fullType}): uint64" iterator genProcs(msg: Message): string = - for line in genNewMessageProc(msg): yield line - - for field in msg.fields: - for line in genClearFieldProc(msg, field): yield line - for line in genHasFieldProc(msg, field): yield line - for line in genSetFieldProc(msg, field): yield line - - if isRepeated(field) and not isMapEntry(field): - for line in genAddToFieldProc(msg, field): yield line - - for line in genFieldAccessorProcs(msg, field): yield line - if isMapEntry(msg): for line in genSizeOfMapKVProc(msg): yield line for line in genWriteMapKVProc(msg): yield line for line in genReadMapKVProc(msg): yield line + else: + for line in genNewMessageProc(msg): yield line - for line in genSizeOfMessageProc(msg): yield line - for line in genWriteMessageProc(msg): yield line - for line in genReadMessageProc(msg): yield line + for field in msg.fields: + for line in genClearFieldProc(msg, field): yield line + for line in genHasFieldProc(msg, field): yield line + for line in genSetFieldProc(msg, field): yield line - yield &"proc serialize*(message: {msg.names}): string =" - yield indent("let", 4) - yield indent("ss = newStringStream()", 8) - yield indent("pbs = newProtobufStream(ss)", 8) - yield indent(&"write{msg.names}(pbs, message)", 4) - yield indent("result = ss.data", 4) - yield "" + if isRepeated(field) and not isMapEntry(field): + for line in genAddToFieldProc(msg, field): yield line - yield &"proc new{msg.names}*(data: string): {msg.names} =" - yield indent("let", 4) - yield indent("ss = newStringStream(data)", 8) - yield indent("pbs = newProtobufStream(ss)", 8) - yield indent(&"result = read{msg.names}(pbs)", 4) - yield "" + for line in genFieldAccessorProcs(msg, field): yield line + + for line in genSizeOfMessageProc(msg): yield line + for line in genWriteMessageProc(msg): yield line + for line in genReadMessageProc(msg): yield line + + yield &"proc serialize*(message: {msg.names}): string =" + yield indent("let", 4) + yield indent("ss = newStringStream()", 8) + yield indent("pbs = newProtobufStream(ss)", 8) + yield indent(&"write{msg.names}(pbs, message)", 4) + yield indent("result = ss.data", 4) + yield "" + + yield &"proc new{msg.names}*(data: string): {msg.names} =" + yield indent("let", 4) + yield indent("ss = newStringStream(data)", 8) + yield indent("pbs = newProtobufStream(ss)", 8) + yield indent(&"result = read{msg.names}(pbs)", 4) + yield "" proc processFile(filename: string, fdesc: FileDescriptorProto, otherFiles: TableRef[string, ProtoFile]): ProcessedFile = |
