• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::fmt;
2 use std::mem::MaybeUninit;
3 
4 /// A wrapper around a byte buffer that is incrementally filled and initialized.
5 ///
6 /// This type is a sort of "double cursor". It tracks three regions in the
7 /// buffer: a region at the beginning of the buffer that has been logically
8 /// filled with data, a region that has been initialized at some point but not
9 /// yet logically filled, and a region at the end that may be uninitialized.
10 /// The filled region is guaranteed to be a subset of the initialized region.
11 ///
12 /// In summary, the contents of the buffer can be visualized as:
13 ///
14 /// ```not_rust
15 /// [             capacity              ]
16 /// [ filled |         unfilled         ]
17 /// [    initialized    | uninitialized ]
18 /// ```
19 ///
20 /// It is undefined behavior to de-initialize any bytes from the uninitialized
21 /// region, since it is merely unknown whether this region is uninitialized or
22 /// not, and if part of it turns out to be initialized, it must stay initialized.
23 pub struct ReadBuf<'a> {
24     buf: &'a mut [MaybeUninit<u8>],
25     filled: usize,
26     initialized: usize,
27 }
28 
29 impl<'a> ReadBuf<'a> {
30     /// Creates a new `ReadBuf` from a fully initialized buffer.
31     #[inline]
new(buf: &'a mut [u8]) -> ReadBuf<'a>32     pub fn new(buf: &'a mut [u8]) -> ReadBuf<'a> {
33         let initialized = buf.len();
34         let buf = unsafe { slice_to_uninit_mut(buf) };
35         ReadBuf {
36             buf,
37             filled: 0,
38             initialized,
39         }
40     }
41 
42     /// Creates a new `ReadBuf` from a fully uninitialized buffer.
43     ///
44     /// Use `assume_init` if part of the buffer is known to be already initialized.
45     #[inline]
uninit(buf: &'a mut [MaybeUninit<u8>]) -> ReadBuf<'a>46     pub fn uninit(buf: &'a mut [MaybeUninit<u8>]) -> ReadBuf<'a> {
47         ReadBuf {
48             buf,
49             filled: 0,
50             initialized: 0,
51         }
52     }
53 
54     /// Returns the total capacity of the buffer.
55     #[inline]
capacity(&self) -> usize56     pub fn capacity(&self) -> usize {
57         self.buf.len()
58     }
59 
60     /// Returns a shared reference to the filled portion of the buffer.
61     #[inline]
filled(&self) -> &[u8]62     pub fn filled(&self) -> &[u8] {
63         let slice = &self.buf[..self.filled];
64         // safety: filled describes how far into the buffer that the
65         // user has filled with bytes, so it's been initialized.
66         unsafe { slice_assume_init(slice) }
67     }
68 
69     /// Returns a mutable reference to the filled portion of the buffer.
70     #[inline]
filled_mut(&mut self) -> &mut [u8]71     pub fn filled_mut(&mut self) -> &mut [u8] {
72         let slice = &mut self.buf[..self.filled];
73         // safety: filled describes how far into the buffer that the
74         // user has filled with bytes, so it's been initialized.
75         unsafe { slice_assume_init_mut(slice) }
76     }
77 
78     /// Returns a new `ReadBuf` comprised of the unfilled section up to `n`.
79     #[inline]
take(&mut self, n: usize) -> ReadBuf<'_>80     pub fn take(&mut self, n: usize) -> ReadBuf<'_> {
81         let max = std::cmp::min(self.remaining(), n);
82         // Safety: We don't set any of the `unfilled_mut` with `MaybeUninit::uninit`.
83         unsafe { ReadBuf::uninit(&mut self.unfilled_mut()[..max]) }
84     }
85 
86     /// Returns a shared reference to the initialized portion of the buffer.
87     ///
88     /// This includes the filled portion.
89     #[inline]
initialized(&self) -> &[u8]90     pub fn initialized(&self) -> &[u8] {
91         let slice = &self.buf[..self.initialized];
92         // safety: initialized describes how far into the buffer that the
93         // user has at some point initialized with bytes.
94         unsafe { slice_assume_init(slice) }
95     }
96 
97     /// Returns a mutable reference to the initialized portion of the buffer.
98     ///
99     /// This includes the filled portion.
100     #[inline]
initialized_mut(&mut self) -> &mut [u8]101     pub fn initialized_mut(&mut self) -> &mut [u8] {
102         let slice = &mut self.buf[..self.initialized];
103         // safety: initialized describes how far into the buffer that the
104         // user has at some point initialized with bytes.
105         unsafe { slice_assume_init_mut(slice) }
106     }
107 
108     /// Returns a mutable reference to the entire buffer, without ensuring that it has been fully
109     /// initialized.
110     ///
111     /// The elements between 0 and `self.filled().len()` are filled, and those between 0 and
112     /// `self.initialized().len()` are initialized (and so can be converted to a `&mut [u8]`).
113     ///
114     /// The caller of this method must ensure that these invariants are upheld. For example, if the
115     /// caller initializes some of the uninitialized section of the buffer, it must call
116     /// [`assume_init`](Self::assume_init) with the number of bytes initialized.
117     ///
118     /// # Safety
119     ///
120     /// The caller must not de-initialize portions of the buffer that have already been initialized.
121     /// This includes any bytes in the region marked as uninitialized by `ReadBuf`.
122     #[inline]
inner_mut(&mut self) -> &mut [MaybeUninit<u8>]123     pub unsafe fn inner_mut(&mut self) -> &mut [MaybeUninit<u8>] {
124         self.buf
125     }
126 
127     /// Returns a mutable reference to the unfilled part of the buffer without ensuring that it has been fully
128     /// initialized.
129     ///
130     /// # Safety
131     ///
132     /// The caller must not de-initialize portions of the buffer that have already been initialized.
133     /// This includes any bytes in the region marked as uninitialized by `ReadBuf`.
134     #[inline]
unfilled_mut(&mut self) -> &mut [MaybeUninit<u8>]135     pub unsafe fn unfilled_mut(&mut self) -> &mut [MaybeUninit<u8>] {
136         &mut self.buf[self.filled..]
137     }
138 
139     /// Returns a mutable reference to the unfilled part of the buffer, ensuring it is fully initialized.
140     ///
141     /// Since `ReadBuf` tracks the region of the buffer that has been initialized, this is effectively "free" after
142     /// the first use.
143     #[inline]
initialize_unfilled(&mut self) -> &mut [u8]144     pub fn initialize_unfilled(&mut self) -> &mut [u8] {
145         self.initialize_unfilled_to(self.remaining())
146     }
147 
148     /// Returns a mutable reference to the first `n` bytes of the unfilled part of the buffer, ensuring it is
149     /// fully initialized.
150     ///
151     /// # Panics
152     ///
153     /// Panics if `self.remaining()` is less than `n`.
154     #[inline]
155     #[track_caller]
initialize_unfilled_to(&mut self, n: usize) -> &mut [u8]156     pub fn initialize_unfilled_to(&mut self, n: usize) -> &mut [u8] {
157         assert!(self.remaining() >= n, "n overflows remaining");
158 
159         // This can't overflow, otherwise the assert above would have failed.
160         let end = self.filled + n;
161 
162         if self.initialized < end {
163             unsafe {
164                 self.buf[self.initialized..end]
165                     .as_mut_ptr()
166                     .write_bytes(0, end - self.initialized);
167             }
168             self.initialized = end;
169         }
170 
171         let slice = &mut self.buf[self.filled..end];
172         // safety: just above, we checked that the end of the buf has
173         // been initialized to some value.
174         unsafe { slice_assume_init_mut(slice) }
175     }
176 
177     /// Returns the number of bytes at the end of the slice that have not yet been filled.
178     #[inline]
remaining(&self) -> usize179     pub fn remaining(&self) -> usize {
180         self.capacity() - self.filled
181     }
182 
183     /// Clears the buffer, resetting the filled region to empty.
184     ///
185     /// The number of initialized bytes is not changed, and the contents of the buffer are not modified.
186     #[inline]
clear(&mut self)187     pub fn clear(&mut self) {
188         self.filled = 0;
189     }
190 
191     /// Advances the size of the filled region of the buffer.
192     ///
193     /// The number of initialized bytes is not changed.
194     ///
195     /// # Panics
196     ///
197     /// Panics if the filled region of the buffer would become larger than the initialized region.
198     #[inline]
199     #[track_caller]
advance(&mut self, n: usize)200     pub fn advance(&mut self, n: usize) {
201         let new = self.filled.checked_add(n).expect("filled overflow");
202         self.set_filled(new);
203     }
204 
205     /// Sets the size of the filled region of the buffer.
206     ///
207     /// The number of initialized bytes is not changed.
208     ///
209     /// Note that this can be used to *shrink* the filled region of the buffer in addition to growing it (for
210     /// example, by a `AsyncRead` implementation that compresses data in-place).
211     ///
212     /// # Panics
213     ///
214     /// Panics if the filled region of the buffer would become larger than the initialized region.
215     #[inline]
216     #[track_caller]
set_filled(&mut self, n: usize)217     pub fn set_filled(&mut self, n: usize) {
218         assert!(
219             n <= self.initialized,
220             "filled must not become larger than initialized"
221         );
222         self.filled = n;
223     }
224 
225     /// Asserts that the first `n` unfilled bytes of the buffer are initialized.
226     ///
227     /// `ReadBuf` assumes that bytes are never de-initialized, so this method does nothing when called with fewer
228     /// bytes than are already known to be initialized.
229     ///
230     /// # Safety
231     ///
232     /// The caller must ensure that `n` unfilled bytes of the buffer have already been initialized.
233     #[inline]
assume_init(&mut self, n: usize)234     pub unsafe fn assume_init(&mut self, n: usize) {
235         let new = self.filled + n;
236         if new > self.initialized {
237             self.initialized = new;
238         }
239     }
240 
241     /// Appends data to the buffer, advancing the written position and possibly also the initialized position.
242     ///
243     /// # Panics
244     ///
245     /// Panics if `self.remaining()` is less than `buf.len()`.
246     #[inline]
247     #[track_caller]
put_slice(&mut self, buf: &[u8])248     pub fn put_slice(&mut self, buf: &[u8]) {
249         assert!(
250             self.remaining() >= buf.len(),
251             "buf.len() must fit in remaining()"
252         );
253 
254         let amt = buf.len();
255         // Cannot overflow, asserted above
256         let end = self.filled + amt;
257 
258         // Safety: the length is asserted above
259         unsafe {
260             self.buf[self.filled..end]
261                 .as_mut_ptr()
262                 .cast::<u8>()
263                 .copy_from_nonoverlapping(buf.as_ptr(), amt);
264         }
265 
266         if self.initialized < end {
267             self.initialized = end;
268         }
269         self.filled = end;
270     }
271 }
272 
273 impl fmt::Debug for ReadBuf<'_> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result274     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
275         f.debug_struct("ReadBuf")
276             .field("filled", &self.filled)
277             .field("initialized", &self.initialized)
278             .field("capacity", &self.capacity())
279             .finish()
280     }
281 }
282 
slice_to_uninit_mut(slice: &mut [u8]) -> &mut [MaybeUninit<u8>]283 unsafe fn slice_to_uninit_mut(slice: &mut [u8]) -> &mut [MaybeUninit<u8>] {
284     &mut *(slice as *mut [u8] as *mut [MaybeUninit<u8>])
285 }
286 
287 // TODO: This could use `MaybeUninit::slice_assume_init` when it is stable.
slice_assume_init(slice: &[MaybeUninit<u8>]) -> &[u8]288 unsafe fn slice_assume_init(slice: &[MaybeUninit<u8>]) -> &[u8] {
289     &*(slice as *const [MaybeUninit<u8>] as *const [u8])
290 }
291 
292 // TODO: This could use `MaybeUninit::slice_assume_init_mut` when it is stable.
slice_assume_init_mut(slice: &mut [MaybeUninit<u8>]) -> &mut [u8]293 unsafe fn slice_assume_init_mut(slice: &mut [MaybeUninit<u8>]) -> &mut [u8] {
294     &mut *(slice as *mut [MaybeUninit<u8>] as *mut [u8])
295 }
296