mirror of https://github.com/status-im/nim-rlp.git
Make 'read' and 'append' easier to override for user-defined types
The 'rlp.inspect' output have been improved.
This commit is contained in:
parent
078aa161dd
commit
790aef0a9d
|
@ -2,6 +2,7 @@
|
|||
*
|
||||
!*.*
|
||||
!*/
|
||||
*.exe
|
||||
|
||||
nimcache/
|
||||
|
||||
|
|
46
rlp.nim
46
rlp.nim
|
@ -267,19 +267,19 @@ proc listLen*(self: Rlp): int =
|
|||
for elem in rlp:
|
||||
inc result
|
||||
|
||||
proc read*(rlp: var Rlp, T: type string): string =
|
||||
proc readImpl(rlp: var Rlp, T: type string): string =
|
||||
result = rlp.toString
|
||||
rlp.skipElem
|
||||
|
||||
proc read*(rlp: var Rlp, T: type Integer): Integer =
|
||||
proc readImpl(rlp: var Rlp, T: type Integer): Integer =
|
||||
result = rlp.toInt(T)
|
||||
rlp.skipElem
|
||||
|
||||
proc read*(rlp: var Rlp, T: typedesc[enum]): T =
|
||||
proc readImpl(rlp: var Rlp, T: typedesc[enum]): T =
|
||||
result = type(result)(rlp.toInt(int))
|
||||
rlp.skipElem
|
||||
|
||||
proc read*[R, E](rlp: var Rlp, T: type array[R, E]): T =
|
||||
proc readImpl[R, E](rlp: var Rlp, T: type array[R, E]): T =
|
||||
mixin read
|
||||
|
||||
when E is (byte or char):
|
||||
|
@ -306,7 +306,7 @@ proc read*[R, E](rlp: var Rlp, T: type array[R, E]): T =
|
|||
result[i] = rlp.read(E)
|
||||
inc i
|
||||
|
||||
proc read*[E](rlp: var Rlp, T: type seq[E]): T =
|
||||
proc readImpl[E](rlp: var Rlp, T: type seq[E]): T =
|
||||
mixin read
|
||||
|
||||
when E is (byte or char):
|
||||
|
@ -323,11 +323,11 @@ proc read*[E](rlp: var Rlp, T: type seq[E]): T =
|
|||
for elem in rlp:
|
||||
result.add rlp.read(E)
|
||||
|
||||
proc read*[E](rlp: var Rlp, T: type openarray[E]): seq[E] =
|
||||
result = read(rlp, seq[E])
|
||||
proc readImpl[E](rlp: var Rlp, T: type openarray[E]): seq[E] =
|
||||
result = readImpl(rlp, seq[E])
|
||||
|
||||
proc read*(rlp: var Rlp, T: typedesc[object|tuple],
|
||||
wrappedInList = wrapObjectsInList): T =
|
||||
proc readImpl(rlp: var Rlp, T: typedesc[object|tuple],
|
||||
wrappedInList = wrapObjectsInList): T =
|
||||
mixin enumerateRlpFields, read
|
||||
|
||||
if wrappedInList:
|
||||
|
@ -356,14 +356,19 @@ proc toNodes*(self: var Rlp): RlpNode =
|
|||
result.bytes = toBytes()
|
||||
position = currentElemEnd()
|
||||
|
||||
# We define a single `read` template with a pretty low specifity
|
||||
# score in order to facilitate easier overloading with user types:
|
||||
template read*(rlp: var Rlp, T: typedesc): auto =
|
||||
readImpl(rlp, T)
|
||||
|
||||
proc decode*(bytes: openarray[byte]): RlpNode =
|
||||
var
|
||||
bytesCopy = @bytes
|
||||
rlp = rlpFromBytes(bytesCopy.toRange())
|
||||
return rlp.toNodes
|
||||
|
||||
|
||||
template decode*(bytes: BytesRange, T: typedesc): untyped =
|
||||
mixin read
|
||||
var rlp = rlpFromBytes bytes
|
||||
rlp.read(T)
|
||||
|
||||
|
@ -374,6 +379,13 @@ template decode*(bytes: openarray[byte], T: typedesc): T =
|
|||
proc append*(writer: var RlpWriter; rlp: Rlp) =
|
||||
append(writer, rlp.rawData)
|
||||
|
||||
proc isPrintable(s: string): bool =
|
||||
for c in s:
|
||||
if ord(c) < 32 or ord(c) >= 128:
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
proc inspectAux(self: var Rlp, depth: int, output: var string) =
|
||||
if not hasData():
|
||||
return
|
||||
|
@ -388,9 +400,17 @@ proc inspectAux(self: var Rlp, depth: int, output: var string) =
|
|||
output.add "byte "
|
||||
output.add $bytes[position]
|
||||
elif self.isBlob:
|
||||
output.add '"'
|
||||
output.add self.toString
|
||||
output.add '"'
|
||||
let str = self.toString
|
||||
if str.isPrintable:
|
||||
output.add '"'
|
||||
output.add str
|
||||
output.add '"'
|
||||
else:
|
||||
output.add "blob(" & $str.len & ") ["
|
||||
for c in str:
|
||||
output.add $ord(c)
|
||||
output.add ","
|
||||
output[^1] = ']'
|
||||
else:
|
||||
output.add "{\n"
|
||||
for subitem in self:
|
||||
|
|
|
@ -15,3 +15,8 @@ macro rlpFields*(T: typedesc, fields: varargs[untyped]): untyped =
|
|||
result = quote do:
|
||||
template enumerateRlpFields*(`ins`: `T`, `op`: untyped) {.inject.} =
|
||||
`body`
|
||||
|
||||
template rlpInline* {.pragma.}
|
||||
## This can be specified on a record field in order to avoid the
|
||||
## default behavior of wrapping the record in a RLP list.
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ proc startList*(self; listSize: int) =
|
|||
else:
|
||||
pendingLists.add((listSize, output.len))
|
||||
|
||||
template appendImpl(self; data, startMarker) =
|
||||
template appendBlob(self; data, startMarker) =
|
||||
mixin baseAddr
|
||||
|
||||
if data.len == 1 and byte(data[0]) < BLOB_START_MARKER:
|
||||
|
@ -142,22 +142,22 @@ template appendImpl(self; data, startMarker) =
|
|||
|
||||
maybeClosePendingLists()
|
||||
|
||||
proc append*(self; data: string) =
|
||||
appendImpl(self, data, BLOB_START_MARKER)
|
||||
proc appendImpl(self; data: string) =
|
||||
appendBlob(self, data, BLOB_START_MARKER)
|
||||
|
||||
proc appendBlob(self; data: openarray[byte]) =
|
||||
appendImpl(self, data, BLOB_START_MARKER)
|
||||
appendBlob(self, data, BLOB_START_MARKER)
|
||||
|
||||
proc appendBlob(self; data: openarray[char]) =
|
||||
appendImpl(self, data, BLOB_START_MARKER)
|
||||
appendBlob(self, data, BLOB_START_MARKER)
|
||||
|
||||
proc appendBytesRange(self; data: BytesRange) =
|
||||
appendImpl(self, data, BLOB_START_MARKER)
|
||||
appendBlob(self, data, BLOB_START_MARKER)
|
||||
|
||||
proc append*(self; data: MemRange) =
|
||||
appendImpl(self, data, BLOB_START_MARKER)
|
||||
proc appendImpl(self; data: MemRange) =
|
||||
appendBlob(self, data, BLOB_START_MARKER)
|
||||
|
||||
proc append*(self; i: Integer) =
|
||||
proc appendImpl(self; i: Integer) =
|
||||
type IntType = type(i)
|
||||
|
||||
if i == IntType(0):
|
||||
|
@ -171,10 +171,10 @@ proc append*(self; i: Integer) =
|
|||
|
||||
self.maybeClosePendingLists()
|
||||
|
||||
template append*(self; e: enum) =
|
||||
append(self, int(e))
|
||||
template appendImpl(self; e: enum) =
|
||||
appendImpl(self, int(e))
|
||||
|
||||
proc append*[T](self; listOrBlob: openarray[T]) =
|
||||
proc appendImpl[T](self; listOrBlob: openarray[T]) =
|
||||
mixin append
|
||||
|
||||
# TODO: This append proc should be overloaded by `openarray[byte]` after
|
||||
|
@ -200,7 +200,7 @@ proc appendTupleOrObject(self; data: object|tuple, wrapInList: bool) =
|
|||
template op(x) = append(self, x)
|
||||
enumerateRlpFields(data, op)
|
||||
|
||||
proc append*(self; data: object, wrapInList = wrapObjectsInList) {.inline.} =
|
||||
proc appendImpl(self; data: object, wrapInList = wrapObjectsInList) {.inline.} =
|
||||
# TODO: This append proc should be overloaded by `BytesRange` after
|
||||
# nim bug #7416 is fixed.
|
||||
when data is BytesRange:
|
||||
|
@ -208,9 +208,13 @@ proc append*(self; data: object, wrapInList = wrapObjectsInList) {.inline.} =
|
|||
else:
|
||||
self.appendTupleOrObject(data, wrapInList)
|
||||
|
||||
proc append*(self; data: tuple, wrapInList = wrapObjectsInList) {.inline.} =
|
||||
proc appendImpl(self; data: tuple, wrapInList = wrapObjectsInList) {.inline.} =
|
||||
self.appendTupleOrObject(data, wrapInList)
|
||||
|
||||
# We define a single `append` template with a pretty low specifity
|
||||
# score in order to facilitate easier overloading with user types:
|
||||
template append*[T](self; data: T) = appendImpl(self, data)
|
||||
|
||||
proc initRlpList*(listSize: int): RlpWriter =
|
||||
result = initRlpWriter()
|
||||
startList(result, listSize)
|
||||
|
@ -222,6 +226,7 @@ proc finish*(self): BytesRange =
|
|||
result = output.toRange()
|
||||
|
||||
proc encode*[T](v: T): BytesRange =
|
||||
mixin append
|
||||
var writer = initRlpWriter()
|
||||
writer.append(v)
|
||||
return writer.finish
|
||||
|
@ -231,10 +236,11 @@ macro encodeList*(args: varargs[untyped]): BytesRange =
|
|||
listLen = args.len
|
||||
writer = genSym(nskVar, "rlpWriter")
|
||||
body = newStmtList()
|
||||
append = bindSym("append", brForceOpen)
|
||||
|
||||
for arg in args:
|
||||
body.add quote do:
|
||||
append(`writer`, `arg`)
|
||||
`append`(`writer`, `arg`)
|
||||
|
||||
result = quote do:
|
||||
var `writer` = initRlpList(`listLen`)
|
||||
|
@ -244,6 +250,7 @@ macro encodeList*(args: varargs[untyped]): BytesRange =
|
|||
when false:
|
||||
# XXX: Currently fails with a malformed AST error on the args.len expression
|
||||
template encodeList*(args: varargs[untyped]): BytesRange =
|
||||
mixin append
|
||||
var writer = initRlpList(args.len)
|
||||
for arg in args:
|
||||
writer.append(arg)
|
||||
|
|
Loading…
Reference in New Issue