use super::{HeaplessBigInt, zero};
use crate::MachineWord;
use const_num_traits::{ByteSliceError, ByteSliceErrorKind, FromByteSlice, Personality};
use core::marker::PhantomData;
#[inline]
fn read_be_word<T: MachineWord>(bytes: &[u8]) -> T {
let mut val = zero::<T>();
let mut first = true;
for &b in bytes {
if !first {
val <<= 8;
}
val |= <T as From<u8>>::from(b);
first = false;
}
val
}
#[inline]
fn read_le_word<T: MachineWord>(bytes: &[u8]) -> T {
let mut val = zero::<T>();
let mut shift = 0;
for &b in bytes {
val |= <T as From<u8>>::from(b) << shift;
shift += 8;
}
val
}
impl<T: MachineWord, const CAP: usize, P: Personality> HeaplessBigInt<T, CAP, P> {
pub fn to_be_bytes<'a>(&self, out: &'a mut [u8]) -> &'a [u8] {
let word_size = core::mem::size_of::<T>();
let byte_count = self.len as usize * word_size;
assert!(
out.len() >= byte_count,
"HeaplessBigInt::to_be_bytes: out.len() < required ({byte_count} bytes)"
);
for (chunk, word) in out[..byte_count]
.chunks_exact_mut(word_size)
.zip(self.limbs[..self.len as usize].iter().rev())
{
let word_bytes = word.to_be_bytes();
for (dst, src) in chunk.iter_mut().zip(word_bytes.as_ref()) {
*dst = *src;
}
}
&out[..byte_count]
}
pub fn to_le_bytes<'a>(&self, out: &'a mut [u8]) -> &'a [u8] {
let word_size = core::mem::size_of::<T>();
let byte_count = self.len as usize * word_size;
assert!(
out.len() >= byte_count,
"HeaplessBigInt::to_le_bytes: out.len() < required ({byte_count} bytes)"
);
for (chunk, word) in out[..byte_count]
.chunks_exact_mut(word_size)
.zip(self.limbs[..self.len as usize].iter())
{
let word_bytes = word.to_le_bytes();
for (dst, src) in chunk.iter_mut().zip(word_bytes.as_ref()) {
*dst = *src;
}
}
&out[..byte_count]
}
pub fn from_be_bytes(bytes: &[u8]) -> Self {
let word_size = core::mem::size_of::<T>();
let max_bytes = CAP * word_size;
assert!(
bytes.len() <= max_bytes,
"HeaplessBigInt::from_be_bytes: input {} bytes > CAP * word_size ({max_bytes})",
bytes.len()
);
let byte_count = bytes.len();
let out_len = byte_count.div_ceil(word_size);
let mut limbs = [zero::<T>(); CAP];
let mut hi = byte_count;
let mut word_idx = 0;
while hi > 0 {
let take = core::cmp::min(word_size, hi);
let lo = hi - take;
limbs[word_idx] = read_be_word::<T>(&bytes[lo..hi]);
word_idx += 1;
hi = lo;
}
Self {
limbs,
len: out_len as u16,
_p: PhantomData,
}
}
pub fn from_le_bytes(bytes: &[u8]) -> Self {
let word_size = core::mem::size_of::<T>();
let max_bytes = CAP * word_size;
assert!(
bytes.len() <= max_bytes,
"HeaplessBigInt::from_le_bytes: input {} bytes > CAP * word_size ({max_bytes})",
bytes.len()
);
let byte_count = bytes.len();
let out_len = byte_count.div_ceil(word_size);
let mut limbs = [zero::<T>(); CAP];
let mut offset = 0;
let mut word_idx = 0;
while offset < byte_count {
let take = core::cmp::min(word_size, byte_count - offset);
limbs[word_idx] = read_le_word::<T>(&bytes[offset..offset + take]);
word_idx += 1;
offset += take;
}
Self {
limbs,
len: out_len as u16,
_p: PhantomData,
}
}
}
impl<T: MachineWord, const CAP: usize, P: Personality> HeaplessBigInt<T, CAP, P> {
#[inline]
fn check_slice_len(len: usize) -> Result<(), ByteSliceError> {
if len == 0 {
return Err(ByteSliceError {
kind: ByteSliceErrorKind::Empty,
});
}
if len > CAP * core::mem::size_of::<T>() {
return Err(ByteSliceError {
kind: ByteSliceErrorKind::Overflow,
});
}
Ok(())
}
}
impl<T: MachineWord, const CAP: usize, P: Personality> FromByteSlice for HeaplessBigInt<T, CAP, P> {
fn from_be_slice(bytes: &[u8]) -> Result<Self, ByteSliceError> {
Self::check_slice_len(bytes.len())?;
Ok(Self::from_be_bytes(bytes))
}
fn from_le_slice(bytes: &[u8]) -> Result<Self, ByteSliceError> {
Self::check_slice_len(bytes.len())?;
Ok(Self::from_le_bytes(bytes))
}
}