use core::convert::TryFrom;
use core::{mem::size_of, ptr};
#[inline]
pub(crate) fn write_u64_le(dst: &mut [u8], input: u64) {
*<&mut [u8; 8]>::try_from(dst).unwrap() = input.to_le_bytes();
}
#[inline]
pub(crate) fn write_u32_le(dst: &mut [u8], input: u32) {
*<&mut [u8; 4]>::try_from(dst).unwrap() = input.to_le_bytes();
}
#[inline]
pub(crate) fn write_u32_be(dst: &mut [u8], input: u32) {
*<&mut [u8; 4]>::try_from(dst).unwrap() = input.to_be_bytes();
}
macro_rules! write_array_type {
($C: ident, $T: ident, $F: ident) => {
pub fn $C(dst: &mut [u8], input: &[$T]) {
const SZ: usize = size_of::<$T>();
assert!(dst.len() == SZ * input.len());
let mut offset = 0;
for v in input.iter() {
match <&mut [u8; SZ]>::try_from(&mut dst[offset..offset + SZ]) {
Ok(t) => *t = v.$F(),
Err(_) => unsafe { core::hint::unreachable_unchecked() },
}
offset += SZ;
}
}
};
}
write_array_type!(write_u64v_le, u64, to_le_bytes);
write_array_type!(write_u64v_be, u64, to_be_bytes);
write_array_type!(write_u32v_le, u32, to_le_bytes);
write_array_type!(write_u32v_be, u32, to_be_bytes);
macro_rules! read_array_type {
($C: ident, $T: ident, $F: ident) => {
pub fn $C(dst: &mut [$T], input: &[u8]) {
const SZ: usize = size_of::<$T>();
assert!(dst.len() * SZ == input.len());
unsafe {
let mut x: *mut $T = dst.get_unchecked_mut(0);
let mut y: *const u8 = input.get_unchecked(0);
for _ in 0..dst.len() {
let mut tmp = [0u8; SZ];
ptr::copy_nonoverlapping(y, &mut tmp as *mut _ as *mut u8, SZ);
*x = $T::$F(tmp);
x = x.add(1);
y = y.add(SZ);
}
}
}
};
}
read_array_type!(read_u64v_be, u64, from_be_bytes);
read_array_type!(read_u64v_le, u64, from_le_bytes);
read_array_type!(read_u32v_be, u32, from_be_bytes);
read_array_type!(read_u32v_le, u32, from_le_bytes);
pub fn read_u32_le(input: &[u8]) -> u32 {
let tmp: [u8; 4] = *<&[u8; 4]>::try_from(input).unwrap();
u32::from_le_bytes(tmp)
}
pub fn xor_keystream_mut(buf: &mut [u8], keystream: &[u8]) {
assert!(buf.len() <= keystream.len());
let k = keystream.as_ptr();
let d = buf.as_mut_ptr();
for i in 0isize..buf.len() as isize {
unsafe { *d.offset(i) = *d.offset(i) ^ *k.offset(i) };
}
}
pub fn xor_array64_mut<const N: usize>(lhs: &mut [u64; N], rhs: &[u64; N]) {
for (left, right) in lhs.iter_mut().zip(rhs.iter()) {
*left ^= *right
}
}
#[inline]
pub fn zero(dst: &mut [u8]) {
unsafe {
ptr::write_bytes(dst.as_mut_ptr(), 0, dst.len());
}
}
#[derive(Clone)]
pub(crate) struct FixedBuffer<const N: usize> {
buffer: [u8; N],
buffer_idx: usize,
}
impl<const N: usize> FixedBuffer<N> {
pub const fn new() -> Self {
Self {
buffer: [0u8; N],
buffer_idx: 0,
}
}
pub fn input<F: FnMut(&[u8])>(&mut self, input: &[u8], mut func: F) {
let mut i = 0;
if self.buffer_idx != 0 {
let buffer_remaining = N - self.buffer_idx;
if input.len() >= buffer_remaining {
self.buffer[self.buffer_idx..N].copy_from_slice(&input[..buffer_remaining]);
self.buffer_idx = 0;
func(&self.buffer);
i += buffer_remaining;
} else {
self.buffer[self.buffer_idx..self.buffer_idx + input.len()].copy_from_slice(&input);
self.buffer_idx += input.len();
return;
}
}
if input.len() - i >= N {
let remaining = input.len() - i;
let block_bytes = (remaining / N) * N;
func(&input[i..i + block_bytes]);
i += block_bytes;
}
let input_remaining = input.len() - i;
self.buffer[0..input_remaining].copy_from_slice(&input[i..]);
self.buffer_idx += input_remaining;
}
pub fn reset(&mut self) {
self.buffer_idx = 0;
}
fn zero_until(&mut self, idx: usize) {
assert!(idx >= self.buffer_idx);
zero(&mut self.buffer[self.buffer_idx..idx]);
self.buffer_idx = idx;
}
pub fn next<const I: usize>(&mut self) -> &mut [u8; I] {
let start = self.buffer_idx;
self.buffer_idx += I;
<&mut [u8; I]>::try_from(&mut self.buffer[start..self.buffer_idx]).unwrap()
}
pub fn full_buffer(&mut self) -> &[u8; N] {
assert!(self.buffer_idx == N);
self.buffer_idx = 0;
&self.buffer
}
pub fn standard_padding<F: FnMut(&[u8; N])>(&mut self, rem: usize, mut func: F) {
self.next::<1>()[0] = 128;
if (N - self.buffer_idx) < rem {
self.zero_until(N);
func(self.full_buffer());
}
self.zero_until(N - rem);
}
}