diff options
| author | Oskari Timperi <oskari.timperi@iki.fi> | 2018-03-24 15:44:30 +0200 |
|---|---|---|
| committer | Oskari Timperi <oskari.timperi@iki.fi> | 2018-03-24 15:44:30 +0200 |
| commit | 0bc7b67059868af65d2158a8aeade5b6f777431b (patch) | |
| tree | b8ce5211ac3cf673a62911e852ed014d5f11f43d /src | |
| download | nimpb-0bc7b67059868af65d2158a8aeade5b6f777431b.tar.gz nimpb-0bc7b67059868af65d2158a8aeade5b6f777431b.zip | |
initial commit
Diffstat (limited to 'src')
| -rw-r--r-- | src/protobuf/gen.nim | 385 | ||||
| -rw-r--r-- | src/protobuf/stream.nim | 311 | ||||
| -rw-r--r-- | src/protobuf/types.nim | 80 |
3 files changed, 776 insertions, 0 deletions
diff --git a/src/protobuf/gen.nim b/src/protobuf/gen.nim new file mode 100644 index 0000000..881b275 --- /dev/null +++ b/src/protobuf/gen.nim @@ -0,0 +1,385 @@ +import macros +import strutils + +import types + +type + MessageDesc* = object + name*: string + fields*: seq[FieldDesc] + + FieldLabel* {.pure.} = enum + Optional = 1 + Required + Repeated + + FieldDesc* = object + name*: string + number*: int + ftype*: FieldType + label*: FieldLabel + typeName*: string + packed*: bool + +proc toNimNode(ftype: FieldType): NimNode {.compileTime.} = + case ftype + of FieldType.Double: result = ident("float64") + of FieldType.Float: result = ident("float32") + of FieldType.Int64: result = ident("int64") + of FieldType.UInt64: result = ident("uint64") + of FieldType.Int32: result = ident("int32") + of FieldType.Fixed64: result = ident("fixed64") + of FieldType.Fixed32: result = ident("fixed32") + of FieldType.Bool: result = ident("bool") + of FieldType.String: result = ident("string") + of FieldType.Group: result = ident("NOTIMPLEMENTED") + of FieldType.Message: result = ident("TODO") + of FieldType.Bytes: result = ident("bytes") + of FieldType.UInt32: result = ident("uint32") + of FieldType.Enum: result = ident("TODO") + of FieldType.SFixed32: result = ident("sfixed32") + of FieldType.SFixed64: result = ident("sfixed64") + of FieldType.SInt32: result = ident("sint32") + of FieldType.SInt64: result = ident("sint64") + +proc findColonExpr(parent: NimNode, s: string): NimNode = + for child in parent: + if child.kind != nnkExprColonExpr: + continue + + if $child[0] == s: + return child + +proc getMessageName(desc: NimNode): string = + let node = findColonExpr(desc, "name") + result = $node[1] + +iterator fields(desc: NimNode): NimNode = + let node = findColonExpr(desc, "fields") + for field in node[1]: + yield field + +proc isRepeated(field: NimNode): bool = + let node = findColonExpr(field, "label") + let value = FieldLabel(node[1].intVal) + result = value == FieldLabel.Repeated + +proc isPacked(field: NimNode): bool = + let node = findColonExpr(field, "packed") + result = bool(node[1].intVal) + +proc getFieldType(field: NimNode): FieldType = + let node = findColonExpr(field, "ftype") + result = FieldType(node[1].intVal) + +proc getFullFieldType(field: NimNode): NimNode = + let ftype = getFieldType(field) + result = toNimNode(ftype) + if isRepeated(field): + result = nnkBracketExpr.newTree(ident("seq"), result) + +proc getFieldName(field: NimNode): string = + let node = findColonExpr(field, "name") + result = $node[1] + +proc getFieldNumber(field: NimNode): int = + result = int(findColonExpr(field, "number")[1].intVal) + +proc defaultValue(field: NimNode): NimNode = + # TODO: check if there is a default value specified for the field + + if isRepeated(field): + return nnkPrefix.newTree(newIdentNode("@"), nnkBracket.newTree()) + + case getFieldType(field) + of FieldType.Double: result = newLit(0.0'f64) + of FieldType.Float: result = newLit(0.0'f32) + of FieldType.Int64: result = newLit(0'i64) + of FieldType.UInt64: result = newLit(0'u64) + of FieldType.Int32: result = newLit(0'i32) + of FieldType.Fixed64: result = newLit(0'u64) + of FieldType.Fixed32: result = newLit(0'u32) + of FieldType.Bool: result = newLit(false) + of FieldType.String: result = newLit("") + of FieldType.Group: result = newLit("NOTIMPLEMENTED") + of FieldType.Message: result = newLit("TODO") + of FieldType.Bytes: result = newCall(ident("bytes"), newLit("")) + of FieldType.UInt32: result = newLit(0'u32) + of FieldType.Enum: result = newLit("TODO") + of FieldType.SFixed32: result = newCall(ident("sfixed32"), newLit(0)) + of FieldType.SFixed64: result = newCall(ident("sfixed64"), newLit(0)) + of FieldType.SInt32: result = newCall(ident("sint32"), newLit(0)) + of FieldType.SInt64: result = newCall(ident("sint64"), newLit(0)) + +proc wiretype(field: NimNode): WireType = + result = wiretype(getFieldType(field)) + +proc fieldInitializer(objname: string, field: NimNode): NimNode = + result = nnkAsgn.newTree( + nnkDotExpr.newTree( + newIdentNode(objname), + newIdentNode(getFieldName(field)) + ), + defaultValue(field) + ) + +macro generateMessageType*(desc: typed): typed = + let + impl = getImpl(symbol(desc)) + typeSection = nnkTypeSection.newTree() + typedef = nnkTypeDef.newTree() + reclist = nnkRecList.newTree() + + let name = getMessageName(impl) + + let typedefRef = nnkTypeDef.newTree(postfix(newIdentNode(name), "*"), newEmptyNode(), + nnkRefTy.newTree(newIdentNode(name & "Obj"))) + add(typeSection, typedefRef) + + add(typeSection, typedef) + + add(typedef, postfix(ident(name & "Obj"), "*")) + add(typedef, newEmptyNode()) + add(typedef, nnkObjectTy.newTree(newEmptyNode(), newEmptyNode(), reclist)) + + for field in fields(impl): + let ftype = getFullFieldType(field) + let name = ident(getFieldName(field)) + add(reclist, newIdentDefs(name, ftype)) + + add(reclist, nnkIdentDefs.newTree( + ident("hasField"), ident("IntSet"), newEmptyNode())) + + result = newStmtList() + add(result, typeSection) + + when defined(debug): + hint(repr(result)) + +proc generateNewMessageProc(desc: NimNode): NimNode = + let body = newStmtList( + newCall(ident("new"), ident("result")) + ) + + for field in fields(desc): + add(body, fieldInitializer("result", field)) + + add(body, newAssignment(newDotExpr(ident("result"), ident("hasField")), + newCall(ident("initIntSet")))) + + result = newProc(postfix(ident("new" & getMessageName(desc)), "*"), + @[ident(getMessageName(desc))], + body) + +proc generateClearFieldProc(desc, field: NimNode): NimNode = + let body = nnkStmtList.newTree() + + let messageName = getMessageName(desc) + let fieldName = getFieldName(field) + + add(body, fieldInitializer("message", field)) + + add(body, nnkCall.newTree( + ident("excl"), + nnkDotExpr.newTree( + ident("message"), + ident("hasField") + ), + newLit(getFieldNumber(field)) + )) + + result = newProc(postfix(ident("clear" & capitalizeAscii(fieldName)), "*"), + @[newEmptyNode(), newIdentDefs(ident("message"), ident(messageName))], + body) + +proc generateHasFieldProc(desc, field: NimNode): NimNode = + let body = nnkCall.newTree( + ident("contains"), + newDotExpr(ident("message"), ident("hasField")), + newLit(getFieldNumber(field)) + ) + + let messageName = getMessageName(desc) + let fieldName = getFieldName(field) + + result = newProc(postfix(ident("has" & capitalizeAscii(fieldName)), "*"), + @[ident("bool"), newIdentDefs(ident("message"), ident(messageName))], + body) + +proc generateSetFieldProc(desc, field: NimNode): NimNode = + # let body = nnkStmtList.newTree(nnkDiscardStmt.newTree(newEmptyNode())) + + let body = newStmtList() + + let messageName = getMessageName(desc) + let fieldName = getFieldName(field) + + add(body, newAssignment(newDotExpr(ident("message"), ident(fieldName)), ident("value"))) + + add(body, newCall("incl", newDotExpr(ident("message"), ident("hasField")), + newLit(getFieldNumber(field)))) + + let ftype = getFullFieldType(field) + + result = newProc(postfix(ident("set" & capitalizeAscii(fieldName)), "*"), + @[newEmptyNode(), newIdentDefs(ident("message"), + ident(messageName)), + newIdentDefs(ident("value"), ftype)], + body) + +proc generateAddToFieldProc(desc, field: NimNode): NimNode = + let body = newStmtList() + + let messageName = getMessageName(desc) + let fieldName = getFieldName(field) + + add(body, newCall( + ident("add"), + newDotExpr(ident("message"), ident(fieldName)), + ident("value") + )) + + add(body, newCall("incl", newDotExpr(ident("message"), ident("hasField")), + newLit(getFieldNumber(field)))) + + let ftype = toNimNode(getFieldType(field)) + + result = newProc(postfix(ident("add" & capitalizeAscii(fieldName)), "*"), + @[newEmptyNode(), newIdentDefs(ident("message"), + ident(messageName)), + newIdentDefs(ident("value"), ftype)], + body) + +proc ident(wt: WireType): NimNode = + result = newDotExpr(ident("WireType"), ident($wt)) + +proc genWriteField(field: NimNode): NimNode = + result = newStmtList() + + let + number = getFieldNumber(field) + writer = ident("write" & $getFieldType(field)) + fname = newDotExpr(ident("message"), ident(getFieldName(field))) + wiretype = ident(wiretype(field)) + + if not isRepeated(field): + result.add quote do: + writeTag(stream, `number`, `wiretype`) + `writer`(stream, `fname`) + else: + if isPacked(field): + result.add quote do: + writeTag(stream, `number`, WireType.LengthDelimited) + writeVarInt(stream, packedFieldSize(`fname`, `wiretype`)) + for value in `fname`: + `writer`(stream, value) + else: + result.add quote do: + for value in `fname`: + writeTag(stream, `number`, `wiretype`) + `writer`(stream, value) + +proc generateWriteMessageProc(desc: NimNode): NimNode = + let body = newStmtList() + + let name = getMessageName(desc) + + for field in fields(desc): + add(body, nnkIfStmt.newTree( + nnkElifBranch.newTree( + newCall(ident("has" & capitalizeAscii(getFieldName(field))), + ident("message")), + genWriteField(field) + ) + )) + + result = newProc(postfix(ident("write" & name), "*"), + @[newEmptyNode(), + newIdentDefs(ident("stream"), ident("ProtobufStream")), + newIdentDefs(ident("message"), ident(name))], + body) + +proc generateReadMessageProc(desc: NimNode): NimNode = + let name = getMessageName(desc) + + let resultId = ident("result") + + let body = newStmtList( + newCall(ident("new"), resultId) + ) + + let tagid = ident("tag") + let wiretypeId = ident("wiretype") + + body.add quote do: + while not atEnd(stream): + let + `tagId` = readTag(stream) + `wiretypeId` = getTagWireType(`tagId`) + case getTagFieldNumber(`tagId`) + + let caseNode = body[^1][1][1] + + # TODO: check wiretypes and fail if it doesn't match + for field in fields(desc): + let number = getFieldNumber(field) + if isRepeated(field): + let adder = ident("add" & capitalizeAscii(getFieldName(field))) + let reader = ident("read" & $getFieldType(field)) + if isNumeric(getFieldType(field)): + add(caseNode, nnkOfBranch.newTree(newLit(number), quote do: + if `wiretypeId` == WireType.LengthDelimited: + # TODO: do this only if it makes sense, i.e. with primitives? + let + size = readVarint(stream) + start = getPosition(stream).uint64 + var consumed = 0'u64 + while consumed < size: + `adder`(`resultId`, `reader`(stream)) + consumed = getPosition(stream).uint64 - start + if consumed != size: + raise newException(Exception, "packed field size mismatch") + else: + `adder`(`resultId`, `reader`(stream)) + )) + else: + add(caseNode, nnkOfBranch.newTree(newLit(number), quote do: + `adder`(`resultId`, `reader`(stream)) + )) + else: + let setter = ident("set" & capitalizeAscii(getFieldName(field))) + let reader = ident("read" & $getFieldType(field)) + add(caseNode, nnkOfBranch.newTree(newLit(number), quote do: + `setter`(`resultId`, `reader`(stream)) + )) + + # TODO: generate code to skip unknown fields + add(caseNode, nnkElse.newTree(quote do: + raise newException(Exception, "unknown field") + )) + + result = newProc(postfix(ident("read" & name), "*"), + @[ident(name), newIdentDefs(ident("stream"), ident("ProtobufStream"))], + body) + +macro generateMessageProcs*(x: typed): typed = + let + desc = getImpl(symbol(x)) + + result = newStmtList( + generateNewMessageProc(desc), + ) + + for field in fields(desc): + add(result, generateClearFieldProc(desc, field)) + add(result, generateHasFieldProc(desc, field)) + add(result, generateSetFieldProc(desc, field)) + + if isRepeated(field): + add(result, generateAddToFieldProc(desc, field)) + + add(result, generateWriteMessageProc(desc)) + add(result, generateReadMessageProc(desc)) + + when defined(debug): + hint(repr(result)) diff --git a/src/protobuf/stream.nim b/src/protobuf/stream.nim new file mode 100644 index 0000000..4c026b4 --- /dev/null +++ b/src/protobuf/stream.nim @@ -0,0 +1,311 @@ +import endians +import streams + +import types + +export streams + +const + MaximumVarintBytes = 10 + WireTypeBits = 3 + WireTypeMask = (1 shl WireTypeBits) - 1 + +type + ProtobufStreamObj* = object of StreamObj + stream: Stream + + ProtobufStream* = ref ProtobufStreamObj + + Tag* = distinct uint32 + +proc pbClose(s: Stream) = + close(ProtobufStream(s).stream) + ProtobufStream(s).stream = nil + +proc pbAtEnd(s: Stream): bool = + result = atEnd(ProtobufStream(s).stream) + +proc pbSetPosition(s: Stream, pos: int) = + setPosition(ProtobufStream(s).stream, pos) + +proc pbGetPosition(s: Stream): int = + result = getPosition(ProtobufStream(s).stream) + +proc pbReadData(s: Stream, buffer: pointer, bufLen: int): int = + result = readData(ProtobufStream(s).stream, buffer, bufLen) + +proc pbPeekData(s: Stream, buffer: pointer, bufLen: int): int = + result = peekData(ProtobufStream(s).stream, buffer, bufLen) + +proc pbWriteData(s: Stream, buffer: pointer, bufLen: int) = + writeData(ProtobufStream(s).stream, buffer, bufLen) + +proc pbFlush(s: Stream) = + flush(ProtobufStream(s).stream) + +proc newProtobufStream*(stream: Stream): ProtobufStream = + new(result) + + result.closeImpl = pbClose + result.atEndImpl = pbAtEnd + result.setPositionImpl = pbSetPosition + result.getPositionImpl = pbGetPosition + result.readDataImpl = pbReadData + result.peekDataImpl = pbPeekData + result.writeDataImpl = pbWriteData + result.flushImpl = pbFlush + + result.stream = stream + +proc readByte(stream: ProtobufStream): byte = + result = readInt8(stream).byte + +proc writeByte(stream: ProtobufStream, b: byte) = + var x: byte + shallowCopy(x, b) + writeData(stream, addr(x), sizeof(x)) + +proc readVarint*(stream: ProtobufStream): uint64 = + var + count = 0 + + result = 0 + + while true: + if count == MaximumVarintBytes: + raise newException(Exception, "invalid varint (<= 10 bytes)") + + let b = readByte(stream) + + result = result or ((b.uint64 and 0x7f) shl (7 * count)) + + inc(count) + + if (b and 0x80) == 0: + break + +proc writeVarint*(stream: ProtobufStream, n: uint64) = + var value = n + while value >= 0x80'u64: + writeByte(stream, (value or 0x80).byte) + value = value shr 7 + writeByte(stream, value.byte) + +proc zigzagEncode*(n: int32): uint32 = + {.emit:["result = ((NU32)n << 1) ^ (NU32)(n >> 31);"].} + +proc zigzagDecode*(n: uint32): int32 = + {.emit:["result = (NI32) ((n >> 1) ^ (~(n & 1) + 1));"].} + +proc zigzagEncode*(n: int64): uint64 = + {.emit:["result = ((NU64)n << 1) ^ (NU64)(n >> 63);"].} + +proc zigzagDecode*(n: uint64): int64 = + {.emit:["result = (NI64) ((n >> 1) ^ (~(n & 1) + 1));"].} + +template makeTag*(fieldNumber: int, wireType: WireType): Tag = + ((fieldNumber shl 3).uint32 or wireType.uint32).Tag + +template getTagWireType*(tag: Tag): WireType = + (tag.uint32 and WireTypeMask).WireType + +template getTagFieldNumber*(tag: Tag): int = + (tag.uint32 shr 3).int + +proc writeTag*(stream: ProtobufStream, tag: Tag) = + writeVarint(stream, tag.uint32) + +proc writeTag*(stream: ProtobufStream, fieldNumber: int, wireType: WireType) = + writeTag(stream, makeTag(fieldNumber, wireType)) + +proc readTag*(stream: ProtobufStream): Tag = + result = readVarint(stream).Tag + +proc writeInt32*(stream: ProtobufStream, n: int32) = + writeVarint(stream, n.uint64) + +proc readInt32*(stream: ProtobufStream): int32 = + result = readVarint(stream).int32 + +proc writeSInt32*(stream: ProtobufStream, n: int32) = + writeVarint(stream, zigzagEncode(n)) + +proc readSInt32*(stream: ProtobufStream): int32 = + result = zigzagDecode(readVarint(stream).uint32) + +proc writeUInt32*(stream: ProtobufStream, n: uint32) = + writeVarint(stream, n) + +proc readUInt32*(stream: ProtobufStream): uint32 = + result = readVarint(stream).uint32 + +proc writeInt64*(stream: ProtobufStream, n: int64) = + writeVarint(stream, n.uint64) + +proc readInt64*(stream: ProtobufStream): int64 = + result = readVarint(stream).int64 + +proc writeSInt64*(stream: ProtobufStream, n: int64) = + writeVarint(stream, zigzagEncode(n)) + +proc readSInt64*(stream: ProtobufStream): int64 = + result = zigzagDecode(readVarint(stream)) + +proc writeUInt64*(stream: ProtobufStream, n: uint64) = + writeVarint(stream, n) + +proc readUInt64*(stream: ProtobufStream): uint64 = + result = readVarint(stream) + +proc writeBool*(stream: ProtobufStream, value: bool) = + writeVarint(stream, value.uint32) + +proc readBool*(stream: ProtobufStream): bool = + result = readVarint(stream).bool + +proc writeFixed64*(stream: ProtobufStream, value: fixed64) = + var + input = value + output: fixed64 + + littleEndian64(addr(output), addr(input)) + + write(stream, output) + +proc readFixed64*(stream: ProtobufStream): fixed64 = + var tmp: fixed64 + discard readData(stream, addr(tmp), sizeof(tmp)) + littleEndian64(addr(result), addr(tmp)) + +proc writeSFixed64*(stream: ProtobufStream, value: sfixed64) = + writeFixed64(stream, cast[fixed64](value)) + +proc readSFixed64*(stream: ProtobufStream): sfixed64 = + result = cast[sfixed64](readFixed64(stream)) + +proc writeDouble*(stream: ProtobufStream, value: float64) = + var + input = value + output: float64 + + littleEndian64(addr(output), addr(input)) + + write(stream, output) + +proc readDouble*(stream: ProtobufStream): float64 = + var tmp: uint64 + discard readData(stream, addr(tmp), sizeof(tmp)) + littleEndian64(addr(tmp), addr(result)) + +proc writeFixed32*(stream: ProtobufStream, value: fixed32) = + var + input = value + output: fixed32 + + littleEndian32(addr(output), addr(input)) + + write(stream, output) + +proc readFixed32*(stream: ProtobufStream): fixed32 = + var tmp: uint32 + discard readData(stream, addr(tmp), sizeof(tmp)) + littleEndian32(addr(tmp), addr(result)) + +proc writeSFixed32*(stream: ProtobufStream, value: sfixed32) = + writeFixed32(stream, cast[fixed32](value)) + +proc readSFixed32*(stream: ProtobufStream): sfixed32 = + result = cast[sfixed32](readFixed32(stream)) + +proc writeFloat*(stream: ProtobufStream, value: float32) = + var + input = value + output: float32 + + littleEndian32(addr(output), addr(input)) + + write(stream, output) + +proc readFloat*(stream: ProtobufStream): float32 = + var tmp: float32 + discard readData(stream, addr(tmp), sizeof(tmp)) + littleEndian32(addr(tmp), addr(result)) + +proc writeString*(stream: ProtobufStream, s: string) = + writeUInt64(stream, len(s).uint64) + write(stream, s) + +proc readString*(stream: ProtobufStream): string = + # TODO: use something else than readStr to get rid of int cast? + let size = readUInt64(stream).int + result = readStr(stream, size) + +proc readEnum*[T](stream: ProtobufStream): T = + result = T(readUInt32(stream)) + +proc writeEnum*[T](stream: ProtobufStream, value: T) = + writeUInt32(stream, uint32(value)) + +proc sizeOfVarint[T](value: T): uint64 = + var tmp = uint64(value) + while tmp >= 0x80'u64: + tmp = tmp shr 7 + inc(result) + inc(result) + +proc packedFieldSize*[T](values: seq[T], wiretype: WireType): uint64 = + case wiretype + of WireType.Fixed32: + result = uint64(len(values)) * 4 + of WireType.Fixed64: + result = uint64(len(values)) * 8 + of WireType.Varint: + for value in values: + result += sizeOfVarint(value) + else: + discard + +proc sizeOfString*(s: string): uint64 = + result = sizeOfVarint(len(s).uint64) + len(s).uint64 + +proc sizeOfDouble*(value: float64): uint64 = + result = 8 + +proc sizeOfFloat*(value: float32): uint64 = + result = 4 + +proc sizeOfInt64*(value: int64): uint64 = + result = sizeOfVarint(value) + +proc sizeOfUInt64*(value: uint64): uint64 = + result = sizeOfVarint(value) + +proc sizeOfInt32*(value: int32): uint64 = + result = sizeOfVarint(value) + +proc sizeOfFixed64*(value: uint64): uint64 = + result = 8 + +proc sizeOfFixed32*(value: uint32): uint64 = + result = 4 + +proc sizeOfBool*(value: bool): uint64 = + result = sizeOfVarint(value) + +proc sizeOfUInt32*(value: uint32): uint64 = + result = sizeOfVarint(value) + +proc sizeOfSFixed32*(value: int32): uint64 = + result = 4 + +proc sizeOfSFixed64*(value: int64): uint64 = + result = 8 + +proc sizeOfSInt32*(value: int32): uint64 = + result = sizeOfVarint(zigzagEncode(value)) + +proc sizeOfSInt64*(value: int64): uint64 = + result = sizeOfVarint(zigzagEncode(value)) + +proc sizeOfEnum*[T](value: T): uint64 = + result = sizeOfUInt32(value.uint32) diff --git a/src/protobuf/types.nim b/src/protobuf/types.nim new file mode 100644 index 0000000..fdd26db --- /dev/null +++ b/src/protobuf/types.nim @@ -0,0 +1,80 @@ +type + fixed32* = distinct uint32 + fixed64* = distinct uint64 + sfixed32* = distinct int32 + sfixed64* = distinct int64 + sint32* = distinct int32 + sint64* = distinct int64 + bytes* = distinct string + + # int32 # varint, no zigzag + # int64 # varint, no zigzag + # uint32 # varint, no zigzag + # uint64 # varint, no zigzag + # fixed32 # 32-bit uint + # fixed64 # 64-bit uint + # sfixed32 # 32-bit int + # sfixed64 # 64-bit int + # sint32 # varint, zigzag + # sint64 # varint, zigzag + # float32 # fixed32 + # float64 # fixed64 + + WireType* {.pure.} = enum + Varint = 0 + Fixed64 = 1 + LengthDelimited = 2 + StartGroup = 3 + EndGroup = 4 + Fixed32 = 5 + + FieldType* {.pure.} = enum + Double = 1 + Float + Int64 + UInt64 + Int32 + Fixed64 + Fixed32 + Bool + String + Group + Message + Bytes + UInt32 + Enum + SFixed32 + SFixed64 + SInt32 + SInt64 + +proc wiretype*(ft: FieldType): WireType = + case ft + of FieldType.Double: result = WireType.Fixed64 + of FieldType.Float: result = WireType.Fixed32 + of FieldType.Int64: result = WireType.Varint + of FieldType.UInt64: result = WireType.Varint + of FieldType.Int32: result = WireType.Varint + of FieldType.Fixed64: result = WireType.Fixed64 + of FieldType.Fixed32: result = WireType.Fixed32 + of FieldType.Bool: result = WireType.Varint + of FieldType.String: result = WireType.LengthDelimited + of FieldType.Group: result = WireType.LengthDelimited # ??? + of FieldType.Message: result = WireType.LengthDelimited + of FieldType.Bytes: result = WireType.LengthDelimited + of FieldType.UInt32: result = WireType.Varint + of FieldType.Enum: result = WireType.Varint + of FieldType.SFixed32: result = WireType.Fixed32 + of FieldType.SFixed64: result = WireType.Fixed64 + of FieldType.SInt32: result = WireType.Varint + of FieldType.SInt64: result = WireType.Varint + +proc isNumeric*(wiretype: WireType): bool = + case wiretype + of WireType.Varint: result = true + of WireType.Fixed64: result = true + of WireType.Fixed32: result = true + else: result = false + +proc isNumeric*(ft: FieldType): bool = + result = isNumeric(wiretype(ft)) |
