1use hybrid_array::{
2 sizes::{U0, U1, U256},
3 typenum::{IsLess, NonZero, True, Unsigned},
4};
5
6use super::{Array, ArraySize};
7use core::{mem::MaybeUninit, ptr};
8
9type Block<N> = MaybeUninit<Array<u8, N>>;
10
11pub trait Sealed {
13 #[cfg(not(feature = "zeroize"))]
14 type Pos: Default + Clone;
15 #[cfg(feature = "zeroize")]
16 type Pos: Default + Clone + zeroize::Zeroize;
17
18 type Overhead: ArraySize;
19
20 const NAME: &'static str;
21
22 fn get_pos<N: ArraySize>(buf: &Block<N>, pos: &Self::Pos) -> usize;
23
24 fn set_pos<N: ArraySize>(buf: &mut Block<N>, pos: &mut Self::Pos, val: usize);
25
26 fn invariant(pos: usize, block_size: usize) -> bool;
29
30 fn split_blocks<N: ArraySize>(data: &[u8]) -> (&[Array<u8, N>], &[u8]);
32}
33
34impl Sealed for super::Eager {
35 type Pos = ();
36 type Overhead = U0;
37 const NAME: &'static str = "BlockBuffer<Eager>";
38
39 fn get_pos<N: ArraySize>(buf: &Block<N>, _pos: &Self::Pos) -> usize {
40 let pos = unsafe {
42 let buf_ptr = buf.as_ptr().cast::<u8>();
43 let last_byte_ptr = buf_ptr.add(N::USIZE - 1);
44 ptr::read(last_byte_ptr)
45 };
46 pos as usize
47 }
48
49 #[allow(clippy::cast_possible_truncation)]
50 fn set_pos<N: ArraySize>(buf: &mut Block<N>, _pos: &mut Self::Pos, val: usize) {
51 debug_assert!(u8::try_from(val).is_ok());
52 unsafe {
54 let buf_ptr = buf.as_mut_ptr().cast::<u8>();
55 let last_byte_ptr = buf_ptr.add(N::USIZE - 1);
56 ptr::write(last_byte_ptr, val as u8);
57 }
58 }
59
60 #[inline(always)]
61 fn invariant(pos: usize, block_size: usize) -> bool {
62 pos < block_size
63 }
64
65 #[inline(always)]
66 fn split_blocks<N: ArraySize>(data: &[u8]) -> (&[Array<u8, N>], &[u8]) {
67 Array::slice_as_chunks(data)
68 }
69}
70
71impl Sealed for super::Lazy {
72 type Pos = u8;
73 type Overhead = U1;
74 const NAME: &'static str = "BlockBuffer<Lazy>";
75
76 fn get_pos<N: ArraySize>(_buf_val: &Block<N>, pos: &Self::Pos) -> usize {
77 *pos as usize
78 }
79
80 #[allow(clippy::cast_possible_truncation)]
81 fn set_pos<N: ArraySize>(_: &mut Block<N>, pos: &mut Self::Pos, val: usize) {
82 debug_assert!(u8::try_from(val).is_ok());
83 *pos = val as u8;
84 }
85
86 #[inline(always)]
87 fn invariant(pos: usize, block_size: usize) -> bool {
88 pos <= block_size
89 }
90
91 #[inline(always)]
92 fn split_blocks<N: ArraySize>(data: &[u8]) -> (&[Array<u8, N>], &[u8]) {
93 let (blocks, tail) = Array::slice_as_chunks(data);
94 if data.is_empty() || !tail.is_empty() {
95 (blocks, tail)
96 } else {
97 let (tail, blocks) = blocks.split_last().expect("`blocks` can not be empty");
98 (blocks, tail)
99 }
100 }
101}
102
103pub trait BlockSizes {}
105
106impl<T: Unsigned> BlockSizes for T where Self: IsLess<U256, Output = True> + NonZero {}