///| Write bytes representation of an `Int` by specified endianness into target `FixedArray[Byte]` at certain offset.
///
/// # Panics
///
/// 4 bytes of data are required from offset position. Panics when insufficient.
pub fn int_into_bytes(
v : Int,
endian : Endianness,
target : FixedArray[Byte],
offset : Int
) -> Unit {
// assert_true!(offset + 4 <= target.length())
for bs = 0; bs < 4; bs = bs + 1 {
let bd = endianness_index(bs, 4, endian)
target[offset + bd] = ((v >> (bs << 3)) & 0xFF).to_byte()
}
}
///| Write bytes representation of an `Int` by little-endian into target `FixedArray[Byte]` at certain offset.
///
/// # Panics
///
/// 4 bytes of data are required from offset position. Panics when insufficient.
pub fn int_into_bytes_le(
v : Int,
target : FixedArray[Byte],
offset : Int
) -> Unit {
int_into_bytes(v, LittleEndian, target, offset)
}
///| Write bytes representation of an `Int` by big-endian into target `FixedArray[Byte]` at certain offset.
///
/// # Panics
///
/// 4 bytes of data are required from offset position. Panics when insufficient.
pub fn int_into_bytes_be(
v : Int,
target : FixedArray[Byte],
offset : Int
) -> Unit {
int_into_bytes(v, BigEndian, target, offset)
}
///|
test "int_into_bytes(series)" {
let cases : Array[
(Int, Int, FixedArray[Byte], FixedArray[Byte], FixedArray[Byte]),
] = [
(
0x07_06_05_04,
0,
FixedArray::from_array([0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc]),
FixedArray::from_array([0x04, 0x05, 0x06, 0x07, 0xcc, 0xcc]),
FixedArray::from_array([0x07, 0x06, 0x05, 0x04, 0xcc, 0xcc]),
),
(
0xff_0b_0c_0d,
1,
FixedArray::from_array([0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa]),
FixedArray::from_array([0xaa, 0x0d, 0x0c, 0x0b, 0xff, 0xaa]),
FixedArray::from_array([0xaa, 0xff, 0x0b, 0x0c, 0x0d, 0xaa]),
),
(
0x44_33_22_11,
2,
FixedArray::from_array([0xdf, 0xfd, 0xdf, 0xdf, 0xdf, 0xdf]),
FixedArray::from_array([0xdf, 0xfd, 0x11, 0x22, 0x33, 0x44]),
FixedArray::from_array([0xdf, 0xfd, 0x44, 0x33, 0x22, 0x11]),
),
]
for icase = 0; icase < cases.length(); icase = icase + 1 {
let (input, pos, original, le_expected, be_expected) = cases[icase]
let buffer = original.copy()
int_into_bytes(input, LittleEndian, buffer, pos)
test_bytes_eq(buffer, le_expected)
let buffer = original.copy()
int_into_bytes(input, BigEndian, buffer, pos)
test_bytes_eq(buffer, be_expected)
let buffer = original.copy()
int_into_bytes(input, NetworkEndian, buffer, pos)
test_bytes_eq(buffer, be_expected)
let buffer = original.copy()
int_into_bytes_le(input, buffer, pos)
test_bytes_eq(buffer, le_expected)
let buffer = original.copy()
int_into_bytes_be(input, buffer, pos)
test_bytes_eq(buffer, be_expected)
}
}
///| Get bytes representation of an `Int` by specified endianness.
pub fn int_to_bytes(v : Int, endian : Endianness) -> FixedArray[Byte] {
let ret : FixedArray[Byte] = FixedArray::make(4, 0)
int_into_bytes(v, endian, ret, 0)
ret
}
///| Get bytes representation of an `Int` by little-endian.
pub fn int_to_bytes_le(v : Int) -> FixedArray[Byte] {
let ret : FixedArray[Byte] = FixedArray::make(4, 0)
int_into_bytes(v, LittleEndian, ret, 0)
ret
}
///| Get bytes representation of an `Int` by big-endian.
pub fn int_to_bytes_be(v : Int) -> FixedArray[Byte] {
let ret : FixedArray[Byte] = FixedArray::make(4, 0)
int_into_bytes(v, BigEndian, ret, 0)
ret
}
///|
test "int_to_bytes(series)" {
let input = 0xff_0b_0c_0d
let le_expected = b"\x0d\x0c\x0b\xff".to_fixedarray()
let be_expected = b"\xff\x0b\x0c\x0d".to_fixedarray()
test_bytes_eq(int_to_bytes(input, LittleEndian), le_expected)
test_bytes_eq(int_to_bytes(input, BigEndian), be_expected)
test_bytes_eq(int_to_bytes(input, NetworkEndian), be_expected)
test_bytes_eq(int_to_bytes_le(input), le_expected)
test_bytes_eq(int_to_bytes_be(input), be_expected)
}
///| Extract an `Int` from certain position of `FixedArray[Byte]` by specified endianness.
///
/// # Panics
///
/// 4 bytes of data are required from offset position. Panics when insufficient.
pub fn int_from_bytes(
bytes : FixedArray[Byte],
offset : Int,
endian : Endianness,
source~ : SourceLoc = _
) -> Int {
if offset + 4 > bytes.length() {
abort("FAILED: \{source} `\{offset} + 4 <= \{bytes.length()}` is not true")
}
let mut r = 0
for bd = 0; bd < 4; bd = bd + 1 {
let bs = offset + endianness_index(bd, 4, endian)
r = r | ((bytes[bs].to_int() & 0xff) << (bd << 3))
}
r
}
///| Extract an `Int` from certain position of `FixedArray[Byte]` by little-endian.
///
/// # Panics
///
/// 4 bytes of data are required from offset position. Panics when insufficient.
pub fn int_le_from_bytes(bytes : FixedArray[Byte], offset : Int) -> Int {
int_from_bytes(bytes, offset, LittleEndian)
}
///| Extract an `Int` from certain position of `FixedArray[Byte]` by big-endian.
///
/// # Panics
///
/// 4 bytes of data are required from offset position. Panics when insufficient.
pub fn int_be_from_bytes(bytes : FixedArray[Byte], offset : Int) -> Int {
int_from_bytes(bytes, offset, BigEndian)
}
///|
test "int_from_bytes(series)" {
let input : FixedArray[Byte] = FixedArray::from_array([
0x7c, 0x47, 0x18, 0x49, 0xff, 0x6c,
])
let cases = [
(0, 0x49_18_47_7c, 0x7c_47_18_49),
(1, 0xff_49_18_47, 0x47_18_49_ff),
(2, 0x6c_ff_49_18, 0x18_49_ff_6c),
]
for icase = 0; icase < cases.length(); icase = icase + 1 {
let (pos, le_expected, be_expected) = cases[icase]
assert_eq(int_from_bytes(input, pos, LittleEndian), le_expected)
assert_eq(int_le_from_bytes(input, pos), le_expected)
assert_eq(int_from_bytes(input, pos, BigEndian), be_expected)
assert_eq(int_from_bytes(input, pos, NetworkEndian), be_expected)
assert_eq(int_be_from_bytes(input, pos), be_expected)
}
}
///|
fn test_bytes_eq(
l : FixedArray[Byte],
r : FixedArray[Byte],
source~ : SourceLoc = _
) -> Unit raise {
if l.length() == r.length() {
for i = 0; i < l.length(); i = i + 1 {
if l[i] != r[i] {
let msg = StringBuilder::new(size_hint=16)
msg.write_string("byte mismatch at \{i}: ")
msg.write_string(l[i].to_string())
msg.write_string(" != ")
msg.write_string(r[i].to_string())
msg.write_string(" (\{source})")
fail(msg.to_string())
}
}
} else {
let msg = StringBuilder::new(size_hint=16)
msg.write_string("length mismatch: ")
msg.write_string(l.length().to_string())
msg.write_string(" != ")
msg.write_string(r.length().to_string())
fail(msg.to_string())
}
}
///|
/// Converts a character representing a digit to its corresponding integer value.
///
/// Parameters:
///
/// * `char` : A character in the range '0' to '9'.
///
/// Returns the integer value of the digit.
///
/// Throws a panic error if the input character is not a valid digit.
///
/// Example:
///
/// ```moonbit
/// test "digit_2_int" {
/// inspect!(digit_2_int('5'), content="5")
/// inspect!(digit_2_int('0'), content="0")
/// }
///
/// test "panic digit_2_int/invalid_char" {
/// let _ = digit_2_int('a')
///
/// }
/// ```
pub fn digit_char_2_int(char : Char) -> Int {
if DEBUGGER && (char < '0' || char > '9') {
panic()
}
return char.to_int() - 0x30
}