From 867739d2caf1e33c5f0e904947c639df46b5a443 Mon Sep 17 00:00:00 2001 From: jangko Date: Tue, 20 Jun 2023 19:45:49 +0700 Subject: [PATCH] more endians2 implementation and tests --- stint/io.nim | 78 ++++++++++++++++++++++++++++++++--- tests/test_conversion.nim | 1 - tests/test_int_endians2.nim | 80 ++++++++++++++++++++++++++++++++++++ tests/test_uint_endians2.nim | 52 ++++------------------- 4 files changed, 161 insertions(+), 50 deletions(-) create mode 100644 tests/test_int_endians2.nim diff --git a/stint/io.nim b/stint/io.nim index 1305927..2458102 100644 --- a/stint/io.nim +++ b/stint/io.nim @@ -378,19 +378,85 @@ func readUintBE*[bits: static[int]](ba: openArray[byte]): StUint[bits] {.noinit, result = (typeof result).fromBytesBE(ba) func toByteArrayBE*[bits: static[int]](n: StUint[bits]): array[bits div 8, byte] {.noinit, inline.}= - ## Convert a uint[bits] to to a big-endian array of bits div 8 bytes + ## Convert a Uint[bits] to to a big-endian array of bits div 8 bytes ## Input: ## - an unsigned integer ## Returns: ## - a big-endian array of the same size result = n.toBytesBE() -func fromBytesBE*(T: type StUint, ba: openArray[byte], allowPadding: static[bool] = true): T {.noinit, inline.}= +func fromBytesBE*(T: type StUint, ba: openArray[byte]): T {.noinit, inline.}= result = readUintBE[T.bits](ba) - #when allowPadding: - # result = result shl (((sizeof(T) - ba.len) * 8) - 1) -template initFromBytesBE*(x: var StUint, ba: openArray[byte], allowPadding: static[bool] = true) = - x = fromBytesBE(type x, ba, allowPadding) +template initFromBytesBE*(x: var StUint, ba: openArray[byte]) = + x = fromBytesBE(type x, ba) + +func readUintLE*[bits: static[int]](ba: openArray[byte]): StUint[bits] {.noinit, inline.}= + ## Convert a lettle-endian array of (bits div 8) Bytes to an UInt[bits] (in native host endianness) + ## Input: + ## - a little-endian openArray of size (bits div 8) at least + ## Returns: + ## - A unsigned integer of the same size with `bits` bits + result = (typeof result).fromBytesLE(ba) + +func toByteArrayLE*[bits: static[int]](n: StUint[bits]): array[bits div 8, byte] {.noinit, inline.}= + ## Convert a Uint[bits] to to a little-endian array of bits div 8 bytes + ## Input: + ## - an unsigned integer + ## Returns: + ## - a little-endian array of the same size + result = n.toBytesLE() + +func fromBytesLE*(T: type StUint, ba: openArray[byte]): T {.noinit, inline.}= + result = readUintLE[T.bits](ba) + +template initFromBytesLE*(x: var StUint, ba: openArray[byte]) = + x = fromBytesLE(type x, ba) + +#---------------Byte Serialization of Signed Integer --------------------------- + +func readIntBE*[bits: static[int]](ba: openArray[byte]): StInt[bits] {.noinit, inline.}= + ## Convert a big-endian array of (bits div 8) Bytes to an Int[bits] (in native host endianness) + ## Input: + ## - a big-endian openArray of size (bits div 8) at least + ## Returns: + ## - A signed integer of the same size with `bits` bits + result.impl = (typeof result.impl).fromBytesBE(ba) + +func toByteArrayBE*[bits: static[int]](n: StInt[bits]): array[bits div 8, byte] {.noinit, inline.}= + ## Convert a Int[bits] to to a big-endian array of bits div 8 bytes + ## Input: + ## - a signed integer + ## Returns: + ## - a big-endian array of the same size + result = n.impl.toBytesBE() + +func fromBytesBE*(T: type StInt, ba: openArray[byte]): T {.noinit, inline.}= + result = readIntBE[T.bits](ba) + +template initFromBytesBE*(x: var StInt, ba: openArray[byte]) = + x = fromBytesBE(type x, ba) + +func readIntLE*[bits: static[int]](ba: openArray[byte]): StInt[bits] {.noinit, inline.}= + ## Convert a lettle-endian array of (bits div 8) Bytes to an Int[bits] (in native host endianness) + ## Input: + ## - a little-endian openArray of size (bits div 8) at least + ## Returns: + ## - A signed integer of the same size with `bits` bits + result.impl = (typeof result.impl).fromBytesLE(ba) + +func toByteArrayLE*[bits: static[int]](n: StInt[bits]): array[bits div 8, byte] {.noinit, inline.}= + ## Convert a Int[bits] to to a little-endian array of bits div 8 bytes + ## Input: + ## - an signed integer + ## Returns: + ## - a little-endian array of the same size + result = n.impl.toBytesLE() + +func fromBytesLE*(T: type StInt, ba: openArray[byte]): T {.noinit, inline.}= + result = readIntLE[T.bits](ba) + +template initFromBytesLE*(x: var StInt, ba: openArray[byte]) = + x = fromBytesLE(type x, ba) {.pop.} diff --git a/tests/test_conversion.nim b/tests/test_conversion.nim index d4d82b4..0e57005 100644 --- a/tests/test_conversion.nim +++ b/tests/test_conversion.nim @@ -54,7 +54,6 @@ template chkStintToStuint(chk, handleErr: untyped, N, bits: static[int]) = template chkStintToStint(chk, handleErr: untyped, N, bits: static[int]) = block: - # TODO add low value tests if bug #92 fixed let y = stint(0, N) let z = stint(1, N) let v = stint(-1, N) diff --git a/tests/test_int_endians2.nim b/tests/test_int_endians2.nim new file mode 100644 index 0000000..595f3e9 --- /dev/null +++ b/tests/test_int_endians2.nim @@ -0,0 +1,80 @@ +# Stint +# Copyright 2018 Status Research & Development GmbH +# Licensed under either of +# +# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) +# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) +# +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +import ../stint, unittest, stew/byteutils, test_helpers + +template chkToBytesLE(chk: untyped, bits: int, hex: string) = + let x = fromHex(StInt[bits], hex) + chk toBytes(x, littleEndian).toHex() == x.dumpHex(littleEndian) + +template chkToBytesBE(chk: untyped, bits: int, hex: string) = + let x = fromHex(StInt[bits], hex) + chk toBytes(x, bigEndian).toHex() == x.dumpHex(bigEndian) + + +template chkFromBytesBE(chk: untyped, bits: int, hex: string) = + let x = fromHex(StInt[bits], hex) + let z = fromBytesBE(StInt[bits], toByteArrayBE(x)) + chk z == x + +template chkFromBytesLE(chk: untyped, bits: int, hex: string) = + let x = fromHex(StInt[bits], hex) + let z = fromBytesLE(StInt[bits], toByteArrayLE(x)) + chk z == x + +template chkEndians(chkFunc, tst, name: untyped) = + tst astToStr(name).substr(3): + name(chkFunc, 64, "abcdef1234567890") + name(chkFunc, 128, "abcdef1234567890abcdef1234567890") + name(chkFunc, 256, "abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890") + +template testEndians(chkFunc, tst: untyped) = + chkEndians(chkFunc, tst, chkToBytesLE) + chkEndians(chkFunc, tst, chkToBytesBE) + chkEndians(chkFunc, tst, chkFromBytesLE) + chkEndians(chkFunc, tst, chkFromBytesBE) + +static: + testEndians(ctCheck, ctTest) + +suite "Testing endians": + test "Endians give sane results": + + check: + 1.i128.toByteArrayBE() == + [0'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] + + 1.i128.toByteArrayLE() == + [1'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + + 1.i128 == Int128.fromBytesBE( + [0'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]) + + 1.i128 == Int128.fromBytesLE( + [1'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) + + -1.i128.toByteArrayBE() == + [255'u8, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255] + + -2.i128.toByteArrayBE() == + [255'u8, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254] + + -1.i128.toByteArrayLE() == + [255'u8, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255] + + -2.i128.toByteArrayLE() == + [254'u8, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255] + + -2.i128 == Int128.fromBytesBE( + [255'u8, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254]) + + -2.i128 == Int128.fromBytesLE( + [254'u8, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]) + + testEndians(check, test) diff --git a/tests/test_uint_endians2.nim b/tests/test_uint_endians2.nim index d9acc1f..a3f19bd 100644 --- a/tests/test_uint_endians2.nim +++ b/tests/test_uint_endians2.nim @@ -9,18 +9,6 @@ import ../stint, unittest, stew/byteutils, test_helpers - -template chkSwapBytes(chk: untyped, bits: int, hex: string) = - # dumpHex already do the job to swap the output if - # we use `littleEndian` on both platform - # bigEndian: B to B, B to L, L to B - # littleEndian: B to L, L to B, B to B - chk swapBytes(fromHex(StUint[bits], hex)).dumpHex(littleEndian) == hex - -template chkToBytes(chk: untyped, bits: int, hex: string) = - let x = fromHex(StUint[bits], hex) - chk toBytes(x).toHex() == x.dumpHex(system.cpuEndian) - template chkToBytesLE(chk: untyped, bits: int, hex: string) = let x = fromHex(StUint[bits], hex) chk toBytes(x, littleEndian).toHex() == x.dumpHex(littleEndian) @@ -29,10 +17,6 @@ template chkToBytesBE(chk: untyped, bits: int, hex: string) = let x = fromHex(StUint[bits], hex) chk toBytes(x, bigEndian).toHex() == x.dumpHex(bigEndian) -template chkFromBytes(chk: untyped, bits: int, hex: string) = - let x = fromHex(StUint[bits], hex) - let z = fromBytes(StUint[bits], toBytes(x)) - chk z == x template chkFromBytesBE(chk: untyped, bits: int, hex: string) = let x = fromHex(StUint[bits], hex) @@ -41,38 +25,20 @@ template chkFromBytesBE(chk: untyped, bits: int, hex: string) = template chkFromBytesLE(chk: untyped, bits: int, hex: string) = let x = fromHex(StUint[bits], hex) - let z = fromBytesLE(StUint[bits], toBytesLE(x)) - chk z == x - -template chkFromToLE(chk: untyped, bits: int, hex: string) = - let x = fromHex(StUint[bits], hex) - let z = x.fromLE.toLE - chk z == x - -template chkFromToBE(chk: untyped, bits: int, hex: string) = - let x = fromHex(StUint[bits], hex) - let z = x.fromBytesBE.toByteArrayBE + let z = fromBytesLE(StUint[bits], toByteArrayLE(x)) chk z == x template chkEndians(chkFunc, tst, name: untyped) = tst astToStr(name).substr(3): - #name(chkFunc, 8, "ab") - #name(chkFunc, 16, "abcd") - #name(chkFunc, 32, "abcdef12") - #name(chkFunc, 64, "abcdef1234567890") + name(chkFunc, 64, "abcdef1234567890") name(chkFunc, 128, "abcdef1234567890abcdef1234567890") name(chkFunc, 256, "abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890") template testEndians(chkFunc, tst: untyped) = - #chkEndians(chkFunc, tst, chkSwapBytes) - #chkEndians(chkFunc, tst, chkToBytes) - #chkEndians(chkFunc, tst, chkToBytesLE) + chkEndians(chkFunc, tst, chkToBytesLE) chkEndians(chkFunc, tst, chkToBytesBE) - #chkEndians(chkFunc, tst, chkFromBytes) - #chkEndians(chkFunc, tst, chkFromBytesLE) - #chkEndians(chkFunc, tst, chkFromBytesBE) - #chkEndians(chkFunc, tst, chkFromToLE) - #chkEndians(chkFunc, tst, chkFromToBE) + chkEndians(chkFunc, tst, chkFromBytesLE) + chkEndians(chkFunc, tst, chkFromBytesBE) static: testEndians(ctCheck, ctTest) @@ -84,13 +50,13 @@ suite "Testing endians": 1.u128.toByteArrayBE() == [0'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] - #1.u128.toBytesLE() == - # [1'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + 1.u128.toByteArrayLE() == + [1'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 1.u128 == UInt128.fromBytesBE( [0'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]) - #1.u128 == UInt128.fromBytesLE( - # [1'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) + 1.u128 == UInt128.fromBytesLE( + [1'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) testEndians(check, test)