Skip to main content

nuclei/io/util/
read_buf.rs

1//! [`ReadBuf`]: a buffer a read fills from the front, over memory that may be
2//! uninitialized, keeping count of the bytes filled and of those known to be
3//! initialized (`filled <= initialized <= capacity`).
4
5use core::fmt;
6use core::mem::MaybeUninit;
7
8/// A buffer being filled by reads: its first `filled` bytes hold data, its
9/// first `initialized` bytes are initialized (`filled <= initialized`), and
10/// the rest may be uninitialized memory that a read may write into.
11pub struct ReadBuf<'a> {
12    buf: &'a mut [MaybeUninit<u8>],
13    filled: usize,
14    initialized: usize,
15}
16
17impl<'a> ReadBuf<'a> {
18    /// A buffer over `buf`, all of it initialized, none of it filled.
19    pub fn new(buf: &'a mut [u8]) -> Self {
20        let initialized = buf.len();
21        // SAFETY: an initialized `u8` is a valid `MaybeUninit<u8>`, and the
22        // buffer never writes uninitialized bytes into it (`initialized`
23        // starts at the whole length and never decreases).
24        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    /// A buffer over `buf`, none of it initialized or filled.
33    pub fn uninit(buf: &'a mut [MaybeUninit<u8>]) -> Self {
34        Self {
35            buf,
36            filled: 0,
37            initialized: 0,
38        }
39    }
40
41    /// The buffer's whole length.
42    pub fn capacity(&self) -> usize {
43        self.buf.len()
44    }
45
46    /// The bytes filled so far.
47    pub fn filled(&self) -> &[u8] {
48        // SAFETY: the first `filled` bytes are initialized (`filled <=
49        // initialized`).
50        unsafe { slice_assume_init(&self.buf[..self.filled]) }
51    }
52
53    /// The bytes filled so far, to change.
54    pub fn filled_mut(&mut self) -> &mut [u8] {
55        // SAFETY: as for `filled`.
56        unsafe { slice_assume_init_mut(&mut self.buf[..self.filled]) }
57    }
58
59    /// The bytes known to be initialized, filled or not.
60    pub fn initialized(&self) -> &[u8] {
61        // SAFETY: the first `initialized` bytes are initialized.
62        unsafe { slice_assume_init(&self.buf[..self.initialized]) }
63    }
64
65    /// The bytes known to be initialized, to change.
66    pub fn initialized_mut(&mut self) -> &mut [u8] {
67        // SAFETY: as for `initialized`.
68        unsafe { slice_assume_init_mut(&mut self.buf[..self.initialized]) }
69    }
70
71    /// A buffer over at most `n` bytes of the unfilled part, sharing what is
72    /// known to be initialized there.
73    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    /// Initializes the whole unfilled part (zeroing what was not
82    /// initialized) and answers it, for a read to write into.
83    pub fn initialize_unfilled(&mut self) -> &mut [u8] {
84        self.initialize_unfilled_to(self.remaining())
85    }
86
87    /// Initializes the first `n` bytes of the unfilled part and answers them.
88    ///
89    /// # Panics
90    ///
91    /// When `n` is more than [`remaining`](Self::remaining).
92    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        // SAFETY: `filled..end` was initialized just above or before.
105        unsafe { slice_assume_init_mut(&mut self.buf[self.filled..end]) }
106    }
107
108    /// The room left after the filled part.
109    pub fn remaining(&self) -> usize {
110        self.capacity() - self.filled
111    }
112
113    /// Empties the filled part; what was initialized stays initialized.
114    pub fn clear(&mut self) {
115        self.filled = 0;
116    }
117
118    /// Counts `n` more bytes as filled.
119    ///
120    /// # Panics
121    ///
122    /// When that passes the initialized part.
123    #[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    /// Sets how many bytes are filled.
130    ///
131    /// # Panics
132    ///
133    /// When `n` passes the initialized part.
134    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    /// Counts the first `n` bytes of the unfilled part as initialized.
143    ///
144    /// # Safety
145    ///
146    /// The caller has initialized those bytes.
147    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    /// Appends `bytes` to the filled part.
155    ///
156    /// # Panics
157    ///
158    /// When they do not fit in [`remaining`](Self::remaining).
159    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        // SAFETY: `MaybeUninit<u8>` and `u8` have the same layout, and the
166        // destination is within `buf`.
167        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    /// The unfilled part, as memory that may be uninitialized.
181    ///
182    /// # Safety
183    ///
184    /// The caller must not write uninitialized bytes into it: the part known
185    /// to be initialized must stay initialized.
186    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
205/// # Safety
206///
207/// Every byte of `slice` is initialized.
208unsafe fn slice_assume_init(slice: &[MaybeUninit<u8>]) -> &[u8] {
209    // SAFETY: same layout; initialized by the caller's promise.
210    unsafe { &*(core::ptr::from_ref::<[MaybeUninit<u8>]>(slice) as *const [u8]) }
211}
212
213/// # Safety
214///
215/// Every byte of `slice` is initialized.
216unsafe fn slice_assume_init_mut(slice: &mut [MaybeUninit<u8>]) -> &mut [u8] {
217    // SAFETY: as for `slice_assume_init`.
218    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}