Add preliminary encode/decode of varints
This commit is contained in:
parent
9d60f49e6f
commit
fe9c5fa1f3
2 changed files with 113 additions and 7 deletions
|
|
@ -1,7 +1,113 @@
|
|||
# This is just an example to get you started. A typical library package
|
||||
# exports the main API in this file. Note that you cannot rename this file
|
||||
# but you can remove it if you wish.
|
||||
import faststreams
|
||||
|
||||
proc add*(x, y: int): int =
|
||||
## Adds two files together.
|
||||
return x + y
|
||||
const
|
||||
MaxMessageSize* = 1'u shl 22
|
||||
|
||||
type
|
||||
ProtoBuffer* = ref object
|
||||
fieldNum: int
|
||||
outstream: OutputStreamVar
|
||||
|
||||
ProtoWireType* = enum
|
||||
## Protobuf's field types enum
|
||||
Varint, Fixed64, Length, StartGroup, EndGroup, Fixed32
|
||||
|
||||
ProtoField* = object
|
||||
## Protobuf's message field representation object
|
||||
index: int
|
||||
case kind: ProtoWireType
|
||||
of Varint:
|
||||
vint*: uint64
|
||||
of Fixed64:
|
||||
vfloat64*: float64
|
||||
of Length:
|
||||
vbuffer*: OutputStreamVar
|
||||
of Fixed32:
|
||||
vfloat32*: float32
|
||||
of StartGroup, EndGroup:
|
||||
discard
|
||||
|
||||
SomeSVarint* = int | int64 | int32 | int16 | int8 | enum
|
||||
SomeUVarint* = uint | uint64 | uint32 | uint16 | uint8 | byte | bool
|
||||
SomeVarint* = SomeSVarint | SomeUVarint
|
||||
|
||||
proc newProtoBuffer*(): ProtoBuffer =
|
||||
ProtoBuffer(outstream: OutputStream.init(), fieldNum: 1)
|
||||
|
||||
# Main interface
|
||||
proc encode*(): ProtoBuffer =
|
||||
discard
|
||||
|
||||
proc decode*[T](source: ProtoBuffer): T =
|
||||
discard
|
||||
|
||||
template wireType(firstByte: byte): ProtoWireType =
|
||||
(firstByte and 0b111).ProtoWireType
|
||||
|
||||
template fieldNumber(firstByte: byte): uint =
|
||||
(firstByte shr 3) and 0b1111
|
||||
|
||||
template protoHeader*(fieldNum: int, wire: ProtoWireType): byte =
|
||||
## Get protobuf's field header integer for ``index`` and ``wire``.
|
||||
((cast[uint](fieldNum) shl 3) or cast[uint](wire)).byte
|
||||
|
||||
proc encodeVarint(stream: OutputStreamVar, fieldNum: int, value: SomeVarint) {.inline.} =
|
||||
let header = protoHeader(fieldNum, Varint)
|
||||
stream.append header
|
||||
|
||||
when value is enum:
|
||||
var value = cast[type(ord(value))](value)
|
||||
elif value is bool:
|
||||
var value = cast[byte](value)
|
||||
else:
|
||||
var value = value
|
||||
|
||||
when type(value) is SomeSVarint:
|
||||
if value < type(value)(0):
|
||||
value = not(value shl type(value)(1))
|
||||
else:
|
||||
value = value shl type(value)(1)
|
||||
|
||||
while value > type(value)(0b0111_1111):
|
||||
stream.append byte((value and 0b0111_1111) or 0b1000_0000)
|
||||
value = value shr 7
|
||||
stream.append byte(value and 0b1111_1111)
|
||||
|
||||
proc encode(protobuf: ProtoBuffer, value: SomeVarint) {.inline.} =
|
||||
protobuf.outstream.encodeVarint(protobuf.fieldNum, value)
|
||||
inc protobuf.fieldNum
|
||||
|
||||
proc decode[T: SomeVarint](bytes: var seq[byte], ty: typedesc[T], offset = 0): tuple[fieldNum: uint, value: T] {.inline.} =
|
||||
# Only up to 128 bits supported by the spec
|
||||
assert (bytes.len - 1) <= 16
|
||||
|
||||
let wireTy = wireType(bytes[offset])
|
||||
if wireTy != Varint:
|
||||
raise newException(Exception, "Not a varint!")
|
||||
|
||||
result.fieldNum = fieldNumber(bytes[offset])
|
||||
result.value = cast[ty](0)
|
||||
var shiftAmount = 0
|
||||
var i = offset + 1
|
||||
while true:
|
||||
result.value += T(bytes[i] and 0b0111_1111) shl shiftAmount
|
||||
shiftAmount += 7
|
||||
if (bytes[i] shr 7) == 0:
|
||||
break
|
||||
i += 1
|
||||
|
||||
when ty is SomeSVarint:
|
||||
if (result.value and T(1)) != T(0):
|
||||
result.value = cast[T](not(result.value shr T(1)))
|
||||
else:
|
||||
result.value = cast[T](result.value shr T(1))
|
||||
|
||||
proc main() =
|
||||
let proto = newProtoBuffer()
|
||||
proto.encode(-1500000)
|
||||
var input: seq[byte] = proto.outstream.getOutput
|
||||
echo input
|
||||
|
||||
echo decode(input, int64)
|
||||
|
||||
main()
|
||||
|
|
@ -11,4 +11,4 @@ skipDirs = @["tests"]
|
|||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 1.0.6"
|
||||
requires "nim >= 1.0.6", "faststreams"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue