mirror of
https://github.com/status-im/nim-rlp.git
synced 2025-01-24 13:31:23 +00:00
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
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,6 +2,7 @@
|
|||||||
*
|
*
|
||||||
!*.*
|
!*.*
|
||||||
!*/
|
!*/
|
||||||
|
*.exe
|
||||||
|
|
||||||
nimcache/
|
nimcache/
|
||||||
|
|
||||||
|
40
rlp.nim
40
rlp.nim
@ -267,19 +267,19 @@ proc listLen*(self: Rlp): int =
|
|||||||
for elem in rlp:
|
for elem in rlp:
|
||||||
inc result
|
inc result
|
||||||
|
|
||||||
proc read*(rlp: var Rlp, T: type string): string =
|
proc readImpl(rlp: var Rlp, T: type string): string =
|
||||||
result = rlp.toString
|
result = rlp.toString
|
||||||
rlp.skipElem
|
rlp.skipElem
|
||||||
|
|
||||||
proc read*(rlp: var Rlp, T: type Integer): Integer =
|
proc readImpl(rlp: var Rlp, T: type Integer): Integer =
|
||||||
result = rlp.toInt(T)
|
result = rlp.toInt(T)
|
||||||
rlp.skipElem
|
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))
|
result = type(result)(rlp.toInt(int))
|
||||||
rlp.skipElem
|
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
|
mixin read
|
||||||
|
|
||||||
when E is (byte or char):
|
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)
|
result[i] = rlp.read(E)
|
||||||
inc i
|
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
|
mixin read
|
||||||
|
|
||||||
when E is (byte or char):
|
when E is (byte or char):
|
||||||
@ -323,10 +323,10 @@ proc read*[E](rlp: var Rlp, T: type seq[E]): T =
|
|||||||
for elem in rlp:
|
for elem in rlp:
|
||||||
result.add rlp.read(E)
|
result.add rlp.read(E)
|
||||||
|
|
||||||
proc read*[E](rlp: var Rlp, T: type openarray[E]): seq[E] =
|
proc readImpl[E](rlp: var Rlp, T: type openarray[E]): seq[E] =
|
||||||
result = read(rlp, seq[E])
|
result = readImpl(rlp, seq[E])
|
||||||
|
|
||||||
proc read*(rlp: var Rlp, T: typedesc[object|tuple],
|
proc readImpl(rlp: var Rlp, T: typedesc[object|tuple],
|
||||||
wrappedInList = wrapObjectsInList): T =
|
wrappedInList = wrapObjectsInList): T =
|
||||||
mixin enumerateRlpFields, read
|
mixin enumerateRlpFields, read
|
||||||
|
|
||||||
@ -356,14 +356,19 @@ proc toNodes*(self: var Rlp): RlpNode =
|
|||||||
result.bytes = toBytes()
|
result.bytes = toBytes()
|
||||||
position = currentElemEnd()
|
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 =
|
proc decode*(bytes: openarray[byte]): RlpNode =
|
||||||
var
|
var
|
||||||
bytesCopy = @bytes
|
bytesCopy = @bytes
|
||||||
rlp = rlpFromBytes(bytesCopy.toRange())
|
rlp = rlpFromBytes(bytesCopy.toRange())
|
||||||
return rlp.toNodes
|
return rlp.toNodes
|
||||||
|
|
||||||
|
|
||||||
template decode*(bytes: BytesRange, T: typedesc): untyped =
|
template decode*(bytes: BytesRange, T: typedesc): untyped =
|
||||||
|
mixin read
|
||||||
var rlp = rlpFromBytes bytes
|
var rlp = rlpFromBytes bytes
|
||||||
rlp.read(T)
|
rlp.read(T)
|
||||||
|
|
||||||
@ -374,6 +379,13 @@ template decode*(bytes: openarray[byte], T: typedesc): T =
|
|||||||
proc append*(writer: var RlpWriter; rlp: Rlp) =
|
proc append*(writer: var RlpWriter; rlp: Rlp) =
|
||||||
append(writer, rlp.rawData)
|
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) =
|
proc inspectAux(self: var Rlp, depth: int, output: var string) =
|
||||||
if not hasData():
|
if not hasData():
|
||||||
return
|
return
|
||||||
@ -388,9 +400,17 @@ proc inspectAux(self: var Rlp, depth: int, output: var string) =
|
|||||||
output.add "byte "
|
output.add "byte "
|
||||||
output.add $bytes[position]
|
output.add $bytes[position]
|
||||||
elif self.isBlob:
|
elif self.isBlob:
|
||||||
|
let str = self.toString
|
||||||
|
if str.isPrintable:
|
||||||
output.add '"'
|
output.add '"'
|
||||||
output.add self.toString
|
output.add str
|
||||||
output.add '"'
|
output.add '"'
|
||||||
|
else:
|
||||||
|
output.add "blob(" & $str.len & ") ["
|
||||||
|
for c in str:
|
||||||
|
output.add $ord(c)
|
||||||
|
output.add ","
|
||||||
|
output[^1] = ']'
|
||||||
else:
|
else:
|
||||||
output.add "{\n"
|
output.add "{\n"
|
||||||
for subitem in self:
|
for subitem in self:
|
||||||
|
@ -15,3 +15,8 @@ macro rlpFields*(T: typedesc, fields: varargs[untyped]): untyped =
|
|||||||
result = quote do:
|
result = quote do:
|
||||||
template enumerateRlpFields*(`ins`: `T`, `op`: untyped) {.inject.} =
|
template enumerateRlpFields*(`ins`: `T`, `op`: untyped) {.inject.} =
|
||||||
`body`
|
`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:
|
else:
|
||||||
pendingLists.add((listSize, output.len))
|
pendingLists.add((listSize, output.len))
|
||||||
|
|
||||||
template appendImpl(self; data, startMarker) =
|
template appendBlob(self; data, startMarker) =
|
||||||
mixin baseAddr
|
mixin baseAddr
|
||||||
|
|
||||||
if data.len == 1 and byte(data[0]) < BLOB_START_MARKER:
|
if data.len == 1 and byte(data[0]) < BLOB_START_MARKER:
|
||||||
@ -142,22 +142,22 @@ template appendImpl(self; data, startMarker) =
|
|||||||
|
|
||||||
maybeClosePendingLists()
|
maybeClosePendingLists()
|
||||||
|
|
||||||
proc append*(self; data: string) =
|
proc appendImpl(self; data: string) =
|
||||||
appendImpl(self, data, BLOB_START_MARKER)
|
appendBlob(self, data, BLOB_START_MARKER)
|
||||||
|
|
||||||
proc appendBlob(self; data: openarray[byte]) =
|
proc appendBlob(self; data: openarray[byte]) =
|
||||||
appendImpl(self, data, BLOB_START_MARKER)
|
appendBlob(self, data, BLOB_START_MARKER)
|
||||||
|
|
||||||
proc appendBlob(self; data: openarray[char]) =
|
proc appendBlob(self; data: openarray[char]) =
|
||||||
appendImpl(self, data, BLOB_START_MARKER)
|
appendBlob(self, data, BLOB_START_MARKER)
|
||||||
|
|
||||||
proc appendBytesRange(self; data: BytesRange) =
|
proc appendBytesRange(self; data: BytesRange) =
|
||||||
appendImpl(self, data, BLOB_START_MARKER)
|
appendBlob(self, data, BLOB_START_MARKER)
|
||||||
|
|
||||||
proc append*(self; data: MemRange) =
|
proc appendImpl(self; data: MemRange) =
|
||||||
appendImpl(self, data, BLOB_START_MARKER)
|
appendBlob(self, data, BLOB_START_MARKER)
|
||||||
|
|
||||||
proc append*(self; i: Integer) =
|
proc appendImpl(self; i: Integer) =
|
||||||
type IntType = type(i)
|
type IntType = type(i)
|
||||||
|
|
||||||
if i == IntType(0):
|
if i == IntType(0):
|
||||||
@ -171,10 +171,10 @@ proc append*(self; i: Integer) =
|
|||||||
|
|
||||||
self.maybeClosePendingLists()
|
self.maybeClosePendingLists()
|
||||||
|
|
||||||
template append*(self; e: enum) =
|
template appendImpl(self; e: enum) =
|
||||||
append(self, int(e))
|
appendImpl(self, int(e))
|
||||||
|
|
||||||
proc append*[T](self; listOrBlob: openarray[T]) =
|
proc appendImpl[T](self; listOrBlob: openarray[T]) =
|
||||||
mixin append
|
mixin append
|
||||||
|
|
||||||
# TODO: This append proc should be overloaded by `openarray[byte]` after
|
# 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)
|
template op(x) = append(self, x)
|
||||||
enumerateRlpFields(data, op)
|
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
|
# TODO: This append proc should be overloaded by `BytesRange` after
|
||||||
# nim bug #7416 is fixed.
|
# nim bug #7416 is fixed.
|
||||||
when data is BytesRange:
|
when data is BytesRange:
|
||||||
@ -208,9 +208,13 @@ proc append*(self; data: object, wrapInList = wrapObjectsInList) {.inline.} =
|
|||||||
else:
|
else:
|
||||||
self.appendTupleOrObject(data, wrapInList)
|
self.appendTupleOrObject(data, wrapInList)
|
||||||
|
|
||||||
proc append*(self; data: tuple, wrapInList = wrapObjectsInList) {.inline.} =
|
proc appendImpl(self; data: tuple, wrapInList = wrapObjectsInList) {.inline.} =
|
||||||
self.appendTupleOrObject(data, wrapInList)
|
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 =
|
proc initRlpList*(listSize: int): RlpWriter =
|
||||||
result = initRlpWriter()
|
result = initRlpWriter()
|
||||||
startList(result, listSize)
|
startList(result, listSize)
|
||||||
@ -222,6 +226,7 @@ proc finish*(self): BytesRange =
|
|||||||
result = output.toRange()
|
result = output.toRange()
|
||||||
|
|
||||||
proc encode*[T](v: T): BytesRange =
|
proc encode*[T](v: T): BytesRange =
|
||||||
|
mixin append
|
||||||
var writer = initRlpWriter()
|
var writer = initRlpWriter()
|
||||||
writer.append(v)
|
writer.append(v)
|
||||||
return writer.finish
|
return writer.finish
|
||||||
@ -231,10 +236,11 @@ macro encodeList*(args: varargs[untyped]): BytesRange =
|
|||||||
listLen = args.len
|
listLen = args.len
|
||||||
writer = genSym(nskVar, "rlpWriter")
|
writer = genSym(nskVar, "rlpWriter")
|
||||||
body = newStmtList()
|
body = newStmtList()
|
||||||
|
append = bindSym("append", brForceOpen)
|
||||||
|
|
||||||
for arg in args:
|
for arg in args:
|
||||||
body.add quote do:
|
body.add quote do:
|
||||||
append(`writer`, `arg`)
|
`append`(`writer`, `arg`)
|
||||||
|
|
||||||
result = quote do:
|
result = quote do:
|
||||||
var `writer` = initRlpList(`listLen`)
|
var `writer` = initRlpList(`listLen`)
|
||||||
@ -244,6 +250,7 @@ macro encodeList*(args: varargs[untyped]): BytesRange =
|
|||||||
when false:
|
when false:
|
||||||
# XXX: Currently fails with a malformed AST error on the args.len expression
|
# XXX: Currently fails with a malformed AST error on the args.len expression
|
||||||
template encodeList*(args: varargs[untyped]): BytesRange =
|
template encodeList*(args: varargs[untyped]): BytesRange =
|
||||||
|
mixin append
|
||||||
var writer = initRlpList(args.len)
|
var writer = initRlpList(args.len)
|
||||||
for arg in args:
|
for arg in args:
|
||||||
writer.append(arg)
|
writer.append(arg)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user