Allow specifying a custom serialization procedure for a particular field

This commit is contained in:
Zahary Karadjov 2018-09-17 12:36:52 +03:00 committed by zah
parent 1720345a24
commit 6556821572
4 changed files with 41 additions and 3 deletions

View File

@ -3,7 +3,7 @@
## https://ethereum.github.io/yellowpaper/paper.pdf ## https://ethereum.github.io/yellowpaper/paper.pdf
import import
strutils, parseutils, macros, strutils, parseutils,
rlp/[types, writer, object_serialization], rlp/[types, writer, object_serialization],
rlp/priv/defs rlp/priv/defs
@ -357,6 +357,10 @@ proc readImpl(rlp: var Rlp, T: typedesc[object|tuple],
rlp.position += payloadOffset rlp.position += payloadOffset
template op(field) = template op(field) =
when hasCustomPragma(field, rlpCustomSerialization):
field = rlp.read(type(field),
getCustomPragmaVal(field, rlpCustomSerialization))
else:
field = rlp.read(type(field)) field = rlp.read(type(field))
enumerateRlpFields(result, op) enumerateRlpFields(result, op)

View File

@ -20,3 +20,9 @@ template rlpInline* {.pragma.}
## This can be specified on a record field in order to avoid the ## This can be specified on a record field in order to avoid the
## default behavior of wrapping the record in a RLP list. ## default behavior of wrapping the record in a RLP list.
template rlpCustomSerialization*(T: typedesc) {.pragma.}
## This can be specified on a record field to trigger the use of a
## custom `read` and `append` serialization functions.
## The custom functions will be passed an additional `type` argument
## specefied in the pragma (it is used as an overload tag)

View File

@ -217,7 +217,12 @@ proc appendTupleOrObject(self; data: object|tuple, wrapInList: bool) =
enumerateRlpFields(data, countFields) enumerateRlpFields(data, countFields)
self.startList(fieldsCount) self.startList(fieldsCount)
template op(x) = append(self, x) template op(field) =
when hasCustomPragma(field, rlpCustomSerialization):
append(self, field, getCustomPragmaVal(field, rlpCustomSerialization))
else:
append(self, field)
enumerateRlpFields(data, op) enumerateRlpFields(data, op)
proc appendImpl(self; data: object, wrapInList = wrapObjectsInList) {.inline.} = proc appendImpl(self; data: object, wrapInList = wrapObjectsInList) {.inline.} =

View File

@ -17,6 +17,11 @@ type
b: string b: string
f: Foo f: Foo
CompressedFoo = object
Bar2 = object
f {.rlpCustomSerialization: CompressedFoo}: Foo
rlpFields Foo, rlpFields Foo,
x, y, z x, y, z
@ -25,6 +30,14 @@ rlpFields Transaction,
proc default(T: typedesc): T = discard proc default(T: typedesc): T = discard
proc append*(rlpWriter: var RlpWriter, f: Foo, tag: type CompressedFoo) =
rlpWriter.append(f.x)
rlpWriter.append(f.y.len)
proc read*(rlp: var Rlp, T: type Foo, tag: type CompressedFoo): Foo =
result.x = rlp.read(uint64)
result.y = newString(rlp.read(int))
test "encoding and decoding an object": test "encoding and decoding an object":
var originalBar = Bar(b: "abracadabra", var originalBar = Bar(b: "abracadabra",
f: Foo(x: 5'u64, y: "hocus pocus", z: @[100, 200, 300])) f: Foo(x: 5'u64, y: "hocus pocus", z: @[100, 200, 300]))
@ -47,3 +60,13 @@ test "encoding and decoding an object":
t2.receiver == "Bob" t2.receiver == "Bob"
t2.amount == 1000 t2.amount == 1000
test "custom field serialization":
var origVal = Bar2(f: Foo(x: 10'u64, y: "y", z: @[]))
var bytes = encode(origVal)
var r = rlpFromBytes(bytes)
var restored = r.read(Bar2)
check:
origVal.f.x == restored.f.x
origVal.f.y.len == restored.f.y.len