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