mirror of
https://github.com/status-im/nim-contract-abi.git
synced 2025-02-21 06:58:33 +00:00
Custom encoding can use startTuple() and finishTuple()
This commit is contained in:
parent
fd377e59da
commit
01c11eecb0
@ -43,11 +43,10 @@ func index(decoder: var AbiDecoder): var int =
|
||||
func `index=`(decoder: var AbiDecoder, value: int) =
|
||||
decoder.currentTuple.index = value
|
||||
|
||||
func startTuple(decoder: var AbiDecoder): ?!void =
|
||||
func startTuple*(decoder: var AbiDecoder) =
|
||||
decoder.stack.add(Tuple.init(decoder.index))
|
||||
success()
|
||||
|
||||
func finishTuple(decoder: var AbiDecoder) =
|
||||
func finishTuple*(decoder: var AbiDecoder) =
|
||||
doAssert decoder.stack.len > 1, "unable to finish a tuple that hasn't started"
|
||||
let tupl = decoder.stack.pop()
|
||||
decoder.index = tupl.index
|
||||
@ -134,7 +133,7 @@ func decode(decoder: var AbiDecoder, T: type seq[byte]): ?!T =
|
||||
|
||||
func decode[T: tuple](decoder: var AbiDecoder, _: typedesc[T]): ?!T =
|
||||
var tupl: T
|
||||
?decoder.startTuple()
|
||||
decoder.startTuple()
|
||||
for element in tupl.fields:
|
||||
element = ?decoder.read(typeof(element))
|
||||
decoder.finishTuple()
|
||||
@ -143,7 +142,7 @@ func decode[T: tuple](decoder: var AbiDecoder, _: typedesc[T]): ?!T =
|
||||
func decode[T](decoder: var AbiDecoder, _: type seq[T]): ?!seq[T] =
|
||||
var sequence: seq[T]
|
||||
let len = ?decoder.read(uint64)
|
||||
?decoder.startTuple()
|
||||
decoder.startTuple()
|
||||
for _ in 0..<len:
|
||||
sequence.add(?decoder.read(T))
|
||||
decoder.finishTuple()
|
||||
@ -151,7 +150,7 @@ func decode[T](decoder: var AbiDecoder, _: type seq[T]): ?!seq[T] =
|
||||
|
||||
func decode[I,T](decoder: var AbiDecoder, _: type array[I,T]): ?!array[I,T] =
|
||||
var arr: array[I, T]
|
||||
?decoder.startTuple()
|
||||
decoder.startTuple()
|
||||
for i in 0..<arr.len:
|
||||
arr[i] = ?decoder.read(T)
|
||||
decoder.finishTuple()
|
||||
|
@ -57,7 +57,7 @@ func postpone(encoder: var AbiEncoder, bytes: seq[byte]) =
|
||||
func setDynamic(encoder: var AbiEncoder) =
|
||||
encoder.stack[^1].dynamic = true
|
||||
|
||||
func startTuple(encoder: var AbiEncoder) =
|
||||
func startTuple*(encoder: var AbiEncoder) =
|
||||
encoder.stack.add(Tuple())
|
||||
|
||||
func encode(encoder: var AbiEncoder, tupl: Tuple) =
|
||||
@ -67,7 +67,7 @@ func encode(encoder: var AbiEncoder, tupl: Tuple) =
|
||||
else:
|
||||
encoder.append(tupl.finish())
|
||||
|
||||
func finishTuple(encoder: var AbiEncoder) =
|
||||
func finishTuple*(encoder: var AbiEncoder) =
|
||||
encoder.encode(encoder.stack.pop())
|
||||
|
||||
func pad(encoder: var AbiEncoder, len: int, padding=0'u8) =
|
||||
@ -131,25 +131,25 @@ func encode(encoder: var AbiEncoder, tupl: tuple) =
|
||||
encoder.write(element)
|
||||
encoder.finishTuple()
|
||||
|
||||
func finish(encoder: var AbiEncoder): Tuple =
|
||||
doAssert encoder.stack.len == 1, "not all tuples were finished"
|
||||
doAssert encoder.stack[0].bytes.len mod 32 == 0, "encoding invariant broken"
|
||||
encoder.stack[0]
|
||||
|
||||
func write*[T](encoder: var AbiEncoder, value: T) =
|
||||
var writer = AbiEncoder.init()
|
||||
writer.encode(value)
|
||||
encoder.encode(writer.stack[0])
|
||||
|
||||
func finish(encoder: var AbiEncoder): seq[byte] =
|
||||
doAssert encoder.stack.len == 1, "not all tuples were finished"
|
||||
doAssert encoder.stack[0].bytes.len mod 32 == 0, "encoding invariant broken"
|
||||
encoder.stack[0].bytes
|
||||
encoder.encode(writer.finish())
|
||||
|
||||
func encode*[T](_: type AbiEncoder, value: T): seq[byte] =
|
||||
var encoder = AbiEncoder.init()
|
||||
encoder.write(value)
|
||||
encoder.finish()
|
||||
encoder.finish().bytes
|
||||
|
||||
proc isDynamic*(_: type AbiEncoder, T: type): bool {.compileTime.} =
|
||||
var encoder = AbiEncoder.init()
|
||||
encoder.encode(T.default)
|
||||
encoder.stack[^1].dynamic
|
||||
encoder.write(T.default)
|
||||
encoder.finish().dynamic
|
||||
|
||||
proc isStatic*(_: type AbiEncoder, T: type): bool {.compileTime.} =
|
||||
not AbiEncoder.isDynamic(T)
|
||||
|
@ -2,30 +2,79 @@ import std/unittest
|
||||
import pkg/questionable/results
|
||||
import contractabi
|
||||
|
||||
type CustomType = object
|
||||
a: uint16
|
||||
b: string
|
||||
type
|
||||
Custom1 = object
|
||||
a: uint16
|
||||
b: string
|
||||
Custom2 = object
|
||||
a: uint16
|
||||
b: string
|
||||
Custom3 = object
|
||||
a: uint16
|
||||
b: string
|
||||
|
||||
func encode(encoder: var AbiEncoder, custom: CustomType) =
|
||||
func encode(encoder: var AbiEncoder, custom: Custom1) =
|
||||
encoder.write( (custom.a, custom.b) )
|
||||
|
||||
func decode(decoder: var AbiDecoder, T: type CustomType): ?!T =
|
||||
func decode(decoder: var AbiDecoder, T: type Custom1): ?!T =
|
||||
let (a, b) = ?decoder.read( (uint16, string) )
|
||||
success CustomType(a: a, b: b)
|
||||
success Custom1(a: a, b: b)
|
||||
|
||||
func encode(encoder: var AbiEncoder, custom: Custom2) =
|
||||
encoder.startTuple()
|
||||
encoder.write(custom.a)
|
||||
encoder.write(custom.b)
|
||||
encoder.finishTuple()
|
||||
|
||||
func decode(decoder: var AbiDecoder, T: type Custom2): ?!T =
|
||||
var custom: T
|
||||
decoder.startTuple()
|
||||
custom.a = ?decoder.read(uint16)
|
||||
custom.b = ?decoder.read(string)
|
||||
decoder.finishTuple()
|
||||
success custom
|
||||
|
||||
func encode(encoder: var AbiEncoder, custom: Custom3) =
|
||||
encoder.startTuple()
|
||||
encoder.write(custom.a)
|
||||
encoder.write(custom.b)
|
||||
# missing: encoder.finishTuple()
|
||||
|
||||
func decode(decoder: var AbiDecoder, T: type Custom3): ?!T =
|
||||
var custom: T
|
||||
decoder.startTuple()
|
||||
custom.a = ?decoder.read(uint16)
|
||||
custom.b = ?decoder.read(string)
|
||||
# missing: decoder.finishTuple()
|
||||
success custom
|
||||
|
||||
suite "custom types":
|
||||
|
||||
let custom = CustomType(a: 42, b: "ultimate answer")
|
||||
let custom1 = Custom1(a: 42, b: "ultimate answer")
|
||||
let custom2 = Custom2(a: 42, b: "ultimate answer")
|
||||
let custom3 = Custom3(a: 42, b: "ultimate answer")
|
||||
|
||||
test "can be encoded":
|
||||
check AbiEncoder.encode(custom) == AbiEncoder.encode( (custom.a, custom.b) )
|
||||
check:
|
||||
AbiEncoder.encode(custom1) == AbiEncoder.encode( (custom1.a, custom1.b) )
|
||||
|
||||
test "can be decoded":
|
||||
let encoding = AbiEncoder.encode(custom)
|
||||
check AbiDecoder.decode(encoding, CustomType) == success custom
|
||||
let encoding = AbiEncoder.encode(custom1)
|
||||
check AbiDecoder.decode(encoding, Custom1) == success custom1
|
||||
|
||||
test "can be embedded in tuples, arrays and sequences":
|
||||
let embedding = (custom, [custom], @[custom])
|
||||
let embedding = (custom1, [custom1], @[custom1])
|
||||
let encoding = AbiEncoder.encode(embedding)
|
||||
let decoded = AbiDecoder.decode(encoding, typeof(embedding))
|
||||
check !decoded == embedding
|
||||
|
||||
test "can use startTuple() and finishTuple()":
|
||||
let encoding = AbiEncoder.encode(custom2)
|
||||
check AbiDecoder.decode(encoding, Custom2) == success custom2
|
||||
|
||||
test "fail when finishTuple() is missing":
|
||||
expect AssertionDefect:
|
||||
discard AbiEncoder.encode(custom3)
|
||||
let encoding = AbiEncoder.encode( (custom3.a, custom3.b) )
|
||||
expect AssertionDefect:
|
||||
discard AbiDecoder.decode(encoding, Custom3)
|
||||
|
Loading…
x
Reference in New Issue
Block a user