diff --git a/constantine/io.nim b/constantine/io.nim index 83c5b74..faf1a9f 100644 --- a/constantine/io.nim +++ b/constantine/io.nim @@ -75,12 +75,11 @@ func readDecChar(c: range['0'..'9']): int {.inline.}= # # ############################################################ -func parseRawUint*( +func parseRawUintLE( src: openarray[byte], - bits: static int, - endian: static Endianness): BigInt[bits] = + bits: static int): BigInt[bits] {.inline.}= ## Parse an unsigned integer from its canonical - ## big-endian or little-endian unsigned representation + ## little-endian unsigned representation ## And store it into a BigInt of size bits ## ## CT: @@ -91,28 +90,39 @@ func parseRawUint*( acc = Word(0) acc_len = 0 - template body(){.dirty.} = + for src_idx in 0 ..< src.len: let src_byte = Word(src[src_idx]) - acc = acc and (src_byte shl acc_len) + # buffer reads + acc = acc or (src_byte shl acc_len) acc_len += 8 # We count bit by bit + # if full, dump if acc_len >= WordBitSize: result[dst_idx] = acc and MaxWord inc dst_idx acc_len -= WordBitSize acc = src_byte shr (8 - acc_len) - when endian == bigEndian: - for src_idx in countdown(src.high, 0): - body() - else: - for src_idx in 0 ..< src.len: - body() - if acc_len != 0: result[dst_idx] = acc +func parseRawUint*( + src: openarray[byte], + bits: static int, + order: static Endianness): BigInt[bits] = + ## Parse an unsigned integer from its canonical + ## big-endian or little-endian unsigned representation + ## And store it into a BigInt of size bits + ## + ## CT: + ## - no leaks + + when order == littleEndian: + parseRawUintLE(src, bits) + else: + {.error: "Not implemented at the moment".} + # ############################################################ # # Serialising from internal representation to canonical format diff --git a/tests/test_io.nim b/tests/test_io.nim index 99c38e9..b3508e0 100644 --- a/tests/test_io.nim +++ b/tests/test_io.nim @@ -31,8 +31,9 @@ suite "IO": T(big[0]) == 0 T(big[1]) == 1 - test "Parsing and dumping round-trip": - block: # "Little-endian" + test "Parsing and dumping round-trip on uint64": + block: + # "Little-endian" - 2^63 let x = 1'u64 shl 63 let x_bytes = cast[array[8, byte]](x) let big = parseRawUint(x_bytes, 64, littleEndian) # It's fine even on big-endian platform. We only want the byte-pattern @@ -41,11 +42,21 @@ suite "IO": dumpRawUint(r_bytes, big, littleEndian) check: x_bytes == r_bytes - # block: # "Little-endian" - # let x = uint64 rand(0..high(int)) - # let x_bytes = cast[array[8, byte]](x) - # let big = parseRawUint(x_bytes, 64, littleEndian) # It's fine even on big-endian platform. We only want the byte-pattern + block: # "Little-endian" - single random + let x = uint64 rand(0..high(int)) + let x_bytes = cast[array[8, byte]](x) + let big = parseRawUint(x_bytes, 64, littleEndian) # It's fine even on big-endian platform. We only want the byte-pattern - # var r_bytes: array[8, byte] - # dumpRawUint(r_bytes, big, littleEndian) - # check: x_bytes == r_bytes + var r_bytes: array[8, byte] + dumpRawUint(r_bytes, big, littleEndian) + check: x_bytes == r_bytes + + block: # "Little-endian" - 10 random cases + for _ in 0 ..< 10: + let x = uint64 rand(0..high(int)) + let x_bytes = cast[array[8, byte]](x) + let big = parseRawUint(x_bytes, 64, littleEndian) # It's fine even on big-endian platform. We only want the byte-pattern + + var r_bytes: array[8, byte] + dumpRawUint(r_bytes, big, littleEndian) + check: x_bytes == r_bytes