import pkg/stint import pkg/stew/endians2 import pkg/stew/byteutils import pkg/questionable/results import pkg/upraises import ./encoding push: {.upraises:[].} type AbiDecoder* = object bytes: seq[byte] stack: seq[Tuple] last: int Tuple = object start: int index: int Padding = enum padLeft, padRight UInt = SomeUnsignedInt | StUint func read*(decoder: var AbiDecoder, T: type): ?!T func init(_: type Tuple, offset: int): Tuple = Tuple(start: offset, index: offset) func init(_: type AbiDecoder, bytes: seq[byte], offset=0): AbiDecoder = AbiDecoder(bytes: bytes, stack: @[Tuple.init(offset)]) func currentTuple(decoder: var AbiDecoder): var Tuple = decoder.stack[^1] func index(decoder: var AbiDecoder): var int = decoder.currentTuple.index func `index=`(decoder: var AbiDecoder, value: int) = decoder.currentTuple.index = value func updateLast(decoder: var AbiDecoder, index: int) = if index > decoder.last: decoder.last = index func advance(decoder: var AbiDecoder, amount: int): ?!void = decoder.index += amount decoder.updateLast(decoder.index) if decoder.index <= decoder.bytes.len: success() else: failure "reading past end" func skipPadding(decoder: var AbiDecoder, amount: int): ?!void = let index = decoder.index ?decoder.advance(amount) for i in index.. 1, "unable to finish a tuple that hasn't started" let tupl = decoder.stack.pop() decoder.index = tupl.index func decode[T: tuple](decoder: var AbiDecoder, _: typedesc[T]): ?!T = var tupl: T ?decoder.startTuple() for element in tupl.fields: element = ?decoder.read(typeof(element)) decoder.finishTuple() success tupl func finish(decoder: var AbiDecoder): ?!void = doAssert decoder.stack.len == 1, "not all tuples were finished" doAssert decoder.last mod 32 == 0, "encoding invariant broken" if decoder.last != decoder.bytes.len: failure "unread trailing bytes found" else: success() func decode[T](decoder: var AbiDecoder, _: type seq[T]): ?!seq[T] = var sequence: seq[T] let len = ?decoder.read(uint64) ?decoder.startTuple() for _ in 0.. 1: decoder.readTail(T) else: decoder.decode(T)