mirror of
https://github.com/status-im/nim-contract-abi.git
synced 2025-02-22 15:38:11 +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) =
|
func `index=`(decoder: var AbiDecoder, value: int) =
|
||||||
decoder.currentTuple.index = value
|
decoder.currentTuple.index = value
|
||||||
|
|
||||||
func startTuple(decoder: var AbiDecoder): ?!void =
|
func startTuple*(decoder: var AbiDecoder) =
|
||||||
decoder.stack.add(Tuple.init(decoder.index))
|
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"
|
doAssert decoder.stack.len > 1, "unable to finish a tuple that hasn't started"
|
||||||
let tupl = decoder.stack.pop()
|
let tupl = decoder.stack.pop()
|
||||||
decoder.index = tupl.index
|
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 =
|
func decode[T: tuple](decoder: var AbiDecoder, _: typedesc[T]): ?!T =
|
||||||
var tupl: T
|
var tupl: T
|
||||||
?decoder.startTuple()
|
decoder.startTuple()
|
||||||
for element in tupl.fields:
|
for element in tupl.fields:
|
||||||
element = ?decoder.read(typeof(element))
|
element = ?decoder.read(typeof(element))
|
||||||
decoder.finishTuple()
|
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] =
|
func decode[T](decoder: var AbiDecoder, _: type seq[T]): ?!seq[T] =
|
||||||
var sequence: seq[T]
|
var sequence: seq[T]
|
||||||
let len = ?decoder.read(uint64)
|
let len = ?decoder.read(uint64)
|
||||||
?decoder.startTuple()
|
decoder.startTuple()
|
||||||
for _ in 0..<len:
|
for _ in 0..<len:
|
||||||
sequence.add(?decoder.read(T))
|
sequence.add(?decoder.read(T))
|
||||||
decoder.finishTuple()
|
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] =
|
func decode[I,T](decoder: var AbiDecoder, _: type array[I,T]): ?!array[I,T] =
|
||||||
var arr: array[I, T]
|
var arr: array[I, T]
|
||||||
?decoder.startTuple()
|
decoder.startTuple()
|
||||||
for i in 0..<arr.len:
|
for i in 0..<arr.len:
|
||||||
arr[i] = ?decoder.read(T)
|
arr[i] = ?decoder.read(T)
|
||||||
decoder.finishTuple()
|
decoder.finishTuple()
|
||||||
|
@ -57,7 +57,7 @@ func postpone(encoder: var AbiEncoder, bytes: seq[byte]) =
|
|||||||
func setDynamic(encoder: var AbiEncoder) =
|
func setDynamic(encoder: var AbiEncoder) =
|
||||||
encoder.stack[^1].dynamic = true
|
encoder.stack[^1].dynamic = true
|
||||||
|
|
||||||
func startTuple(encoder: var AbiEncoder) =
|
func startTuple*(encoder: var AbiEncoder) =
|
||||||
encoder.stack.add(Tuple())
|
encoder.stack.add(Tuple())
|
||||||
|
|
||||||
func encode(encoder: var AbiEncoder, tupl: Tuple) =
|
func encode(encoder: var AbiEncoder, tupl: Tuple) =
|
||||||
@ -67,7 +67,7 @@ func encode(encoder: var AbiEncoder, tupl: Tuple) =
|
|||||||
else:
|
else:
|
||||||
encoder.append(tupl.finish())
|
encoder.append(tupl.finish())
|
||||||
|
|
||||||
func finishTuple(encoder: var AbiEncoder) =
|
func finishTuple*(encoder: var AbiEncoder) =
|
||||||
encoder.encode(encoder.stack.pop())
|
encoder.encode(encoder.stack.pop())
|
||||||
|
|
||||||
func pad(encoder: var AbiEncoder, len: int, padding=0'u8) =
|
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.write(element)
|
||||||
encoder.finishTuple()
|
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) =
|
func write*[T](encoder: var AbiEncoder, value: T) =
|
||||||
var writer = AbiEncoder.init()
|
var writer = AbiEncoder.init()
|
||||||
writer.encode(value)
|
writer.encode(value)
|
||||||
encoder.encode(writer.stack[0])
|
encoder.encode(writer.finish())
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
func encode*[T](_: type AbiEncoder, value: T): seq[byte] =
|
func encode*[T](_: type AbiEncoder, value: T): seq[byte] =
|
||||||
var encoder = AbiEncoder.init()
|
var encoder = AbiEncoder.init()
|
||||||
encoder.write(value)
|
encoder.write(value)
|
||||||
encoder.finish()
|
encoder.finish().bytes
|
||||||
|
|
||||||
proc isDynamic*(_: type AbiEncoder, T: type): bool {.compileTime.} =
|
proc isDynamic*(_: type AbiEncoder, T: type): bool {.compileTime.} =
|
||||||
var encoder = AbiEncoder.init()
|
var encoder = AbiEncoder.init()
|
||||||
encoder.encode(T.default)
|
encoder.write(T.default)
|
||||||
encoder.stack[^1].dynamic
|
encoder.finish().dynamic
|
||||||
|
|
||||||
proc isStatic*(_: type AbiEncoder, T: type): bool {.compileTime.} =
|
proc isStatic*(_: type AbiEncoder, T: type): bool {.compileTime.} =
|
||||||
not AbiEncoder.isDynamic(T)
|
not AbiEncoder.isDynamic(T)
|
||||||
|
@ -2,30 +2,79 @@ import std/unittest
|
|||||||
import pkg/questionable/results
|
import pkg/questionable/results
|
||||||
import contractabi
|
import contractabi
|
||||||
|
|
||||||
type CustomType = object
|
type
|
||||||
a: uint16
|
Custom1 = object
|
||||||
b: string
|
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) )
|
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) )
|
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":
|
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":
|
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":
|
test "can be decoded":
|
||||||
let encoding = AbiEncoder.encode(custom)
|
let encoding = AbiEncoder.encode(custom1)
|
||||||
check AbiDecoder.decode(encoding, CustomType) == success custom
|
check AbiDecoder.decode(encoding, Custom1) == success custom1
|
||||||
|
|
||||||
test "can be embedded in tuples, arrays and sequences":
|
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 encoding = AbiEncoder.encode(embedding)
|
||||||
let decoded = AbiDecoder.decode(encoding, typeof(embedding))
|
let decoded = AbiDecoder.decode(encoding, typeof(embedding))
|
||||||
check !decoded == 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