diff --git a/stint/io.nim b/stint/io.nim index 5020545..7c1cfcb 100644 --- a/stint/io.nim +++ b/stint/io.nim @@ -300,6 +300,44 @@ func dumpHex*(x: Stint or StUint): string {.inline.}= # TODO: Have a default static argument in the previous proc. Currently we get # "Cannot evaluate at compile-time". +proc initFromBytesBE*[bits: static[int]](val: var Stuint[bits], ba: openarray[byte], allowPadding: static[bool] = true) = + ## Initializes a UInt[bits] value from a byte buffer storing a big-endian + ## representation of a number. + ## + ## If `allowPadding` is set to false, the input array must be exactly + ## (bits div 8) bytes long. Otherwise, it may be shorter and the remaining + ## bytes will be assumed to be zero. + + const N = bits div 8 + + when not allowPadding: + assert(ba.len == N) + else: + assert ba.len <= N + + {.pragma: restrict, codegenDecl: "$# __restrict $#".} + let r_ptr {.restrict.} = cast[ptr array[N, byte]](val.addr) + + when system.cpuEndian == bigEndian: + # TODO: due to https://github.com/status-im/nim-stint/issues/38 + # We can't cast a stack byte array to stuint with a convenient proc signature. + when allowPadding: + let baseIdx = N - val.len + for i, b in ba: r_ptr[baseIdx + i] = b + else: + for i, b in ba: r_ptr[i] = b + else: + when allowPadding: + let baseIdx = ba.len - 1 + for i, b in ba: r_ptr[baseIdx - i] = b + else: + for i, b in ba: r_ptr[N-1 - i] = b + +func fromBytesBE*(T: type Stuint, ba: openarray[byte], + allowPadding: static[bool] = true): T = + ## This function provides a convenience wrapper around `initFromBytesBE`. + result.initFromBytesBE(ba, allowPadding) + func readUintBE*[bits: static[int]](ba: openarray[byte]): Stuint[bits] = ## Convert a big-endian array of (bits div 8) Bytes to an UInt[bits] (in native host endianness) ## Input: @@ -308,19 +346,7 @@ func readUintBE*[bits: static[int]](ba: openarray[byte]): Stuint[bits] = ## - A unsigned integer of the same size with `bits` bits ## ## ⚠ If the openarray length is bigger than bits div 8, part converted is undefined behaviour. - - const N = bits div 8 - assert(ba.len == N) - - {.pragma: restrict, codegenDecl: "$# __restrict $#".} - let r_ptr {.restrict.} = cast[ptr array[N, byte]](result.addr) - for i, val in ba: - when system.cpuEndian == bigEndian: - # TODO: due to https://github.com/status-im/nim-stint/issues/38 - # We can't cast a stack byte array to stuint with a convenient proc signature. - r_ptr[i] = val - else: - r_ptr[N-1 - i] = val + result.initFromBytesBE(ba, false) func toByteArrayBE*[bits: static[int]](n: StUint[bits]): array[bits div 8, byte] = ## Convert a uint[bits] to to a big-endian array of bits div 8 bytes