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