#![allow(clippy::let_unit_value)]
use super::{FixedUInt, MachineWord, impl_from_be_bytes_slice, impl_from_le_bytes_slice};
use const_num_traits::Personality;
trait AssertBufferFits<const M: usize> {
const CHECK: ();
}
impl<T: MachineWord, const N: usize, P: Personality, const M: usize> AssertBufferFits<M>
for FixedUInt<T, N, P>
{
const CHECK: () = assert!(
M >= Self::BYTE_WIDTH,
"*_bytes_fixed: buffer size M must be >= FixedUInt::BYTE_WIDTH (= N * size_of::<T>())",
);
}
impl<T: MachineWord, const N: usize, P: Personality> FixedUInt<T, N, P> {
#[inline]
pub fn to_le_bytes_fixed<'a, const M: usize>(&self, out: &'a mut [u8; M]) -> &'a [u8] {
let _ = <Self as AssertBufferFits<M>>::CHECK;
let word_size = Self::WORD_SIZE;
for (chunk, word) in out.chunks_exact_mut(word_size).zip(self.array.iter()) {
chunk.copy_from_slice(word.to_le_bytes().as_ref());
}
&out[..Self::BYTE_WIDTH]
}
#[inline]
pub fn to_be_bytes_fixed<'a, const M: usize>(&self, out: &'a mut [u8; M]) -> &'a [u8] {
let _ = <Self as AssertBufferFits<M>>::CHECK;
let word_size = Self::WORD_SIZE;
let start = M - Self::BYTE_WIDTH;
for (chunk, word) in out[start..]
.chunks_exact_mut(word_size)
.zip(self.array.iter().rev())
{
chunk.copy_from_slice(word.to_be_bytes().as_ref());
}
&out[start..]
}
#[inline]
pub fn from_le_bytes_fixed<const M: usize>(bytes: &[u8; M]) -> Self {
let _ = <Self as AssertBufferFits<M>>::CHECK;
Self::from_array(impl_from_le_bytes_slice::<T, N>(bytes))
}
#[inline]
pub fn from_be_bytes_fixed<const M: usize>(bytes: &[u8; M]) -> Self {
let _ = <Self as AssertBufferFits<M>>::CHECK;
Self::from_array(impl_from_be_bytes_slice::<T, N>(bytes))
}
}
#[cfg(test)]
mod tests {
use super::*;
type U16 = FixedUInt<u8, 2>;
type U32 = FixedUInt<u32, 1>; type U64 = FixedUInt<u32, 2>;
#[test]
fn to_le_bytes_fixed_exact_size_round_trips() {
let v = U16::from(0x1234u16);
let mut buf = [0u8; U16::BYTE_WIDTH];
let written = v.to_le_bytes_fixed(&mut buf);
assert_eq!(written, &[0x34, 0x12]);
assert_eq!(buf, [0x34, 0x12]);
}
#[test]
fn to_le_bytes_fixed_oversized_leaves_trailing_untouched() {
let v = U16::from(0x1234u16);
let mut buf = [0xFFu8; 4];
let written = v.to_le_bytes_fixed(&mut buf);
assert_eq!(written, &[0x34, 0x12]);
assert_eq!(buf, [0x34, 0x12, 0xFF, 0xFF]);
}
#[test]
fn to_le_bytes_fixed_matches_slice_method() {
let v = U64::from_array([0xDEADBEEFu32, 0xCAFEBABEu32]);
let mut a = [0u8; U64::BYTE_WIDTH];
let mut b = [0u8; U64::BYTE_WIDTH];
let fixed = v.to_le_bytes_fixed(&mut a);
let slice = v.to_le_bytes(&mut b).unwrap();
assert_eq!(fixed, slice);
}
#[test]
fn to_be_bytes_fixed_exact_size_round_trips() {
let v = U16::from(0x1234u16);
let mut buf = [0u8; U16::BYTE_WIDTH];
let written = v.to_be_bytes_fixed(&mut buf);
assert_eq!(written, &[0x12, 0x34]);
assert_eq!(buf, [0x12, 0x34]);
}
#[test]
fn to_be_bytes_fixed_matches_slice_method() {
let v = U64::from_array([0xDEADBEEFu32, 0xCAFEBABEu32]);
let mut a = [0u8; U64::BYTE_WIDTH];
let mut b = [0u8; U64::BYTE_WIDTH];
let fixed = v.to_be_bytes_fixed(&mut a);
let slice = v.to_be_bytes(&mut b).unwrap();
assert_eq!(fixed, slice);
}
#[test]
fn to_be_bytes_fixed_oversized_writes_trailing_window() {
let v = U16::from(0x1234u16);
let mut buf = [0xFFu8; 4];
let written = v.to_be_bytes_fixed(&mut buf);
assert_eq!(written, &[0x12, 0x34]);
assert_eq!(buf, [0xFF, 0xFF, 0x12, 0x34]);
}
#[test]
fn to_be_fixed_from_be_fixed_round_trip_oversized() {
let v = U16::from(0x1234u16);
let mut buf = [0u8; 4];
let _ = v.to_be_bytes_fixed(&mut buf);
let back: U16 = U16::from_be_bytes_fixed(&buf);
assert_eq!(back, v);
}
#[test]
fn from_le_bytes_fixed_exact_size() {
let buf = [0x34u8, 0x12];
let v: U16 = U16::from_le_bytes_fixed(&buf);
assert_eq!(v, U16::from(0x1234u16));
}
#[test]
fn from_le_bytes_fixed_oversized_takes_low_bytes() {
let buf = [0x34u8, 0x12, 0xFF, 0xFF];
let v: U16 = U16::from_le_bytes_fixed(&buf);
assert_eq!(v, U16::from(0x1234u16));
}
#[test]
fn from_le_bytes_fixed_matches_slice_method() {
let buf = [0xEF, 0xBE, 0xAD, 0xDE, 0xBE, 0xBA, 0xFE, 0xCA];
let fixed: U64 = U64::from_le_bytes_fixed(&buf);
let slice: U64 = U64::from_le_bytes(&buf[..]);
assert_eq!(fixed, slice);
}
#[test]
fn from_be_bytes_fixed_exact_size() {
let buf = [0x12u8, 0x34];
let v: U16 = U16::from_be_bytes_fixed(&buf);
assert_eq!(v, U16::from(0x1234u16));
}
#[test]
fn from_be_bytes_fixed_oversized_takes_trailing_bytes() {
let buf = [0xFFu8, 0xFF, 0x12, 0x34];
let v: U16 = U16::from_be_bytes_fixed(&buf);
assert_eq!(v, U16::from(0x1234u16));
}
#[test]
fn from_be_bytes_fixed_matches_slice_method() {
let buf = [0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE];
let fixed: U64 = U64::from_be_bytes_fixed(&buf);
let slice: U64 = U64::from_be_bytes(&buf[..]);
assert_eq!(fixed, slice);
}
#[test]
fn round_trip_le_fixed() {
let original = U64::from_array([0xDEADBEEFu32, 0xCAFEBABEu32]);
let mut buf = [0u8; U64::BYTE_WIDTH];
let _ = original.to_le_bytes_fixed(&mut buf);
let back: U64 = U64::from_le_bytes_fixed(&buf);
assert_eq!(back, original);
}
#[test]
fn round_trip_be_fixed() {
let original = U64::from_array([0xDEADBEEFu32, 0xCAFEBABEu32]);
let mut buf = [0u8; U64::BYTE_WIDTH];
let _ = original.to_be_bytes_fixed(&mut buf);
let back: U64 = U64::from_be_bytes_fixed(&buf);
assert_eq!(back, original);
}
#[test]
fn u32_single_limb_le() {
let v = U32::from(0x12345678u32);
let mut buf = [0u8; U32::BYTE_WIDTH];
let written = v.to_le_bytes_fixed(&mut buf);
assert_eq!(written, &[0x78, 0x56, 0x34, 0x12]);
let back: U32 = U32::from_le_bytes_fixed(&buf);
assert_eq!(back, v);
}
#[test]
fn u32_single_limb_be() {
let v = U32::from(0x12345678u32);
let mut buf = [0u8; U32::BYTE_WIDTH];
let written = v.to_be_bytes_fixed(&mut buf);
assert_eq!(written, &[0x12, 0x34, 0x56, 0x78]);
let back: U32 = U32::from_be_bytes_fixed(&buf);
assert_eq!(back, v);
}
#[test]
fn byte_width_is_usable_as_array_length() {
const BUF_LEN: usize = U64::BYTE_WIDTH;
let mut buf = [0u8; BUF_LEN];
let v = U64::from(42u32);
let _ = v.to_le_bytes_fixed(&mut buf);
assert_eq!(buf[0], 42);
}
}