use super::{impl_from_be_bytes_slice, impl_from_le_bytes_slice, FixedUInt, MachineWord};
use crate::const_numtraits::{ConstFromBytes, ConstToBytes};
use crate::machineword::ConstMachineWord;
use core::mem::size_of;
pub const fn byte_len<T, const N: usize>() -> usize {
N * size_of::<T>()
}
#[derive(Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Debug, Hash)]
pub struct ConstBytesHolder<const SIZE: usize> {
bytes: [u8; SIZE],
}
impl<const SIZE: usize> const Default for ConstBytesHolder<SIZE> {
fn default() -> Self {
Self { bytes: [0u8; SIZE] }
}
}
impl<const SIZE: usize> const From<[u8; SIZE]> for ConstBytesHolder<SIZE> {
fn from(bytes: [u8; SIZE]) -> Self {
Self { bytes }
}
}
impl<const SIZE: usize> const From<ConstBytesHolder<SIZE>> for [u8; SIZE] {
fn from(holder: ConstBytesHolder<SIZE>) -> Self {
holder.bytes
}
}
impl<const SIZE: usize> const AsRef<[u8]> for ConstBytesHolder<SIZE> {
fn as_ref(&self) -> &[u8] {
&self.bytes
}
}
impl<const SIZE: usize> const AsMut<[u8]> for ConstBytesHolder<SIZE> {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.bytes
}
}
impl<const SIZE: usize> core::borrow::Borrow<[u8]> for ConstBytesHolder<SIZE> {
fn borrow(&self) -> &[u8] {
&self.bytes
}
}
impl<const SIZE: usize> core::borrow::BorrowMut<[u8]> for ConstBytesHolder<SIZE> {
fn borrow_mut(&mut self) -> &mut [u8] {
&mut self.bytes
}
}
c0nst::c0nst! {
impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst ConstToBytes for FixedUInt<T, N>
where
[(); byte_len::<T, N>()]:,
{
type Bytes = ConstBytesHolder<{ byte_len::<T, N>() }>;
fn to_le_bytes(&self) -> Self::Bytes {
let mut result = ConstBytesHolder { bytes: [0u8; byte_len::<T, N>()] };
let word_size = size_of::<T>();
let mut i = 0;
while i < N {
let word_bytes = ConstToBytes::to_le_bytes(&self.array[i]);
let src = word_bytes.as_ref();
let mut j = 0;
while j < word_size {
result.bytes[i * word_size + j] = src[j];
j += 1;
}
i += 1;
}
result
}
fn to_be_bytes(&self) -> Self::Bytes {
let mut result = ConstBytesHolder { bytes: [0u8; byte_len::<T, N>()] };
let word_size = size_of::<T>();
let mut i = 0;
while i < N {
let word_idx = N - 1 - i;
let word_bytes = ConstToBytes::to_be_bytes(&self.array[word_idx]);
let src = word_bytes.as_ref();
let mut j = 0;
while j < word_size {
result.bytes[i * word_size + j] = src[j];
j += 1;
}
i += 1;
}
result
}
}
impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst ConstFromBytes for FixedUInt<T, N>
where
[(); byte_len::<T, N>()]:,
{
type Bytes = ConstBytesHolder<{ byte_len::<T, N>() }>;
fn from_le_bytes(bytes: &Self::Bytes) -> Self {
Self { array: impl_from_le_bytes_slice::<T, N>(bytes.as_ref()) }
}
fn from_be_bytes(bytes: &Self::Bytes) -> Self {
Self { array: impl_from_be_bytes_slice::<T, N>(bytes.as_ref()) }
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_const_to_le_bytes() {
let val: FixedUInt<u8, 4> = FixedUInt::from(0x04030201u32);
let bytes = ConstToBytes::to_le_bytes(&val);
assert_eq!(bytes.as_ref(), &[0x01, 0x02, 0x03, 0x04]);
}
#[test]
fn test_const_to_be_bytes() {
let val: FixedUInt<u8, 4> = FixedUInt::from(0x04030201u32);
let bytes = ConstToBytes::to_be_bytes(&val);
assert_eq!(bytes.as_ref(), &[0x04, 0x03, 0x02, 0x01]);
}
#[test]
fn test_const_to_bytes_u32_words() {
let val: FixedUInt<u32, 2> = FixedUInt {
array: [0x04030201, 0x08070605],
};
let le_bytes = ConstToBytes::to_le_bytes(&val);
assert_eq!(
le_bytes.as_ref(),
&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]
);
let be_bytes = ConstToBytes::to_be_bytes(&val);
assert_eq!(
be_bytes.as_ref(),
&[0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01]
);
}
const CONST_LE_BYTES: [u8; 4] = {
let val: FixedUInt<u8, 4> = FixedUInt {
array: [0x01, 0x02, 0x03, 0x04],
};
let holder = ConstToBytes::to_le_bytes(&val);
holder.bytes
};
#[test]
fn test_const_context() {
assert_eq!(CONST_LE_BYTES, [0x01, 0x02, 0x03, 0x04]);
}
#[test]
fn test_const_from_le_bytes() {
let bytes = ConstBytesHolder {
bytes: [0x01, 0x02, 0x03, 0x04],
};
let val: FixedUInt<u8, 4> = ConstFromBytes::from_le_bytes(&bytes);
assert_eq!(val.array, [0x01, 0x02, 0x03, 0x04]);
}
#[test]
fn test_const_from_be_bytes() {
let bytes = ConstBytesHolder {
bytes: [0x04, 0x03, 0x02, 0x01],
};
let val: FixedUInt<u8, 4> = ConstFromBytes::from_be_bytes(&bytes);
assert_eq!(val.array, [0x01, 0x02, 0x03, 0x04]);
}
#[test]
fn test_const_from_bytes_u32_words() {
let bytes = ConstBytesHolder {
bytes: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
};
let le_val: FixedUInt<u32, 2> = ConstFromBytes::from_le_bytes(&bytes);
assert_eq!(le_val.array, [0x04030201, 0x08070605]);
let be_bytes = ConstBytesHolder {
bytes: [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01],
};
let be_val: FixedUInt<u32, 2> = ConstFromBytes::from_be_bytes(&be_bytes);
assert_eq!(be_val.array, [0x04030201, 0x08070605]);
}
const CONST_FROM_LE: FixedUInt<u8, 4> = {
let bytes = ConstBytesHolder {
bytes: [0x01, 0x02, 0x03, 0x04],
};
ConstFromBytes::from_le_bytes(&bytes)
};
#[test]
fn test_const_from_bytes_context() {
assert_eq!(CONST_FROM_LE.array, [0x01, 0x02, 0x03, 0x04]);
}
#[test]
fn test_const_bytes_roundtrip() {
let original: FixedUInt<u32, 2> = FixedUInt {
array: [0x12345678, 0xDEADBEEF],
};
let le_bytes = ConstToBytes::to_le_bytes(&original);
let from_le: FixedUInt<u32, 2> = ConstFromBytes::from_le_bytes(&le_bytes);
assert_eq!(from_le.array, original.array);
let be_bytes = ConstToBytes::to_be_bytes(&original);
let from_be: FixedUInt<u32, 2> = ConstFromBytes::from_be_bytes(&be_bytes);
assert_eq!(from_be.array, original.array);
}
}