tokio/io/read_buf.rs
1use std::fmt;
2use 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.
23pub struct ReadBuf<'a> {
24 buf: &'a mut [MaybeUninit<u8>],
25 filled: usize,
26 initialized: usize,
27}
28
29impl<'a> ReadBuf<'a> {
30 /// Creates a new `ReadBuf` from a fully initialized buffer.
31 #[inline]
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 buffer that may be uninitialized.
43 ///
44 /// The internal cursor will mark the entire buffer as uninitialized. If
45 /// the buffer is known to be partially initialized, then use `assume_init`
46 /// to move the internal cursor.
47 #[inline]
48 pub fn uninit(buf: &'a mut [MaybeUninit<u8>]) -> ReadBuf<'a> {
49 ReadBuf {
50 buf,
51 filled: 0,
52 initialized: 0,
53 }
54 }
55
56 /// Returns the total capacity of the buffer.
57 #[inline]
58 pub fn capacity(&self) -> usize {
59 self.buf.len()
60 }
61
62 /// Returns a shared reference to the filled portion of the buffer.
63 #[inline]
64 pub fn filled(&self) -> &[u8] {
65 let slice = &self.buf[..self.filled];
66 // safety: filled describes how far into the buffer that the
67 // user has filled with bytes, so it's been initialized.
68 unsafe { slice_assume_init(slice) }
69 }
70
71 /// Returns a mutable reference to the filled portion of the buffer.
72 #[inline]
73 pub fn filled_mut(&mut self) -> &mut [u8] {
74 let slice = &mut self.buf[..self.filled];
75 // safety: filled describes how far into the buffer that the
76 // user has filled with bytes, so it's been initialized.
77 unsafe { slice_assume_init_mut(slice) }
78 }
79
80 /// Returns a new `ReadBuf` comprised of the unfilled section up to `n`.
81 #[inline]
82 pub fn take(&mut self, n: usize) -> ReadBuf<'_> {
83 let max = std::cmp::min(self.remaining(), n);
84 // Safety: We don't set any of the `unfilled_mut` with `MaybeUninit::uninit`.
85 unsafe { ReadBuf::uninit(&mut self.unfilled_mut()[..max]) }
86 }
87
88 /// Returns a shared reference to the initialized portion of the buffer.
89 ///
90 /// This includes the filled portion.
91 #[inline]
92 pub fn initialized(&self) -> &[u8] {
93 let slice = &self.buf[..self.initialized];
94 // safety: initialized describes how far into the buffer that the
95 // user has at some point initialized with bytes.
96 unsafe { slice_assume_init(slice) }
97 }
98
99 /// Returns a mutable reference to the initialized portion of the buffer.
100 ///
101 /// This includes the filled portion.
102 #[inline]
103 pub fn initialized_mut(&mut self) -> &mut [u8] {
104 let slice = &mut self.buf[..self.initialized];
105 // safety: initialized describes how far into the buffer that the
106 // user has at some point initialized with bytes.
107 unsafe { slice_assume_init_mut(slice) }
108 }
109
110 /// Returns a mutable reference to the entire buffer, without ensuring that it has been fully
111 /// initialized.
112 ///
113 /// The elements between 0 and `self.filled().len()` are filled, and those between 0 and
114 /// `self.initialized().len()` are initialized (and so can be converted to a `&mut [u8]`).
115 ///
116 /// The caller of this method must ensure that these invariants are upheld. For example, if the
117 /// caller initializes some of the uninitialized section of the buffer, it must call
118 /// [`assume_init`](Self::assume_init) with the number of bytes initialized.
119 ///
120 /// # Safety
121 ///
122 /// The caller must not de-initialize portions of the buffer that have already been initialized.
123 /// This includes any bytes in the region marked as uninitialized by `ReadBuf`.
124 #[inline]
125 pub unsafe fn inner_mut(&mut self) -> &mut [MaybeUninit<u8>] {
126 self.buf
127 }
128
129 /// Returns a mutable reference to the unfilled part of the buffer without ensuring that it has been fully
130 /// initialized.
131 ///
132 /// # Safety
133 ///
134 /// The caller must not de-initialize portions of the buffer that have already been initialized.
135 /// This includes any bytes in the region marked as uninitialized by `ReadBuf`.
136 #[inline]
137 pub unsafe fn unfilled_mut(&mut self) -> &mut [MaybeUninit<u8>] {
138 &mut self.buf[self.filled..]
139 }
140
141 /// Returns a mutable reference to the unfilled part of the buffer, ensuring it is fully initialized.
142 ///
143 /// Since `ReadBuf` tracks the region of the buffer that has been initialized, this is effectively "free" after
144 /// the first use.
145 #[inline]
146 pub fn initialize_unfilled(&mut self) -> &mut [u8] {
147 self.initialize_unfilled_to(self.remaining())
148 }
149
150 /// Returns a mutable reference to the first `n` bytes of the unfilled part of the buffer, ensuring it is
151 /// fully initialized.
152 ///
153 /// # Panics
154 ///
155 /// Panics if `self.remaining()` is less than `n`.
156 #[inline]
157 #[track_caller]
158 pub fn initialize_unfilled_to(&mut self, n: usize) -> &mut [u8] {
159 assert!(self.remaining() >= n, "n overflows remaining");
160
161 // This can't overflow, otherwise the assert above would have failed.
162 let end = self.filled + n;
163
164 if self.initialized < end {
165 unsafe {
166 self.buf[self.initialized..end]
167 .as_mut_ptr()
168 .write_bytes(0, end - self.initialized);
169 }
170 self.initialized = end;
171 }
172
173 let slice = &mut self.buf[self.filled..end];
174 // safety: just above, we checked that the end of the buf has
175 // been initialized to some value.
176 unsafe { slice_assume_init_mut(slice) }
177 }
178
179 /// Returns the number of bytes at the end of the slice that have not yet been filled.
180 #[inline]
181 pub fn remaining(&self) -> usize {
182 self.capacity() - self.filled
183 }
184
185 /// Clears the buffer, resetting the filled region to empty.
186 ///
187 /// The number of initialized bytes is not changed, and the contents of the buffer are not modified.
188 #[inline]
189 pub fn clear(&mut self) {
190 self.filled = 0;
191 }
192
193 /// Advances the size of the filled region of the buffer.
194 ///
195 /// The number of initialized bytes is not changed.
196 ///
197 /// # Panics
198 ///
199 /// Panics if the filled region of the buffer would become larger than the initialized region.
200 #[inline]
201 #[track_caller]
202 pub fn advance(&mut self, n: usize) {
203 let new = self.filled.checked_add(n).expect("filled overflow");
204 self.set_filled(new);
205 }
206
207 /// Sets the size of the filled region of the buffer.
208 ///
209 /// The number of initialized bytes is not changed.
210 ///
211 /// Note that this can be used to *shrink* the filled region of the buffer in addition to growing it (for
212 /// example, by a `AsyncRead` implementation that compresses data in-place).
213 ///
214 /// # Panics
215 ///
216 /// Panics if the filled region of the buffer would become larger than the initialized region.
217 #[inline]
218 #[track_caller]
219 pub fn set_filled(&mut self, n: usize) {
220 assert!(
221 n <= self.initialized,
222 "filled must not become larger than initialized"
223 );
224 self.filled = n;
225 }
226
227 /// Asserts that the first `n` unfilled bytes of the buffer are initialized.
228 ///
229 /// `ReadBuf` assumes that bytes are never de-initialized, so this method does nothing when called with fewer
230 /// bytes than are already known to be initialized.
231 ///
232 /// # Safety
233 ///
234 /// The caller must ensure that `n` unfilled bytes of the buffer have already been initialized.
235 #[inline]
236 pub unsafe fn assume_init(&mut self, n: usize) {
237 let new = self.filled + n;
238 if new > self.initialized {
239 self.initialized = new;
240 }
241 }
242
243 /// Appends data to the buffer, advancing the written position and possibly also the initialized position.
244 ///
245 /// # Panics
246 ///
247 /// Panics if `self.remaining()` is less than `buf.len()`.
248 #[inline]
249 #[track_caller]
250 pub fn put_slice(&mut self, buf: &[u8]) {
251 assert!(
252 self.remaining() >= buf.len(),
253 "buf.len() must fit in remaining(); buf.len() = {}, remaining() = {}",
254 buf.len(),
255 self.remaining()
256 );
257
258 let amt = buf.len();
259 // Cannot overflow, asserted above
260 let end = self.filled + amt;
261
262 // Safety: the length is asserted above
263 unsafe {
264 self.buf[self.filled..end]
265 .as_mut_ptr()
266 .cast::<u8>()
267 .copy_from_nonoverlapping(buf.as_ptr(), amt);
268 }
269
270 if self.initialized < end {
271 self.initialized = end;
272 }
273 self.filled = end;
274 }
275}
276
277#[cfg(feature = "io-util")]
278#[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
279unsafe impl<'a> bytes::BufMut for ReadBuf<'a> {
280 fn remaining_mut(&self) -> usize {
281 self.remaining()
282 }
283
284 // SAFETY: The caller guarantees that at least `cnt` unfilled bytes have been initialized.
285 unsafe fn advance_mut(&mut self, cnt: usize) {
286 self.assume_init(cnt);
287 self.advance(cnt);
288 }
289
290 fn chunk_mut(&mut self) -> &mut bytes::buf::UninitSlice {
291 // SAFETY: No region of `unfilled` will be deinitialized because it is
292 // exposed as an `UninitSlice`, whose API guarantees that the memory is
293 // never deinitialized.
294 let unfilled = unsafe { self.unfilled_mut() };
295 let len = unfilled.len();
296 let ptr = unfilled.as_mut_ptr() as *mut u8;
297
298 // SAFETY: The pointer is valid for `len` bytes because it comes from a
299 // slice of that length.
300 unsafe { bytes::buf::UninitSlice::from_raw_parts_mut(ptr, len) }
301 }
302}
303
304impl fmt::Debug for ReadBuf<'_> {
305 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
306 f.debug_struct("ReadBuf")
307 .field("filled", &self.filled)
308 .field("initialized", &self.initialized)
309 .field("capacity", &self.capacity())
310 .finish()
311 }
312}
313
314unsafe fn slice_to_uninit_mut(slice: &mut [u8]) -> &mut [MaybeUninit<u8>] {
315 &mut *(slice as *mut [u8] as *mut [MaybeUninit<u8>])
316}
317
318// TODO: This could use `MaybeUninit::slice_assume_init` when it is stable.
319unsafe fn slice_assume_init(slice: &[MaybeUninit<u8>]) -> &[u8] {
320 &*(slice as *const [MaybeUninit<u8>] as *const [u8])
321}
322
323// TODO: This could use `MaybeUninit::slice_assume_init_mut` when it is stable.
324unsafe fn slice_assume_init_mut(slice: &mut [MaybeUninit<u8>]) -> &mut [u8] {
325 &mut *(slice as *mut [MaybeUninit<u8>] as *mut [u8])
326}