use super::{Array, ArraySize};
use core::{mem::MaybeUninit, ptr, slice};
type Block<N> = MaybeUninit<Array<u8, N>>;
pub trait Sealed {
#[cfg(not(feature = "zeroize"))]
type Pos: Default + Clone;
#[cfg(feature = "zeroize")]
type Pos: Default + Clone + zeroize::Zeroize;
const NAME: &'static str;
fn get_pos<N: ArraySize>(buf: &Block<N>, pos: &Self::Pos) -> usize;
fn set_pos<N: ArraySize>(buf: &mut Block<N>, pos: &mut Self::Pos, val: usize);
fn invariant(pos: usize, block_size: usize) -> bool;
fn split_blocks<N: ArraySize>(data: &[u8]) -> (&[Array<u8, N>], &[u8]);
}
impl Sealed for super::Eager {
type Pos = ();
const NAME: &'static str = "BlockBuffer<Eager>";
fn get_pos<N: ArraySize>(buf: &Block<N>, _pos: &Self::Pos) -> usize {
let pos = unsafe {
let buf_ptr = buf.as_ptr().cast::<u8>();
let last_byte_ptr = buf_ptr.add(N::USIZE - 1);
ptr::read(last_byte_ptr)
};
pos as usize
}
fn set_pos<N: ArraySize>(buf: &mut Block<N>, _pos: &mut Self::Pos, val: usize) {
debug_assert!(val <= u8::MAX as usize);
unsafe {
let buf_ptr = buf.as_mut_ptr().cast::<u8>();
let last_byte_ptr = buf_ptr.add(N::USIZE - 1);
ptr::write(last_byte_ptr, val as u8);
}
}
#[inline(always)]
fn invariant(pos: usize, block_size: usize) -> bool {
pos < block_size
}
#[inline(always)]
fn split_blocks<N: ArraySize>(data: &[u8]) -> (&[Array<u8, N>], &[u8]) {
let nb = data.len() / N::USIZE;
let blocks_len = nb * N::USIZE;
let tail_len = data.len() - blocks_len;
unsafe {
let blocks_ptr = data.as_ptr() as *const Array<u8, N>;
let tail_ptr = data.as_ptr().add(blocks_len);
(
slice::from_raw_parts(blocks_ptr, nb),
slice::from_raw_parts(tail_ptr, tail_len),
)
}
}
}
impl Sealed for super::Lazy {
type Pos = u8;
const NAME: &'static str = "BlockBuffer<Lazy>";
fn get_pos<N: ArraySize>(_buf_val: &Block<N>, pos: &Self::Pos) -> usize {
*pos as usize
}
fn set_pos<N: ArraySize>(_: &mut Block<N>, pos: &mut Self::Pos, val: usize) {
debug_assert!(val <= u8::MAX as usize);
*pos = val as u8;
}
#[inline(always)]
fn invariant(pos: usize, block_size: usize) -> bool {
pos <= block_size
}
#[inline(always)]
fn split_blocks<N: ArraySize>(data: &[u8]) -> (&[Array<u8, N>], &[u8]) {
if data.is_empty() {
return (&[], &[]);
}
let (nb, tail_len) = if data.len() % N::USIZE == 0 {
(data.len() / N::USIZE - 1, N::USIZE)
} else {
let nb = data.len() / N::USIZE;
(nb, data.len() - nb * N::USIZE)
};
let blocks_len = nb * N::USIZE;
unsafe {
let blocks_ptr = data.as_ptr() as *const Array<u8, N>;
let tail_ptr = data.as_ptr().add(blocks_len);
(
slice::from_raw_parts(blocks_ptr, nb),
slice::from_raw_parts(tail_ptr, tail_len),
)
}
}
}