nuclei/io/util/
read_buf.rs1use core::fmt;
6use core::mem::MaybeUninit;
7
8pub struct ReadBuf<'a> {
12 buf: &'a mut [MaybeUninit<u8>],
13 filled: usize,
14 initialized: usize,
15}
16
17impl<'a> ReadBuf<'a> {
18 pub fn new(buf: &'a mut [u8]) -> Self {
20 let initialized = buf.len();
21 let buf = unsafe { &mut *(core::ptr::from_mut::<[u8]>(buf) as *mut [MaybeUninit<u8>]) };
25 Self {
26 buf,
27 filled: 0,
28 initialized,
29 }
30 }
31
32 pub fn uninit(buf: &'a mut [MaybeUninit<u8>]) -> Self {
34 Self {
35 buf,
36 filled: 0,
37 initialized: 0,
38 }
39 }
40
41 pub fn capacity(&self) -> usize {
43 self.buf.len()
44 }
45
46 pub fn filled(&self) -> &[u8] {
48 unsafe { slice_assume_init(&self.buf[..self.filled]) }
51 }
52
53 pub fn filled_mut(&mut self) -> &mut [u8] {
55 unsafe { slice_assume_init_mut(&mut self.buf[..self.filled]) }
57 }
58
59 pub fn initialized(&self) -> &[u8] {
61 unsafe { slice_assume_init(&self.buf[..self.initialized]) }
63 }
64
65 pub fn initialized_mut(&mut self) -> &mut [u8] {
67 unsafe { slice_assume_init_mut(&mut self.buf[..self.initialized]) }
69 }
70
71 pub fn take(&mut self, n: usize) -> ReadBuf<'_> {
74 let n = n.min(self.remaining());
75 let initialized = self.initialized.saturating_sub(self.filled).min(n);
76 let mut taken = ReadBuf::uninit(&mut self.unfilled_uninit()[..n]);
77 taken.initialized = initialized;
78 taken
79 }
80
81 pub fn initialize_unfilled(&mut self) -> &mut [u8] {
84 self.initialize_unfilled_to(self.remaining())
85 }
86
87 pub fn initialize_unfilled_to(&mut self, n: usize) -> &mut [u8] {
93 assert!(
94 n <= self.remaining(),
95 "n overflows the buffer's remaining room"
96 );
97 let end = self.filled + n;
98 if self.initialized < end {
99 for byte in &mut self.buf[self.initialized..end] {
100 byte.write(0);
101 }
102 self.initialized = end;
103 }
104 unsafe { slice_assume_init_mut(&mut self.buf[self.filled..end]) }
106 }
107
108 pub fn remaining(&self) -> usize {
110 self.capacity() - self.filled
111 }
112
113 pub fn clear(&mut self) {
115 self.filled = 0;
116 }
117
118 #[expect(clippy::expect_used, reason = "documented under `# Panics`")]
124 pub fn advance(&mut self, n: usize) {
125 let filled = self.filled.checked_add(n).expect("filled overflows");
126 self.set_filled(filled);
127 }
128
129 pub fn set_filled(&mut self, n: usize) {
135 assert!(
136 n <= self.initialized,
137 "filled must not pass the initialized part of the buffer"
138 );
139 self.filled = n;
140 }
141
142 pub unsafe fn assume_init(&mut self, n: usize) {
148 let end = self.filled + n;
149 if end > self.initialized {
150 self.initialized = end;
151 }
152 }
153
154 pub fn put_slice(&mut self, bytes: &[u8]) {
160 assert!(
161 self.remaining() >= bytes.len(),
162 "the bytes do not fit in the buffer's remaining room"
163 );
164 let end = self.filled + bytes.len();
165 unsafe {
168 core::ptr::copy_nonoverlapping(
169 bytes.as_ptr(),
170 self.buf[self.filled..end].as_mut_ptr().cast::<u8>(),
171 bytes.len(),
172 );
173 }
174 if self.initialized < end {
175 self.initialized = end;
176 }
177 self.filled = end;
178 }
179
180 pub unsafe fn unfilled_mut(&mut self) -> &mut [MaybeUninit<u8>] {
187 &mut self.buf[self.filled..]
188 }
189
190 fn unfilled_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
191 &mut self.buf[self.filled..]
192 }
193}
194
195impl fmt::Debug for ReadBuf<'_> {
196 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197 f.debug_struct("ReadBuf")
198 .field("filled", &self.filled)
199 .field("initialized", &self.initialized)
200 .field("capacity", &self.capacity())
201 .finish()
202 }
203}
204
205unsafe fn slice_assume_init(slice: &[MaybeUninit<u8>]) -> &[u8] {
209 unsafe { &*(core::ptr::from_ref::<[MaybeUninit<u8>]>(slice) as *const [u8]) }
211}
212
213unsafe fn slice_assume_init_mut(slice: &mut [MaybeUninit<u8>]) -> &mut [u8] {
217 unsafe { &mut *(core::ptr::from_mut::<[MaybeUninit<u8>]>(slice) as *mut [u8]) }
219}
220
221#[cfg(test)]
222mod tests {
223 use super::*;
224
225 #[test]
226 fn a_new_buffer_is_initialized_and_empty() {
227 let mut bytes = [7u8; 8];
228 let buf = ReadBuf::new(&mut bytes);
229 assert_eq!(buf.capacity(), 8);
230 assert_eq!(buf.remaining(), 8);
231 assert!(buf.filled().is_empty());
232 assert_eq!(buf.initialized(), &[7; 8]);
233 }
234
235 #[test]
236 fn put_slice_and_advance_count_the_filled_part() {
237 let mut bytes = [0u8; 8];
238 let mut buf = ReadBuf::new(&mut bytes);
239 buf.put_slice(b"abc");
240 assert_eq!(buf.filled(), b"abc");
241 buf.initialize_unfilled_to(2).copy_from_slice(b"de");
242 buf.advance(2);
243 assert_eq!(buf.filled(), b"abcde");
244 assert_eq!(buf.remaining(), 3);
245 buf.clear();
246 assert!(buf.filled().is_empty());
247 assert_eq!(
248 buf.initialized().len(),
249 8,
250 "clearing keeps what was initialized"
251 );
252 }
253
254 #[test]
255 fn an_uninit_buffer_initializes_only_what_is_asked() {
256 let mut mem = [MaybeUninit::<u8>::uninit(); 16];
257 let mut buf = ReadBuf::uninit(&mut mem);
258 assert!(buf.initialized().is_empty());
259 let part = buf.initialize_unfilled_to(4);
260 assert_eq!(part, &[0; 4]);
261 part.copy_from_slice(b"wxyz");
262 buf.advance(4);
263 assert_eq!(buf.initialized().len(), 4);
264 assert_eq!(buf.filled(), b"wxyz");
265 let rest = buf.initialize_unfilled();
266 assert_eq!(rest.len(), 12);
267 assert_eq!(buf.initialized().len(), 16);
268 }
269
270 #[test]
271 fn take_shares_the_initialized_part_and_bounds_the_room() {
272 let mut bytes = [1u8; 10];
273 let mut buf = ReadBuf::new(&mut bytes);
274 buf.put_slice(&[9, 9]);
275 let mut taken = buf.take(3);
276 assert_eq!(taken.capacity(), 3);
277 assert_eq!(taken.initialized().len(), 3);
278 taken.put_slice(&[5, 5, 5]);
279 assert_eq!(taken.filled(), &[5, 5, 5]);
280 }
281
282 #[test]
283 #[should_panic(expected = "filled must not pass the initialized part")]
284 fn advancing_past_the_initialized_part_panics() {
285 let mut mem = [MaybeUninit::<u8>::uninit(); 4];
286 let mut buf = ReadBuf::uninit(&mut mem);
287 buf.advance(1);
288 }
289
290 #[test]
291 #[should_panic(expected = "do not fit")]
292 fn put_slice_past_the_room_panics() {
293 let mut bytes = [0u8; 2];
294 ReadBuf::new(&mut bytes).put_slice(b"abc");
295 }
296}