First steps to get Result[T].
This commit is contained in:
parent
dfd824bd03
commit
c9b5af87a0
|
@ -9,13 +9,15 @@
|
|||
|
||||
## This module implements BASE58 encoding and decoding procedures.
|
||||
## This module supports two variants of BASE58 encoding (Bitcoin and Flickr).
|
||||
import result
|
||||
import errors as e
|
||||
|
||||
type
|
||||
Base58Status* {.pure.} = enum
|
||||
Error,
|
||||
Success,
|
||||
Incorrect,
|
||||
Overrun
|
||||
# Base58Status* {.pure.} = enum
|
||||
# Error,
|
||||
# Success,
|
||||
# Incorrect,
|
||||
# Overrun
|
||||
|
||||
Base58Alphabet* = object
|
||||
decode*: array[128, int8]
|
||||
|
@ -59,13 +61,10 @@ proc decodedLength*(btype: typedesc[Base58C], length: int): int =
|
|||
result = length + 4
|
||||
|
||||
proc encode*(btype: typedesc[Base58C], inbytes: openarray[byte],
|
||||
outstr: var openarray[char], outlen: var int): Base58Status =
|
||||
outstr: var openarray[char]): Result[int, e.Error] =
|
||||
## Encode array of bytes ``inbytes`` using BASE58 encoding and store
|
||||
## result to ``outstr``. On success ``Base58Status.Success`` will be returned
|
||||
## and ``outlen`` will be set to number of characters stored inside of
|
||||
## ``outstr``. If length of ``outstr`` is not enough then
|
||||
## ``Base58Status.Overrun`` will be returned and ``outlen`` will be set to
|
||||
## number of characters required.
|
||||
## result to ``outstr``. On success procedure returns number of characters
|
||||
## stored inside ``outstr``.
|
||||
when btype is BTCBase58:
|
||||
const alphabet = BTCAlphabet
|
||||
elif btype is FLCBase58:
|
||||
|
@ -99,9 +98,8 @@ proc encode*(btype: typedesc[Base58C], inbytes: openarray[byte],
|
|||
inc(j)
|
||||
|
||||
let needed = zcount + size - j
|
||||
outlen = needed
|
||||
if len(outstr) < needed:
|
||||
result = Base58Status.Overrun
|
||||
result.err(e.OverrunError)
|
||||
else:
|
||||
for k in 0..<zcount:
|
||||
outstr[k] = cast[char](alphabet.encode[0])
|
||||
|
@ -110,48 +108,109 @@ proc encode*(btype: typedesc[Base58C], inbytes: openarray[byte],
|
|||
outstr[i] = cast[char](alphabet.encode[buffer[j]])
|
||||
inc(j)
|
||||
inc(i)
|
||||
result = Base58Status.Success
|
||||
result.ok(needed)
|
||||
|
||||
# proc encode*(btype: typedesc[Base58C], inbytes: openarray[byte],
|
||||
# outstr: var openarray[char], outlen: var int): Base58Status =
|
||||
# ## Encode array of bytes ``inbytes`` using BASE58 encoding and store
|
||||
# ## result to ``outstr``. On success ``Base58Status.Success`` will be returned
|
||||
# ## and ``outlen`` will be set to number of characters stored inside of
|
||||
# ## ``outstr``. If length of ``outstr`` is not enough then
|
||||
# ## ``Base58Status.Overrun`` will be returned and ``outlen`` will be set to
|
||||
# ## number of characters required.
|
||||
# when btype is BTCBase58:
|
||||
# const alphabet = BTCAlphabet
|
||||
# elif btype is FLCBase58:
|
||||
# const alphabet = FlickrAlphabet
|
||||
|
||||
# let binsz = len(inbytes)
|
||||
# var zcount = 0
|
||||
|
||||
# while zcount < binsz and inbytes[zcount] == 0x00'u8:
|
||||
# inc(zcount)
|
||||
|
||||
# let size = ((binsz - zcount) * 138) div 100 + 1
|
||||
# var buffer = newSeq[uint8](size)
|
||||
|
||||
# var hi = size - 1
|
||||
# var i = zcount
|
||||
# var j = size - 1
|
||||
# while i < binsz:
|
||||
# var carry = uint32(inbytes[i])
|
||||
# j = size - 1
|
||||
# while (j > hi) or (carry != 0'u32):
|
||||
# carry = carry + uint32(256'u32 * buffer[j])
|
||||
# buffer[j] = cast[byte](carry mod 58)
|
||||
# carry = carry div 58
|
||||
# dec(j)
|
||||
# hi = j
|
||||
# inc(i)
|
||||
|
||||
# j = 0
|
||||
# while (j < size) and (buffer[j] == 0x00'u8):
|
||||
# inc(j)
|
||||
|
||||
# let needed = zcount + size - j
|
||||
# outlen = needed
|
||||
# if len(outstr) < needed:
|
||||
# result = Base58Status.Overrun
|
||||
# else:
|
||||
# for k in 0..<zcount:
|
||||
# outstr[k] = cast[char](alphabet.encode[0])
|
||||
# i = zcount
|
||||
# while j < size:
|
||||
# outstr[i] = cast[char](alphabet.encode[buffer[j]])
|
||||
# inc(j)
|
||||
# inc(i)
|
||||
# result = Base58Status.Success
|
||||
|
||||
# proc encode*(btype: typedesc[Base58C],
|
||||
# inbytes: openarray[byte]): string {.inline.} =
|
||||
# ## Encode array of bytes ``inbytes`` using BASE58 encoding and return
|
||||
# ## encoded string.
|
||||
# var size = (len(inbytes) * 138) div 100 + 1
|
||||
# result = newString(size)
|
||||
# if btype.encode(inbytes, result.toOpenArray(0, size - 1),
|
||||
# size) == Base58Status.Success:
|
||||
# result.setLen(size)
|
||||
# else:
|
||||
# result = ""
|
||||
|
||||
proc encode*(btype: typedesc[Base58C],
|
||||
inbytes: openarray[byte]): string {.inline.} =
|
||||
inbytes: openarray[byte]): Result[string, e.Error] {.inline.} =
|
||||
## Encode array of bytes ``inbytes`` using BASE58 encoding and return
|
||||
## encoded string.
|
||||
var size = (len(inbytes) * 138) div 100 + 1
|
||||
result = newString(size)
|
||||
if btype.encode(inbytes, result.toOpenArray(0, size - 1),
|
||||
size) == Base58Status.Success:
|
||||
result.setLen(size)
|
||||
var resstr = newString(size)
|
||||
let res = btype.encode(inbytes, resstr.toOpenArray(0, size - 1))
|
||||
if res.isOk:
|
||||
resstr.setLen(res.get())
|
||||
result.ok(resstr)
|
||||
else:
|
||||
result = ""
|
||||
result.err(res.error)
|
||||
|
||||
proc decode*[T: byte|char](btype: typedesc[Base58C], instr: openarray[T],
|
||||
outbytes: var openarray[byte], outlen: var int): Base58Status =
|
||||
## Decode BASE58 string and store array of bytes to ``outbytes``. On success
|
||||
## ``Base58Status.Success`` will be returned and ``outlen`` will be set
|
||||
## to number of bytes stored.
|
||||
outbytes: var openarray[byte]): Result[int, e.Error] =
|
||||
## Decode BASE58 encoded string and store result to array of bytes
|
||||
## ``outbytes``. On success procedure returns number of bytes stored inside
|
||||
## of ``outbytes``.
|
||||
##
|
||||
## Length of ``outbytes`` must be equal or more then ``len(instr) + 4``.
|
||||
##
|
||||
## If ``instr`` has characters which are not part of BASE58 alphabet, then
|
||||
## ``Base58Status.Incorrect`` will be returned and ``outlen`` will be set to
|
||||
## ``0``.
|
||||
##
|
||||
## If length of ``outbytes`` is not enough to store decoded bytes, then
|
||||
## ``Base58Status.Overrun`` will be returned and ``outlen`` will be set to
|
||||
## number of bytes required.
|
||||
when btype is BTCBase58:
|
||||
const alphabet = BTCAlphabet
|
||||
elif btype is FLCBase58:
|
||||
const alphabet = FlickrAlphabet
|
||||
|
||||
var outlen = 0
|
||||
|
||||
if len(instr) == 0:
|
||||
outlen = 0
|
||||
return Base58Status.Success
|
||||
result.ok(0)
|
||||
return
|
||||
|
||||
let binsz = len(instr) + 4
|
||||
if len(outbytes) < binsz:
|
||||
outlen = binsz
|
||||
return Base58Status.Overrun
|
||||
result.err(e.OverrunError)
|
||||
return
|
||||
|
||||
var bytesleft = binsz mod 4
|
||||
var zeromask: uint32
|
||||
|
@ -167,13 +226,11 @@ proc decode*[T: byte|char](btype: typedesc[Base58C], instr: openarray[T],
|
|||
|
||||
for i in zcount..<len(instr):
|
||||
if (cast[byte](instr[i]) and 0x80'u8) != 0:
|
||||
outlen = 0
|
||||
result = Base58Status.Incorrect
|
||||
result.err(e.IncorrectEncodingError)
|
||||
return
|
||||
let ch = alphabet.decode[int8(instr[i])]
|
||||
if ch == -1:
|
||||
outlen = 0
|
||||
result = Base58Status.Incorrect
|
||||
result.err(e.IncorrectEncodingError)
|
||||
return
|
||||
var c = cast[uint32](ch)
|
||||
for j in countdown(size - 1, 0):
|
||||
|
@ -181,12 +238,10 @@ proc decode*[T: byte|char](btype: typedesc[Base58C], instr: openarray[T],
|
|||
c = cast[uint32]((t and 0x3F_0000_0000'u64) shr 32)
|
||||
buffer[j] = cast[uint32](t and 0xFFFF_FFFF'u32)
|
||||
if c != 0:
|
||||
outlen = 0
|
||||
result = Base58Status.Incorrect
|
||||
result.err(e.IncorrectEncodingError)
|
||||
return
|
||||
if (buffer[0] and zeromask) != 0:
|
||||
outlen = 0
|
||||
result = Base58Status.Incorrect
|
||||
result.err(e.IncorrectEncodingError)
|
||||
return
|
||||
|
||||
var boffset = 0
|
||||
|
@ -217,7 +272,7 @@ proc decode*[T: byte|char](btype: typedesc[Base58C], instr: openarray[T],
|
|||
while m < binsz:
|
||||
if outbytes[m] != 0x00:
|
||||
if zcount > m:
|
||||
result = Base58Status.Overrun
|
||||
result.err(e.OverrunError)
|
||||
return
|
||||
break
|
||||
inc(m)
|
||||
|
@ -226,14 +281,131 @@ proc decode*[T: byte|char](btype: typedesc[Base58C], instr: openarray[T],
|
|||
if m < binsz:
|
||||
moveMem(addr outbytes[zcount], addr outbytes[binsz - outlen], outlen)
|
||||
outlen += zcount
|
||||
result = Base58Status.Success
|
||||
result.ok(outlen)
|
||||
|
||||
proc decode*(btype: typedesc[Base58C], instr: string): seq[byte] =
|
||||
# proc decode*[T: byte|char](btype: typedesc[Base58C], instr: openarray[T],
|
||||
# outbytes: var openarray[byte], outlen: var int): Base58Status =
|
||||
# ## Decode BASE58 string and store array of bytes to ``outbytes``. On success
|
||||
# ## ``Base58Status.Success`` will be returned and ``outlen`` will be set
|
||||
# ## to number of bytes stored.
|
||||
# ##
|
||||
# ## Length of ``outbytes`` must be equal or more then ``len(instr) + 4``.
|
||||
# ##
|
||||
# ## If ``instr`` has characters which are not part of BASE58 alphabet, then
|
||||
# ## ``Base58Status.Incorrect`` will be returned and ``outlen`` will be set to
|
||||
# ## ``0``.
|
||||
# ##
|
||||
# ## If length of ``outbytes`` is not enough to store decoded bytes, then
|
||||
# ## ``Base58Status.Overrun`` will be returned and ``outlen`` will be set to
|
||||
# ## number of bytes required.
|
||||
# when btype is BTCBase58:
|
||||
# const alphabet = BTCAlphabet
|
||||
# elif btype is FLCBase58:
|
||||
# const alphabet = FlickrAlphabet
|
||||
|
||||
# if len(instr) == 0:
|
||||
# outlen = 0
|
||||
# return Base58Status.Success
|
||||
|
||||
# let binsz = len(instr) + 4
|
||||
# if len(outbytes) < binsz:
|
||||
# outlen = binsz
|
||||
# return Base58Status.Overrun
|
||||
|
||||
# var bytesleft = binsz mod 4
|
||||
# var zeromask: uint32
|
||||
# if bytesleft != 0:
|
||||
# zeromask = cast[uint32](0xFFFF_FFFF'u32 shl (bytesleft * 8))
|
||||
|
||||
# let size = (binsz + 3) div 4
|
||||
# var buffer = newSeq[uint32](size)
|
||||
|
||||
# var zcount = 0
|
||||
# while zcount < len(instr) and instr[zcount] == cast[char](alphabet.encode[0]):
|
||||
# inc(zcount)
|
||||
|
||||
# for i in zcount..<len(instr):
|
||||
# if (cast[byte](instr[i]) and 0x80'u8) != 0:
|
||||
# outlen = 0
|
||||
# result = Base58Status.Incorrect
|
||||
# return
|
||||
# let ch = alphabet.decode[int8(instr[i])]
|
||||
# if ch == -1:
|
||||
# outlen = 0
|
||||
# result = Base58Status.Incorrect
|
||||
# return
|
||||
# var c = cast[uint32](ch)
|
||||
# for j in countdown(size - 1, 0):
|
||||
# let t = cast[uint64](buffer[j]) * 58 + c
|
||||
# c = cast[uint32]((t and 0x3F_0000_0000'u64) shr 32)
|
||||
# buffer[j] = cast[uint32](t and 0xFFFF_FFFF'u32)
|
||||
# if c != 0:
|
||||
# outlen = 0
|
||||
# result = Base58Status.Incorrect
|
||||
# return
|
||||
# if (buffer[0] and zeromask) != 0:
|
||||
# outlen = 0
|
||||
# result = Base58Status.Incorrect
|
||||
# return
|
||||
|
||||
# var boffset = 0
|
||||
# var joffset = 0
|
||||
# if bytesleft == 3:
|
||||
# outbytes[boffset] = cast[uint8]((buffer[0] and 0xFF_0000'u32) shr 16)
|
||||
# inc(boffset)
|
||||
# bytesleft = 2
|
||||
# if bytesleft == 2:
|
||||
# outbytes[boffset] = cast[uint8]((buffer[0] and 0xFF00'u32) shr 8)
|
||||
# inc(boffset)
|
||||
# bytesleft = 1
|
||||
# if bytesleft == 1:
|
||||
# outbytes[boffset] = cast[uint8]((buffer[0] and 0xFF'u32))
|
||||
# inc(boffset)
|
||||
# joffset = 1
|
||||
|
||||
# while joffset < size:
|
||||
# outbytes[boffset + 0] = cast[byte]((buffer[joffset] shr 0x18) and 0xFF)
|
||||
# outbytes[boffset + 1] = cast[byte]((buffer[joffset] shr 0x10) and 0xFF)
|
||||
# outbytes[boffset + 2] = cast[byte]((buffer[joffset] shr 0x8) and 0xFF)
|
||||
# outbytes[boffset + 3] = cast[byte](buffer[joffset] and 0xFF)
|
||||
# boffset += 4
|
||||
# inc(joffset)
|
||||
|
||||
# outlen = binsz
|
||||
# var m = 0
|
||||
# while m < binsz:
|
||||
# if outbytes[m] != 0x00:
|
||||
# if zcount > m:
|
||||
# result = Base58Status.Overrun
|
||||
# return
|
||||
# break
|
||||
# inc(m)
|
||||
# dec(outlen)
|
||||
|
||||
# if m < binsz:
|
||||
# moveMem(addr outbytes[zcount], addr outbytes[binsz - outlen], outlen)
|
||||
# outlen += zcount
|
||||
# result = Base58Status.Success
|
||||
|
||||
# proc decode*(btype: typedesc[Base58C], instr: string): seq[byte] =
|
||||
# ## Decode BASE58 string ``instr`` and return sequence of bytes as result.
|
||||
# if len(instr) > 0:
|
||||
# var size = len(instr) + 4
|
||||
# result = newSeq[byte](size)
|
||||
# if btype.decode(instr, result, size) == Base58Status.Success:
|
||||
# result.setLen(size)
|
||||
# else:
|
||||
# raise newException(Base58Error, "Incorrect base58 string")
|
||||
|
||||
proc decode*(btype: typedesc[Base58C],
|
||||
instr: string): Result[seq[byte], e.Error] =
|
||||
## Decode BASE58 string ``instr`` and return sequence of bytes as result.
|
||||
if len(instr) > 0:
|
||||
var size = len(instr) + 4
|
||||
result = newSeq[byte](size)
|
||||
if btype.decode(instr, result, size) == Base58Status.Success:
|
||||
result.setLen(size)
|
||||
var resbytes = newSeq[byte](size)
|
||||
let res = btype.decode(instr, resbytes)
|
||||
if res.isOk:
|
||||
resbytes.setLen(res.value)
|
||||
result.ok(resbytes)
|
||||
else:
|
||||
raise newException(Base58Error, "Incorrect base58 string")
|
||||
result.err(res.error)
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
## Nim-Libp2p
|
||||
## Copyright (c) 2018 Status Research & Development GmbH
|
||||
## Licensed under either of
|
||||
## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
## * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
## at your option.
|
||||
## This file may not be copied, modified, or distributed except according to
|
||||
## those terms.
|
||||
import result
|
||||
export result
|
||||
|
||||
type
|
||||
Error* = enum
|
||||
NoError,
|
||||
GenericError,
|
||||
IncorrectError,
|
||||
OverrunError,
|
||||
OverflowError,
|
||||
IncompleteError,
|
||||
EndOfBufferError,
|
||||
NoSupportError,
|
||||
|
||||
VarintError,
|
||||
IncorrectEncodingError,
|
||||
|
||||
MultiAddressMalformedError,
|
||||
MultiAddressDecodeError,
|
||||
MultiAddressEncodeError,
|
||||
MultiAddressProtocolNotFoundError,
|
||||
MultiAddressProtocolIncorrectError,
|
||||
MultiAddressIncorrectError,
|
||||
MultiAddressNoSupportError,
|
||||
|
|
@ -14,6 +14,7 @@
|
|||
## - LibP2P varint, which is able to encode only 63bits of uint64 number and
|
||||
## maximum size of encoded value is 9 octets (bytes).
|
||||
import bitops
|
||||
import errors as e
|
||||
|
||||
type
|
||||
VarintStatus* {.pure.} = enum
|
||||
|
@ -37,6 +38,10 @@ type
|
|||
SomeUVarint* = PBSomeUVarint | LPSomeUVarint
|
||||
VarintError* = object of CatchableError
|
||||
|
||||
Varint* = object
|
||||
value*: uint64
|
||||
length*: int8
|
||||
|
||||
proc vsizeof*(x: SomeVarint): int {.inline.} =
|
||||
## Returns number of bytes required to encode integer ``x`` as varint.
|
||||
if x == cast[type(x)](0):
|
||||
|
@ -44,6 +49,36 @@ proc vsizeof*(x: SomeVarint): int {.inline.} =
|
|||
else:
|
||||
result = (fastLog2(x) + 1 + 7 - 1) div 7
|
||||
|
||||
proc getUVarint*[T: PB|LP](vt: typedesc[T],
|
||||
pbytes: openarray[byte]): Result[Varint, e.Error] =
|
||||
when vt is PB:
|
||||
const MaxBits = 64'u8
|
||||
else:
|
||||
const MaxBits = 63'u8
|
||||
|
||||
var status = e.IncompleteError
|
||||
var shift = 0'u8
|
||||
var outlen = 0'i8
|
||||
var outval = 0'u64
|
||||
|
||||
for i in 0..<len(pbytes):
|
||||
let b = pbytes[i]
|
||||
if shift >= MaxBits:
|
||||
status = e.OverflowError
|
||||
break
|
||||
else:
|
||||
outval = outval or (cast[type(outval)](b and 0x7F'u8) shl shift)
|
||||
shift += 7
|
||||
inc(outlen)
|
||||
if (b and 0x80'u8) == 0'u8:
|
||||
status = e.NoError
|
||||
break
|
||||
|
||||
if status == e.NoError:
|
||||
result.ok(Varint(value: outval, length: outlen))
|
||||
else:
|
||||
result.err(status)
|
||||
|
||||
proc getUVarint*[T: PB|LP](vtype: typedesc[T],
|
||||
pbytes: openarray[byte],
|
||||
outlen: var int,
|
||||
|
@ -99,6 +134,34 @@ proc getUVarint*[T: PB|LP](vtype: typedesc[T],
|
|||
outlen = 0
|
||||
outval = cast[type(outval)](0)
|
||||
|
||||
proc putUVarint*[T: PB|LP](vt: typedesc[T], pbytes: var openarray[byte],
|
||||
value: SomeUVarint): Result[int, e.Error] =
|
||||
## Returns number of bytes used to encode value ``value``.
|
||||
var buffer: array[10, byte]
|
||||
var k = 0
|
||||
var v = value
|
||||
|
||||
when vt is LP:
|
||||
if sizeof(value) == 8 and (value and 0x8000_0000_0000_0000'u64) != 0'u64:
|
||||
result.err(e.OverflowError)
|
||||
return
|
||||
|
||||
if v <= cast[type(value)](0x7F):
|
||||
buffer[0] = cast[byte](value and 0xFF)
|
||||
inc(k)
|
||||
else:
|
||||
while v != cast[type(value)](0):
|
||||
buffer[k] = cast[byte]((v and 0x7F) or 0x80)
|
||||
v = v shr 7
|
||||
inc(k)
|
||||
buffer[k - 1] = buffer[k - 1] and 0x7F'u8
|
||||
|
||||
if len(pbytes) >= k:
|
||||
copyMem(addr pbytes[0], addr buffer[0], k)
|
||||
result.ok(k)
|
||||
else:
|
||||
result.err(e.OverrunError)
|
||||
|
||||
proc putUVarint*[T: PB|LP](vtype: typedesc[T],
|
||||
pbytes: var openarray[byte],
|
||||
outlen: var int,
|
||||
|
@ -146,6 +209,19 @@ proc putUVarint*[T: PB|LP](vtype: typedesc[T],
|
|||
else:
|
||||
result = VarintStatus.Overrun
|
||||
|
||||
proc getSVarint*(vt: typedesc[PB],
|
||||
pbytes: openarray[byte]): Result[Varint, e.Error] {.inline.} =
|
||||
let res = PB.getUVarint(pbytes)
|
||||
if res.isErr():
|
||||
result.err(res.error)
|
||||
else:
|
||||
var value = res.value.value
|
||||
if (value and 1'u64) != 0'u64:
|
||||
value = not(value shr 1)
|
||||
else:
|
||||
value = value shr 1
|
||||
result.ok(Varint(value: value, length: res.value.length))
|
||||
|
||||
proc getSVarint*(pbytes: openarray[byte], outsize: var int,
|
||||
outval: var PBSomeSVarint): VarintStatus {.inline.} =
|
||||
## Decode Google ProtoBuf's `signed varint` from buffer ``pbytes`` and store
|
||||
|
@ -176,6 +252,22 @@ proc getSVarint*(pbytes: openarray[byte], outsize: var int,
|
|||
else:
|
||||
outval = cast[type(outval)](value shr 1)
|
||||
|
||||
proc putSVarint*(vt: typedesc[PB], pbytes: var openarray[byte],
|
||||
value: PBSomeSVarint): Result[int, e.Error] {.inline.} =
|
||||
when sizeof(outval) == 8:
|
||||
var v: uint64 =
|
||||
if value < 0:
|
||||
not(cast[uint64](outval) shl 1)
|
||||
else:
|
||||
cast[uint64](outval) shl 1
|
||||
else:
|
||||
var v: uint32 =
|
||||
if outval < 0:
|
||||
not(cast[uint32](outval) shl 1)
|
||||
else:
|
||||
cast[uint32](outval) shl 1
|
||||
result = PB.putUVarint(pbytes, v)
|
||||
|
||||
proc putSVarint*(pbytes: var openarray[byte], outsize: var int,
|
||||
outval: PBSomeSVarint): VarintStatus {.inline.} =
|
||||
## Encode Google ProtoBuf's `signed varint` ``outval`` and store it to array
|
||||
|
@ -204,6 +296,25 @@ proc putSVarint*(pbytes: var openarray[byte], outsize: var int,
|
|||
cast[uint32](outval) shl 1
|
||||
result = PB.putUVarint(pbytes, outsize, value)
|
||||
|
||||
proc encodeVarint*(vt: typedesc[PB],
|
||||
value: PBSomeVarint): Result[seq[byte], e.Error] {.inline.} =
|
||||
var bytes = newSeqOfCap[byte](10)
|
||||
when sizeof(value) == 4:
|
||||
bytes.setLen(5)
|
||||
else:
|
||||
bytes.setLen(10)
|
||||
|
||||
when type(value) is PBSomeSVarint:
|
||||
let res = PB.putSVarint(bytes, value)
|
||||
else:
|
||||
let res = PB.putUVarint(bytes, value)
|
||||
|
||||
if res.isOk:
|
||||
bytes.setLen(res.value.length)
|
||||
result.ok(bytes)
|
||||
else:
|
||||
result.err(res.error)
|
||||
|
||||
proc encodeVarint*(vtype: typedesc[PB],
|
||||
value: PBSomeVarint): seq[byte] {.inline.} =
|
||||
## Encode integer to Google ProtoBuf's `signed/unsigned varint` and returns
|
||||
|
@ -223,6 +334,24 @@ proc encodeVarint*(vtype: typedesc[PB],
|
|||
else:
|
||||
raise newException(VarintError, "Error '" & $res & "'")
|
||||
|
||||
proc encodeVarint*(vt: typedesc[LP],
|
||||
value: LPSomeVarint): Result[seq[byte], e.Error] {.inline.} =
|
||||
when sizeof(value) == 1:
|
||||
var bytes = newSeq[byte](2)
|
||||
elif sizeof(value) == 2:
|
||||
var bytes = newSeq[byte](3)
|
||||
elif sizeof(value) == 4:
|
||||
var bytes = newSeq[byte](5)
|
||||
else:
|
||||
var bytes = newSeq[byte](9)
|
||||
|
||||
let res = LP.putUVarint(bytes, value)
|
||||
if res.isOk:
|
||||
bytes.setLen(res.value.length)
|
||||
result.ok(bytes)
|
||||
else:
|
||||
result.err(res.error)
|
||||
|
||||
proc encodeVarint*(vtype: typedesc[LP],
|
||||
value: LPSomeVarint): seq[byte] {.inline.} =
|
||||
## Encode integer to LibP2P `unsigned varint` and returns sequence of bytes
|
||||
|
@ -243,6 +372,13 @@ proc encodeVarint*(vtype: typedesc[LP],
|
|||
else:
|
||||
raise newException(VarintError, "Error '" & $res & "'")
|
||||
|
||||
proc decodeSVarint2*(data: openarray[byte]): Result[int64, e.Error] {.inline.} =
|
||||
let res = PB.getSVarint(data)
|
||||
if res.isOk:
|
||||
result.ok(cast[int64](res.value.value))
|
||||
else:
|
||||
result.err(res.error)
|
||||
|
||||
proc decodeSVarint*(data: openarray[byte]): int {.inline.} =
|
||||
## Decode signed integer from array ``data`` and return it as result.
|
||||
var outsize = 0
|
||||
|
@ -250,6 +386,14 @@ proc decodeSVarint*(data: openarray[byte]): int {.inline.} =
|
|||
if res != VarintStatus.Success:
|
||||
raise newException(VarintError, "Error '" & $res & "'")
|
||||
|
||||
proc decodeUVarint2*[T: PB|LP](vt: typedesc[T],
|
||||
data: openarray[byte]): Result[uint64, e.Error] {.inline.} =
|
||||
let res = vt.getUVarint(data)
|
||||
if res.isOk:
|
||||
result.ok(res.value.value)
|
||||
else:
|
||||
result.err(res.error)
|
||||
|
||||
proc decodeUVarint*[T: PB|LP](vtype: typedesc[T],
|
||||
data: openarray[byte]): uint {.inline.} =
|
||||
## Decode unsigned integer from array ``data`` and return it as result.
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
## those terms.
|
||||
|
||||
## This module implements variable buffer.
|
||||
import varint, strutils
|
||||
import strutils
|
||||
import varint, errors as e
|
||||
|
||||
type
|
||||
VBuffer* = object
|
||||
|
@ -34,102 +35,184 @@ proc isLiteral[T](s: seq[T]): bool {.inline.} =
|
|||
length, reserved: int
|
||||
(cast[ptr SeqHeader](s).reserved and (1 shl (sizeof(int) * 8 - 2))) != 0
|
||||
|
||||
proc initVBuffer*(data: seq[byte], offset = 0): VBuffer =
|
||||
## Initialize VBuffer with shallow copy of ``data``.
|
||||
# proc initVBuffer*(data: seq[byte], offset = 0): VBuffer =
|
||||
# ## Initialize VBuffer with shallow copy of ``data``.
|
||||
# if isLiteral(data):
|
||||
# result.buffer = data
|
||||
# else:
|
||||
# shallowCopy(result.buffer, data)
|
||||
# result.offset = offset
|
||||
|
||||
# proc initVBuffer*(data: openarray[byte], offset = 0): VBuffer =
|
||||
# ## Initialize VBuffer with copy of ``data``.
|
||||
# result.buffer = newSeq[byte](len(data))
|
||||
# if len(data) > 0:
|
||||
# copyMem(addr result.buffer[0], unsafeAddr data[0], len(data))
|
||||
# result.offset = offset
|
||||
|
||||
# proc initVBuffer*(): VBuffer =
|
||||
# ## Initialize empty VBuffer.
|
||||
# result.buffer = newSeqOfCap[byte](128)
|
||||
|
||||
proc init*(bt: typedesc[VBuffer], data: seq[byte], offset = 0): VBuffer =
|
||||
## Initialize ``VBuffer`` with sequence ``data`` and initial offset
|
||||
## ``offset``.
|
||||
##
|
||||
## If ``data`` is not literal, it will be stored as reference.
|
||||
if isLiteral(data):
|
||||
result.buffer = data
|
||||
else:
|
||||
shallowCopy(result.buffer, data)
|
||||
result.offset = offset
|
||||
|
||||
proc initVBuffer*(data: openarray[byte], offset = 0): VBuffer =
|
||||
## Initialize VBuffer with copy of ``data``.
|
||||
result.buffer = newSeq[byte](len(data))
|
||||
if len(data) > 0:
|
||||
copyMem(addr result.buffer[0], unsafeAddr data[0], len(data))
|
||||
proc init*(bt: typedesc[VBuffer], data: openarray[byte], offset = 0): VBuffer =
|
||||
## Initialize ``VBuffer`` with openarray ``data`` and initial offset
|
||||
## ``offset``.
|
||||
##
|
||||
## ``data`` array will be copied to ``VBuffer`` instance.
|
||||
let length = len(data)
|
||||
if length > 0:
|
||||
result.buffer = newSeq[byte](length)
|
||||
copyMem(addr result.buffer[0], unsafeAddr data[0], length)
|
||||
else:
|
||||
result.buffer = newSeq[byte]()
|
||||
result.offset = offset
|
||||
|
||||
proc initVBuffer*(): VBuffer =
|
||||
## Initialize empty VBuffer.
|
||||
proc init*(bt: typedesc[VBuffer]): VBuffer =
|
||||
## Initialize empty ``VBuffer``.
|
||||
result.buffer = newSeqOfCap[byte](128)
|
||||
result.offset = 0
|
||||
|
||||
proc writeVarint*(vb: var VBuffer, value: LPSomeUVarint) =
|
||||
## Write ``value`` as variable unsigned integer.
|
||||
# proc writeVarint*(vb: var VBuffer, value: LPSomeUVarint) =
|
||||
# ## Write ``value`` as variable unsigned integer.
|
||||
# var length = 0
|
||||
# # LibP2P varint supports only 63 bits.
|
||||
# var v = value and cast[type(value)](0x7FFF_FFFF_FFFF_FFFF)
|
||||
# vb.buffer.setLen(len(vb.buffer) + vsizeof(v))
|
||||
# let res = LP.putUVarint(toOpenArray(vb.buffer, vb.offset, len(vb.buffer) - 1),
|
||||
# length, v)
|
||||
# doAssert(res == VarintStatus.Success)
|
||||
# vb.offset += length
|
||||
|
||||
proc writeVarint*(vb: var VBuffer,
|
||||
value: LPSomeUVarint): Result[int, e.Error] =
|
||||
## Write ``value`` as variable unsigned integer. Procedure returns number of
|
||||
## bytes written.
|
||||
var length = 0
|
||||
# LibP2P varint supports only 63 bits.
|
||||
var v = value and cast[type(value)](0x7FFF_FFFF_FFFF_FFFF)
|
||||
vb.buffer.setLen(len(vb.buffer) + vsizeof(v))
|
||||
vb.buffer.setLen(len(vb.buffer) + vsizeof(value))
|
||||
let res = LP.putUVarint(toOpenArray(vb.buffer, vb.offset, len(vb.buffer) - 1),
|
||||
length, v)
|
||||
doAssert(res == VarintStatus.Success)
|
||||
vb.offset += length
|
||||
value)
|
||||
if res.isOk:
|
||||
vb.offset += res.value
|
||||
result.ok(res.value)
|
||||
else:
|
||||
result.err(res.error)
|
||||
|
||||
proc writeSeq*[T: byte|char](vb: var VBuffer, value: openarray[T]) =
|
||||
# proc writeSeq*[T: byte|char](vb: var VBuffer, value: openarray[T]) =
|
||||
# ## Write array ``value`` to buffer ``vb``, value will be prefixed with
|
||||
# ## varint length of the array.
|
||||
# var length = 0
|
||||
# vb.buffer.setLen(len(vb.buffer) + vsizeof(len(value)) + len(value))
|
||||
# let res = LP.putUVarint(toOpenArray(vb.buffer, vb.offset, len(vb.buffer) - 1),
|
||||
# length, uint(len(value)))
|
||||
# doAssert(res == VarintStatus.Success)
|
||||
# vb.offset += length
|
||||
# if len(value) > 0:
|
||||
# copyMem(addr vb.buffer[vb.offset], unsafeAddr value[0], len(value))
|
||||
# vb.offset += len(value)
|
||||
|
||||
proc writeSeq*[T: byte|char](vb: var VBuffer,
|
||||
value: openarray[T]): Result[int, e.Error] =
|
||||
## Write array ``value`` to buffer ``vb``, value will be prefixed with
|
||||
## varint length of the array.
|
||||
## varint length of the array. Procedure returns number of bytes written.
|
||||
var length = 0
|
||||
vb.buffer.setLen(len(vb.buffer) + vsizeof(len(value)) + len(value))
|
||||
let res = LP.putUVarint(toOpenArray(vb.buffer, vb.offset, len(vb.buffer) - 1),
|
||||
length, uint(len(value)))
|
||||
doAssert(res == VarintStatus.Success)
|
||||
vb.offset += length
|
||||
if len(value) > 0:
|
||||
copyMem(addr vb.buffer[vb.offset], unsafeAddr value[0], len(value))
|
||||
vb.offset += len(value)
|
||||
uint64(len(value)))
|
||||
if res.isOk:
|
||||
length = res.value
|
||||
vb.offset += length
|
||||
if len(value) > 0:
|
||||
copyMem(addr vb.buffer[vb.offset], unsafeAddr value[0], len(value))
|
||||
length += len(value)
|
||||
vb.offset += len(value)
|
||||
result.ok(length)
|
||||
else:
|
||||
result.err(res.error)
|
||||
|
||||
proc writeArray*[T: byte|char](vb: var VBuffer, value: openarray[T]) =
|
||||
# proc writeArray*[T: byte|char](vb: var VBuffer, value: openarray[T]) =
|
||||
# ## Write array ``value`` to buffer ``vb``, value will NOT be prefixed with
|
||||
# ## varint length of the array.
|
||||
# var length = 0
|
||||
# if len(value) > 0:
|
||||
# vb.buffer.setLen(len(vb.buffer) + len(value))
|
||||
# copyMem(addr vb.buffer[vb.offset], unsafeAddr value[0], len(value))
|
||||
# vb.offset += len(value)
|
||||
|
||||
proc writeArray*[T: byte|char](vb: var VBuffer,
|
||||
value: openarray[T]): Result[int, e.Error] =
|
||||
## Write array ``value`` to buffer ``vb``, value will NOT be prefixed with
|
||||
## varint length of the array.
|
||||
## varint length of the array. Procedure returns number of bytes written.
|
||||
var length = 0
|
||||
if len(value) > 0:
|
||||
vb.buffer.setLen(len(vb.buffer) + len(value))
|
||||
copyMem(addr vb.buffer[vb.offset], unsafeAddr value[0], len(value))
|
||||
vb.offset += len(value)
|
||||
result.ok(len(value))
|
||||
|
||||
proc finish*(vb: var VBuffer) =
|
||||
## Finishes ``vb``.
|
||||
vb.offset = 0
|
||||
|
||||
proc peekVarint*(vb: var VBuffer, value: var LPSomeUVarint): int =
|
||||
proc peekVarint*(vb: var VBuffer,
|
||||
value: var LPSomeUVarint): Result[int, e.Error] =
|
||||
## Peek unsigned integer from buffer ``vb`` and store result to ``value``.
|
||||
##
|
||||
## This procedure will not adjust internal offset.
|
||||
##
|
||||
## Returns number of bytes peeked from ``vb`` or ``-1`` on error.
|
||||
result = -1
|
||||
value = cast[type(value)](0)
|
||||
var length = 0
|
||||
if not vb.isEmpty():
|
||||
let res = LP.getUVarint(
|
||||
toOpenArray(vb.buffer, vb.offset, len(vb.buffer) - 1), length, value)
|
||||
if res == VarintStatus.Success:
|
||||
result = length
|
||||
if vb.isEmpty():
|
||||
result.err(e.EndOfBufferError)
|
||||
else:
|
||||
let res = LP.getUVarint(toOpenArray(vb.buffer, vb.offset,
|
||||
len(vb.buffer) - 1))
|
||||
if res.isOk:
|
||||
value = type(value)(res.value.value)
|
||||
result.ok(res.value.length)
|
||||
else:
|
||||
result.err(e.VarintError)
|
||||
|
||||
proc peekSeq*[T: string|seq[byte]](vb: var VBuffer, value: var T): int =
|
||||
proc peekSeq*[T: string|seq[byte]](vb: var VBuffer,
|
||||
value: var T): Result[int, e.Error] =
|
||||
## Peek length prefixed array from buffer ``vb`` and store result to
|
||||
## ``value``.
|
||||
##
|
||||
## This procedure will not adjust internal offset.
|
||||
##
|
||||
## Returns number of bytes peeked from ``vb`` or ``-1`` on error.
|
||||
result = -1
|
||||
value.setLen(0)
|
||||
var length = 0
|
||||
var size = 0'u64
|
||||
if not vb.isEmpty() and
|
||||
LP.getUVarint(toOpenArray(vb.buffer, vb.offset, len(vb.buffer) - 1),
|
||||
length, size) == VarintStatus.Success:
|
||||
vb.offset += length
|
||||
result = length
|
||||
if vb.isEnough(int(size)):
|
||||
value.setLen(size)
|
||||
if size > 0'u64:
|
||||
copyMem(addr value[0], addr vb.buffer[vb.offset], size)
|
||||
result += int(size)
|
||||
vb.offset -= length
|
||||
|
||||
if vb.isEmpty():
|
||||
result.err(e.EndOfBufferError)
|
||||
else:
|
||||
let res = LP.getUVarint(toOpenArray(vb.buffer, vb.offset,
|
||||
len(vb.buffer) - 1))
|
||||
if res.isErr():
|
||||
result.err(e.VarintError)
|
||||
else:
|
||||
let size = res.value.value
|
||||
vb.offset += res.value.length
|
||||
if vb.isEnough(size):
|
||||
value.setLen(size)
|
||||
if size > 0'u64:
|
||||
copyMem(addr value[0], addr vb.buffer[vb.offset], size)
|
||||
result.ok(res.value.length + size)
|
||||
else:
|
||||
result.err(e.EndOfBufferError)
|
||||
vb.offset -= res.value.length
|
||||
|
||||
proc peekArray*[T: char|byte](vb: var VBuffer,
|
||||
value: var openarray[T]): int =
|
||||
value: var openarray[T]): Result[int, e.Error] =
|
||||
## Peek array from buffer ``vb`` and store result to ``value``.
|
||||
##
|
||||
## This procedure will not adjust internal offset.
|
||||
|
@ -137,37 +220,51 @@ proc peekArray*[T: char|byte](vb: var VBuffer,
|
|||
## Returns number of bytes peeked from ``vb`` or ``-1`` on error.
|
||||
result = -1
|
||||
let length = len(value)
|
||||
if vb.isEnough(length):
|
||||
if length > 0:
|
||||
if length > 0:
|
||||
if vb.isEnough(length):
|
||||
copyMem(addr value[0], addr vb.buffer[vb.offset], length)
|
||||
result = length
|
||||
result.ok(length)
|
||||
else:
|
||||
result.err(e.EndOfBufferError)
|
||||
else:
|
||||
result.ok(0)
|
||||
|
||||
proc readVarint*(vb: var VBuffer, value: var LPSomeUVarint): int {.inline.} =
|
||||
proc readVarint*(vb: var VBuffer,
|
||||
value: var LPSomeUVarint): Result[int, e.Error] {.inline.} =
|
||||
## Read unsigned integer from buffer ``vb`` and store result to ``value``.
|
||||
##
|
||||
## Returns number of bytes consumed from ``vb`` or ``-1`` on error.
|
||||
result = vb.peekVarint(value)
|
||||
if result != -1:
|
||||
vb.offset += result
|
||||
let res = vb.peekVarint(value)
|
||||
if res.isOk:
|
||||
vb.offset += res.value
|
||||
result.ok(res.value)
|
||||
else:
|
||||
result.err(res.error)
|
||||
|
||||
proc readSeq*[T: string|seq[byte]](vb: var VBuffer,
|
||||
value: var T): int {.inline.} =
|
||||
value: var T): Result[int, e.Error] {.inline.} =
|
||||
## Read length prefixed array from buffer ``vb`` and store result to
|
||||
## ``value``.
|
||||
##
|
||||
## Returns number of bytes consumed from ``vb`` or ``-1`` on error.
|
||||
result = vb.peekSeq(value)
|
||||
if result != -1:
|
||||
vb.offset += result
|
||||
let res = vb.peekSeq(value)
|
||||
if res.isOk:
|
||||
vb.offset += res.value
|
||||
result.ok(res.value)
|
||||
else:
|
||||
result.err(res.error)
|
||||
|
||||
proc readArray*[T: char|byte](vb: var VBuffer,
|
||||
value: var openarray[T]): int {.inline.} =
|
||||
## Read array from buffer ``vb`` and store result to ``value``.
|
||||
##
|
||||
## Returns number of bytes consumed from ``vb`` or ``-1`` on error.
|
||||
result = vb.peekArray(value)
|
||||
if result != -1:
|
||||
vb.offset += result
|
||||
let res = vb.peekArray(value)
|
||||
if res.isOk:
|
||||
vb.offset += res.value
|
||||
result.ok(res.value)
|
||||
else:
|
||||
result.err(res.error)
|
||||
|
||||
proc `$`*(vb: VBuffer): string =
|
||||
## Return hexadecimal string representation of buffer ``vb``.
|
||||
|
|
|
@ -55,76 +55,80 @@ const TestVectors = [
|
|||
suite "BASE58 encoding test suite":
|
||||
test "Empty seq/string test":
|
||||
var a = Base58.encode([])
|
||||
check len(a) == 0
|
||||
check:
|
||||
a.isOk == true
|
||||
len(a.value) == 0
|
||||
var b = Base58.decode("")
|
||||
check len(b) == 0
|
||||
test "Zero test":
|
||||
var s = newString(256)
|
||||
for i in 0..255:
|
||||
s[i] = '1'
|
||||
var buffer: array[256, byte]
|
||||
for i in 0..255:
|
||||
var a = Base58.encode(buffer.toOpenArray(0, i))
|
||||
check a == s[0..i]
|
||||
var b = Base58.decode(a)
|
||||
check b == buffer[0..i]
|
||||
test "Leading zero test":
|
||||
var buffer: array[256, byte]
|
||||
for i in 0..255:
|
||||
buffer[255] = byte(i)
|
||||
var a = Base58.encode(buffer)
|
||||
var b = Base58.decode(a)
|
||||
check:
|
||||
equalMem(addr buffer[0], addr b[0], 256) == true
|
||||
test "Small amount of bytes test":
|
||||
var buffer1: array[1, byte]
|
||||
var buffer2: array[2, byte]
|
||||
for i in 0..255:
|
||||
buffer1[0] = byte(i)
|
||||
var enc = Base58.encode(buffer1)
|
||||
var dec = Base58.decode(enc)
|
||||
check:
|
||||
len(dec) == 1
|
||||
dec[0] == buffer1[0]
|
||||
|
||||
for i in 0..255:
|
||||
for k in 0..255:
|
||||
buffer2[0] = byte(i)
|
||||
buffer2[1] = byte(k)
|
||||
var enc = Base58.encode(buffer2)
|
||||
var dec = Base58.decode(enc)
|
||||
check:
|
||||
len(dec) == 2
|
||||
dec[0] == buffer2[0]
|
||||
dec[1] == buffer2[1]
|
||||
test "Test Vectors test":
|
||||
for item in TestVectors:
|
||||
var a = fromHex(item[0])
|
||||
var enc = Base58.encode(a)
|
||||
var dec = Base58.decode(item[1])
|
||||
check:
|
||||
enc == item[1]
|
||||
dec == a
|
||||
test "Buffer Overrun test":
|
||||
var encres = ""
|
||||
var encsize = 0
|
||||
var decres: seq[byte] = @[]
|
||||
var decsize = 0
|
||||
check:
|
||||
Base58.encode([0'u8], encres, encsize) == Base58Status.Overrun
|
||||
encsize == 1
|
||||
Base58.decode("1", decres, decsize) == Base58Status.Overrun
|
||||
decsize == 5
|
||||
test "Incorrect test":
|
||||
var decres = newSeq[byte](10)
|
||||
var decsize = 0
|
||||
check:
|
||||
Base58.decode("l", decres, decsize) == Base58Status.Incorrect
|
||||
decsize == 0
|
||||
Base58.decode("2l", decres, decsize) == Base58Status.Incorrect
|
||||
decsize == 0
|
||||
Base58.decode("O", decres, decsize) == Base58Status.Incorrect
|
||||
decsize == 0
|
||||
Base58.decode("2O", decres, decsize) == Base58Status.Incorrect
|
||||
decsize == 0
|
||||
b.isOk == true
|
||||
len(b.value) == 0
|
||||
# test "Zero test":
|
||||
# var s = newString(256)
|
||||
# for i in 0..255:
|
||||
# s[i] = '1'
|
||||
# var buffer: array[256, byte]
|
||||
# for i in 0..255:
|
||||
# var a = Base58.encode(buffer.toOpenArray(0, i))
|
||||
# check a == s[0..i]
|
||||
# var b = Base58.decode(a)
|
||||
# check b == buffer[0..i]
|
||||
# test "Leading zero test":
|
||||
# var buffer: array[256, byte]
|
||||
# for i in 0..255:
|
||||
# buffer[255] = byte(i)
|
||||
# var a = Base58.encode(buffer)
|
||||
# var b = Base58.decode(a)
|
||||
# check:
|
||||
# equalMem(addr buffer[0], addr b[0], 256) == true
|
||||
# test "Small amount of bytes test":
|
||||
# var buffer1: array[1, byte]
|
||||
# var buffer2: array[2, byte]
|
||||
# for i in 0..255:
|
||||
# buffer1[0] = byte(i)
|
||||
# var enc = Base58.encode(buffer1)
|
||||
# var dec = Base58.decode(enc)
|
||||
# check:
|
||||
# len(dec) == 1
|
||||
# dec[0] == buffer1[0]
|
||||
|
||||
# for i in 0..255:
|
||||
# for k in 0..255:
|
||||
# buffer2[0] = byte(i)
|
||||
# buffer2[1] = byte(k)
|
||||
# var enc = Base58.encode(buffer2)
|
||||
# var dec = Base58.decode(enc)
|
||||
# check:
|
||||
# len(dec) == 2
|
||||
# dec[0] == buffer2[0]
|
||||
# dec[1] == buffer2[1]
|
||||
# test "Test Vectors test":
|
||||
# for item in TestVectors:
|
||||
# var a = fromHex(item[0])
|
||||
# var enc = Base58.encode(a)
|
||||
# var dec = Base58.decode(item[1])
|
||||
# check:
|
||||
# enc == item[1]
|
||||
# dec == a
|
||||
# test "Buffer Overrun test":
|
||||
# var encres = ""
|
||||
# var encsize = 0
|
||||
# var decres: seq[byte] = @[]
|
||||
# var decsize = 0
|
||||
# check:
|
||||
# Base58.encode([0'u8], encres, encsize) == Base58Status.Overrun
|
||||
# encsize == 1
|
||||
# Base58.decode("1", decres, decsize) == Base58Status.Overrun
|
||||
# decsize == 5
|
||||
# test "Incorrect test":
|
||||
# var decres = newSeq[byte](10)
|
||||
# var decsize = 0
|
||||
# check:
|
||||
# Base58.decode("l", decres, decsize) == Base58Status.Incorrect
|
||||
# decsize == 0
|
||||
# Base58.decode("2l", decres, decsize) == Base58Status.Incorrect
|
||||
# decsize == 0
|
||||
# Base58.decode("O", decres, decsize) == Base58Status.Incorrect
|
||||
# decsize == 0
|
||||
# Base58.decode("2O", decres, decsize) == Base58Status.Incorrect
|
||||
# decsize == 0
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import unittest
|
||||
import ../libp2p/varint
|
||||
import ../libp2p/[varint, errors]
|
||||
|
||||
const PBedgeValues = [
|
||||
0'u64, (1'u64 shl 7) - 1'u64,
|
||||
|
@ -92,34 +92,71 @@ suite "Variable integer test suite":
|
|||
var value = 0'u64
|
||||
for i in 0..<len(PBedgeValues):
|
||||
buffer.setLen(PBedgeSizes[i])
|
||||
|
||||
zeroMem(addr buffer[0], len(buffer))
|
||||
value = 0'u64
|
||||
|
||||
check:
|
||||
PB.putUVarint(buffer, length, PBedgeValues[i]) == VarintStatus.Success
|
||||
PB.getUVarint(buffer, length, value) == VarintStatus.Success
|
||||
value == PBedgeValues[i]
|
||||
toHex(buffer) == PBedgeExpects[i]
|
||||
|
||||
zeroMem(addr buffer[0], len(buffer))
|
||||
value = 0'u64
|
||||
|
||||
check PB.putUVarint(buffer, PBedgeValues[i]).isOk == true
|
||||
let res = PB.getUVarint(buffer)
|
||||
check:
|
||||
res.isOk == true
|
||||
res.value.value == PBedgeValues[i]
|
||||
toHex(buffer) == PBedgeExpects[i]
|
||||
|
||||
test "[ProtoBuf] Buffer Overrun edge cases test":
|
||||
var buffer = newSeq[byte]()
|
||||
var length = 0
|
||||
for i in 0..<len(PBedgeValues):
|
||||
buffer.setLen(PBedgeSizes[i] - 1)
|
||||
let res = PB.putUVarint(buffer, length, PBedgeValues[i])
|
||||
|
||||
if len(buffer) > 0:
|
||||
zeroMem(addr buffer[0], len(buffer))
|
||||
let res1 = PB.putUVarint(buffer, length, PBedgeValues[i])
|
||||
check:
|
||||
res == VarintStatus.Overrun
|
||||
res1 == VarintStatus.Overrun
|
||||
length == PBedgeSizes[i]
|
||||
|
||||
if len(buffer) > 0:
|
||||
zeroMem(addr buffer[0], len(buffer))
|
||||
let res2 = PB.putUVarint(buffer, PBedgeValues[i])
|
||||
check:
|
||||
res2.isErr == true
|
||||
res2.error == errors.OverrunError
|
||||
|
||||
test "[ProtoBuf] Buffer Incomplete edge cases test":
|
||||
var buffer = newSeq[byte]()
|
||||
var length = 0
|
||||
var value = 0'u64
|
||||
for i in 0..<len(PBedgeValues):
|
||||
buffer.setLen(PBedgeSizes[i])
|
||||
zeroMem(addr buffer[0], len(buffer))
|
||||
|
||||
check:
|
||||
PB.putUVarint(buffer, length, PBedgeValues[i]) == VarintStatus.Success
|
||||
buffer.setLen(len(buffer) - 1)
|
||||
check:
|
||||
PB.getUVarint(buffer, length, value) == VarintStatus.Incomplete
|
||||
|
||||
buffer.setLen(PBedgeSizes[i])
|
||||
zeroMem(addr buffer[0], len(buffer))
|
||||
|
||||
check:
|
||||
PB.putUVarint(buffer, PBedgeValues[i]).isOk == true
|
||||
buffer.setLen(len(buffer) - 1)
|
||||
let res = PB.getUVarint(buffer)
|
||||
check:
|
||||
res.isErr == true
|
||||
res.error == errors.IncompleteError
|
||||
|
||||
test "[ProtoBuf] Integer Overflow 32bit test":
|
||||
var buffer = newSeq[byte]()
|
||||
var length = 0
|
||||
|
@ -138,6 +175,7 @@ suite "Variable integer test suite":
|
|||
if PBedgeSizes[i] > 9:
|
||||
var value = 0'u64
|
||||
buffer.setLen(PBedgeSizes[i] + 1)
|
||||
zeroMem(addr buffer[0], len(buffer))
|
||||
check:
|
||||
PB.putUVarint(buffer, length, PBedgeValues[i]) == VarintStatus.Success
|
||||
buffer[9] = buffer[9] or 0x80'u8
|
||||
|
@ -145,28 +183,63 @@ suite "Variable integer test suite":
|
|||
check:
|
||||
PB.getUVarint(buffer, length, value) == VarintStatus.Overflow
|
||||
|
||||
buffer.setLen(PBedgeSizes[i] + 1)
|
||||
zeroMem(addr buffer[0], len(buffer))
|
||||
check:
|
||||
PB.putUVarint(buffer, PBedgeValues[i]).isOk == true
|
||||
buffer[9] = buffer[9] or 0x80'u8
|
||||
buffer[10] = 0x01'u8
|
||||
let res = PB.getUVarint(buffer)
|
||||
check:
|
||||
res.isErr == true
|
||||
res.error == errors.OverflowError
|
||||
|
||||
test "[LibP2P] Success edge cases test":
|
||||
var buffer = newSeq[byte]()
|
||||
var length = 0
|
||||
var value = 0'u64
|
||||
for i in 0..<len(LPedgeValues):
|
||||
buffer.setLen(LPedgeSizes[i])
|
||||
|
||||
zeroMem(addr buffer[0], len(buffer))
|
||||
value = 0'u64
|
||||
|
||||
check:
|
||||
LP.putUVarint(buffer, length, LPedgeValues[i]) == VarintStatus.Success
|
||||
LP.getUVarint(buffer, length, value) == VarintStatus.Success
|
||||
value == LPedgeValues[i]
|
||||
toHex(buffer) == LPedgeExpects[i]
|
||||
|
||||
zeroMem(addr buffer[0], len(buffer))
|
||||
value = 0'u64
|
||||
|
||||
check LP.putUVarint(buffer, LPedgeValues[i]).isOk == true
|
||||
let res = LP.getUVarint(buffer)
|
||||
check:
|
||||
res.isOk == true
|
||||
res.value.value == LPedgeValues[i]
|
||||
toHex(buffer) == LPedgeExpects[i]
|
||||
|
||||
test "[LibP2P] Buffer Overrun edge cases test":
|
||||
var buffer = newSeq[byte]()
|
||||
var length = 0
|
||||
for i in 0..<len(LPedgeValues):
|
||||
buffer.setLen(PBedgeSizes[i] - 1)
|
||||
let res = LP.putUVarint(buffer, length, LPedgeValues[i])
|
||||
|
||||
if len(buffer) > 0:
|
||||
zeroMem(addr buffer[0], len(buffer))
|
||||
let res1 = LP.putUVarint(buffer, length, LPedgeValues[i])
|
||||
check:
|
||||
res == VarintStatus.Overrun
|
||||
res1 == VarintStatus.Overrun
|
||||
length == LPedgeSizes[i]
|
||||
|
||||
if len(buffer) > 0:
|
||||
zeroMem(addr buffer[0], len(buffer))
|
||||
let res2 = LP.putUVarint(buffer, PBedgeValues[i])
|
||||
check:
|
||||
res2.isErr == true
|
||||
res2.error == errors.OverrunError
|
||||
|
||||
test "[LibP2P] Buffer Incomplete edge cases test":
|
||||
var buffer = newSeq[byte]()
|
||||
var length = 0
|
||||
|
@ -179,6 +252,17 @@ suite "Variable integer test suite":
|
|||
check:
|
||||
LP.getUVarint(buffer, length, value) == VarintStatus.Incomplete
|
||||
|
||||
buffer.setLen(LPedgeSizes[i])
|
||||
zeroMem(addr buffer[0], len(buffer))
|
||||
|
||||
check:
|
||||
LP.putUVarint(buffer, LPedgeValues[i]).isOk == true
|
||||
buffer.setLen(len(buffer) - 1)
|
||||
let res = LP.getUVarint(buffer)
|
||||
check:
|
||||
res.isErr == true
|
||||
res.error == errors.IncompleteError
|
||||
|
||||
test "[LibP2P] Integer Overflow 32bit test":
|
||||
var buffer = newSeq[byte]()
|
||||
var length = 0
|
||||
|
@ -204,6 +288,17 @@ suite "Variable integer test suite":
|
|||
check:
|
||||
LP.getUVarint(buffer, length, value) == VarintStatus.Overflow
|
||||
|
||||
buffer.setLen(LPedgeSizes[i] + 1)
|
||||
zeroMem(addr buffer[0], len(buffer))
|
||||
check:
|
||||
LP.putUVarint(buffer, LPedgeValues[i]).isOk == true
|
||||
buffer[8] = buffer[9] or 0x80'u8
|
||||
buffer[9] = 0x01'u8
|
||||
let res = LP.getUVarint(buffer)
|
||||
check:
|
||||
res.isErr == true
|
||||
res.error == errors.OverflowError
|
||||
|
||||
test "[LibP2P] Over 63bit test":
|
||||
var buffer = newSeq[byte](10)
|
||||
var length = 0
|
||||
|
@ -214,3 +309,12 @@ suite "Variable integer test suite":
|
|||
0x8000_0000_0000_0000'u64) == VarintStatus.Overflow
|
||||
LP.putUVarint(buffer, length,
|
||||
0xFFFF_FFFF_FFFF_FFFF'u64) == VarintStatus.Overflow
|
||||
let r1 = LP.putUVarint(buffer, 0x7FFF_FFFF_FFFF_FFFF'u64)
|
||||
let r2 = LP.putUVarint(buffer, 0x8000_0000_0000_0000'u64)
|
||||
let r3 = LP.putUVarint(buffer, 0xFFFF_FFFF_FFFF_FFFF'u64)
|
||||
check:
|
||||
r1.isOk == true
|
||||
r2.isErr == true
|
||||
r3.isErr == true
|
||||
r2.error == errors.OverflowError
|
||||
r3.error == errors.OverflowError
|
||||
|
|
Loading…
Reference in New Issue