1use super::{Array, BlockSizes, Error};
2use core::fmt;
3
4pub struct ReadBuffer<BS: BlockSizes> {
6 buffer: Array<u8, BS>,
10}
11
12impl<BS: BlockSizes> fmt::Debug for ReadBuffer<BS> {
13 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
14 f.debug_struct("ReadBuffer")
15 .field("remaining_data", &self.remaining())
16 .finish_non_exhaustive()
17 }
18}
19
20impl<BS: BlockSizes> Default for ReadBuffer<BS> {
21 #[inline]
22 fn default() -> Self {
23 let buffer = Default::default();
24 let mut res = Self { buffer };
25 unsafe { res.set_pos_unchecked(BS::USIZE) };
27 res
28 }
29}
30
31impl<BS: BlockSizes> Clone for ReadBuffer<BS> {
32 #[inline]
33 fn clone(&self) -> Self {
34 let buffer = self.buffer.clone();
35 Self { buffer }
36 }
37}
38
39impl<BS: BlockSizes> ReadBuffer<BS> {
40 #[inline(always)]
42 pub fn get_pos(&self) -> usize {
43 let pos = self.buffer[0];
44 if pos == 0 || pos > BS::U8 {
45 debug_assert!(false);
46 unsafe {
48 core::hint::unreachable_unchecked();
49 }
50 }
51 pos as usize
52 }
53
54 #[inline(always)]
56 pub fn size(&self) -> usize {
57 BS::USIZE
58 }
59
60 #[inline(always)]
62 pub fn remaining(&self) -> usize {
63 self.size() - self.get_pos()
64 }
65
66 #[inline(always)]
71 #[allow(clippy::cast_possible_truncation)]
72 unsafe fn set_pos_unchecked(&mut self, pos: usize) {
73 debug_assert!(pos != 0 && pos <= BS::USIZE);
74 self.buffer[0] = pos as u8;
75 }
76
77 #[inline(always)]
82 pub fn read_cached(&mut self, len: usize) -> &[u8] {
83 let rem = self.remaining();
84 let new_len = core::cmp::min(rem, len);
85 let pos = self.get_pos();
86
87 unsafe { self.set_pos_unchecked(pos + new_len) };
89 &self.buffer[pos..][..new_len]
90 }
91
92 #[inline(always)]
102 pub fn write_block(
103 &mut self,
104 read_len: usize,
105 gen_block: impl FnOnce(&mut Array<u8, BS>),
106 read_fn: impl FnOnce(&[u8]),
107 ) {
108 if read_len == 0 {
109 return;
110 }
111 assert!(read_len < BS::USIZE);
112
113 let g = ResetGuard(self);
114 let buf = &mut g.0.buffer;
115
116 gen_block(buf);
120 read_fn(&buf[..read_len]);
121
122 core::mem::forget(g);
123
124 unsafe { self.set_pos_unchecked(read_len) };
126 }
127
128 pub fn reset(&mut self) {
130 self.buffer[0] = BS::U8;
131 }
132
133 #[inline]
137 pub fn read(&mut self, buf: &mut [u8], mut gen_block: impl FnMut(&mut Array<u8, BS>)) {
138 let head_ks = self.read_cached(buf.len());
139 let (head, buf) = buf.split_at_mut(head_ks.len());
140 let (blocks, tail) = Array::slice_as_chunks_mut(buf);
141
142 head.copy_from_slice(head_ks);
143 for block in blocks {
144 gen_block(block);
145 }
146
147 self.write_block(tail.len(), gen_block, |tail_ks| {
148 tail.copy_from_slice(tail_ks);
149 });
150 }
151
152 #[inline]
154 pub fn serialize(&self) -> Array<u8, BS> {
155 let pos = self.get_pos();
156 let mut res = self.buffer.clone();
157 for b in &mut res[1..pos] {
159 *b = 0;
160 }
161 res
162 }
163
164 #[inline]
170 pub fn deserialize(buffer: &Array<u8, BS>) -> Result<Self, Error> {
171 let pos = usize::from(buffer[0]);
172 if pos == 0 || pos > BS::USIZE || buffer[1..pos].iter().any(|&b| b != 0) {
173 Err(Error)
174 } else {
175 let buffer = buffer.clone();
176 Ok(Self { buffer })
177 }
178 }
179}
180
181#[cfg(feature = "zeroize")]
182impl<BS: BlockSizes> Drop for ReadBuffer<BS> {
183 fn drop(&mut self) {
184 use zeroize::Zeroize;
185 self.buffer.zeroize();
186 }
187}
188
189#[cfg(feature = "zeroize")]
190impl<BS: BlockSizes> zeroize::ZeroizeOnDrop for ReadBuffer<BS> {}
191
192struct ResetGuard<'a, BS: BlockSizes>(&'a mut ReadBuffer<BS>);
194
195impl<BS: BlockSizes> Drop for ResetGuard<'_, BS> {
196 fn drop(&mut self) {
197 self.0.reset();
198 }
199}