22
33use crate :: fmt:: { self , Debug , Formatter } ;
44use crate :: mem:: { self , MaybeUninit } ;
5+ use crate :: { cmp, ptr} ;
56
6- /// A borrowed buffer of initially uninitialized bytes, which is incrementally filled.
7+ /// A borrowed byte buffer which is incrementally filled and initialized .
78///
8- /// This type makes it safer to work with `MaybeUninit` buffers, such as to read into a buffer
9- /// without having to initialize it first. It tracks the region of bytes that have been filled and
10- /// the region that remains uninitialized.
9+ /// This type is a sort of "double cursor". It tracks three regions in the buffer: a region at the beginning of the
10+ /// buffer that has been logically filled with data, a region that has been initialized at some point but not yet
11+ /// logically filled, and a region at the end that is fully uninitialized. The filled region is guaranteed to be a
12+ /// subset of the initialized region.
1113///
12- /// The contents of the buffer can be visualized as:
14+ /// In summary, the contents of the buffer can be visualized as:
1315/// ```not_rust
14- /// [ capacity ]
15- /// [ len: filled and initialized | capacity - len: uninitialized ]
16+ /// [ capacity ]
17+ /// [ filled | unfilled ]
18+ /// [ initialized | uninitialized ]
1619/// ```
1720///
18- /// Note that `BorrowedBuf` does not distinguish between uninitialized data and data that was
19- /// previously initialized but no longer contains valid data.
20- ///
21- /// A `BorrowedBuf` is created around some existing data (or capacity for data) via a unique
22- /// reference (`&mut`). The `BorrowedBuf` can be configured (e.g., using `clear` or `set_len`), but
23- /// cannot be directly written. To write into the buffer, use `unfilled` to create a
24- /// `BorrowedCursor`. The cursor has write-only access to the unfilled portion of the buffer.
21+ /// A `BorrowedBuf` is created around some existing data (or capacity for data) via a unique reference
22+ /// (`&mut`). The `BorrowedBuf` can be configured (e.g., using `clear` or `set_init`), but cannot be
23+ /// directly written. To write into the buffer, use `unfilled` to create a `BorrowedCursor`. The cursor
24+ /// has write-only access to the unfilled portion of the buffer (you can think of it as a
25+ /// write-only iterator).
2526///
2627/// The lifetime `'data` is a bound on the lifetime of the underlying data.
2728pub struct BorrowedBuf < ' data > {
2829 /// The buffer's underlying data.
2930 buf : & ' data mut [ MaybeUninit < u8 > ] ,
3031 /// The length of `self.buf` which is known to be filled.
3132 filled : usize ,
33+ /// The length of `self.buf` which is known to be initialized.
34+ init : usize ,
3235}
3336
3437impl Debug for BorrowedBuf < ' _ > {
3538 fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
3639 f. debug_struct ( "BorrowedBuf" )
40+ . field ( "init" , & self . init )
3741 . field ( "filled" , & self . filled )
3842 . field ( "capacity" , & self . capacity ( ) )
3943 . finish ( )
@@ -44,22 +48,24 @@ impl Debug for BorrowedBuf<'_> {
4448impl < ' data > From < & ' data mut [ u8 ] > for BorrowedBuf < ' data > {
4549 #[ inline]
4650 fn from ( slice : & ' data mut [ u8 ] ) -> BorrowedBuf < ' data > {
51+ let len = slice. len ( ) ;
52+
4753 BorrowedBuf {
48- // SAFETY: Always in bounds. We treat the buffer as uninitialized, even though it's
49- // already initialized.
54+ // SAFETY: initialized data never becoming uninitialized is an invariant of BorrowedBuf
5055 buf : unsafe { ( slice as * mut [ u8 ] ) . as_uninit_slice_mut ( ) . unwrap ( ) } ,
5156 filled : 0 ,
57+ init : len,
5258 }
5359 }
5460}
5561
5662/// Creates a new `BorrowedBuf` from an uninitialized buffer.
5763///
58- /// Use `set_filled ` if part of the buffer is known to be already filled .
64+ /// Use `set_init ` if part of the buffer is known to be already initialized .
5965impl < ' data > From < & ' data mut [ MaybeUninit < u8 > ] > for BorrowedBuf < ' data > {
6066 #[ inline]
6167 fn from ( buf : & ' data mut [ MaybeUninit < u8 > ] ) -> BorrowedBuf < ' data > {
62- BorrowedBuf { buf, filled : 0 }
68+ BorrowedBuf { buf, filled : 0 , init : 0 }
6369 }
6470}
6571
@@ -68,11 +74,14 @@ impl<'data> From<&'data mut [MaybeUninit<u8>]> for BorrowedBuf<'data> {
6874/// Use `BorrowedCursor::with_unfilled_buf` instead for a safer alternative.
6975impl < ' data > From < BorrowedCursor < ' data > > for BorrowedBuf < ' data > {
7076 #[ inline]
71- fn from ( buf : BorrowedCursor < ' data > ) -> BorrowedBuf < ' data > {
77+ fn from ( mut buf : BorrowedCursor < ' data > ) -> BorrowedBuf < ' data > {
78+ let init = buf. init_mut ( ) . len ( ) ;
7279 BorrowedBuf {
73- // SAFETY: Always in bounds. We treat the buffer as uninitialized.
80+ // SAFETY: no initialized byte is ever uninitialized as per
81+ // `BorrowedBuf`'s invariant
7482 buf : unsafe { buf. buf . buf . get_unchecked_mut ( buf. buf . filled ..) } ,
7583 filled : 0 ,
84+ init,
7685 }
7786 }
7887}
@@ -90,6 +99,12 @@ impl<'data> BorrowedBuf<'data> {
9099 self . filled
91100 }
92101
102+ /// Returns the length of the initialized part of the buffer.
103+ #[ inline]
104+ pub fn init_len ( & self ) -> usize {
105+ self . init
106+ }
107+
93108 /// Returns a shared reference to the filled portion of the buffer.
94109 #[ inline]
95110 pub fn filled ( & self ) -> & [ u8 ] {
@@ -144,16 +159,33 @@ impl<'data> BorrowedBuf<'data> {
144159
145160 /// Clears the buffer, resetting the filled region to empty.
146161 ///
147- /// The contents of the buffer are not modified.
162+ /// The number of initialized bytes is not changed, and the contents of the buffer are not modified.
148163 #[ inline]
149164 pub fn clear ( & mut self ) -> & mut Self {
150165 self . filled = 0 ;
151166 self
152167 }
168+
169+ /// Asserts that the first `n` bytes of the buffer are initialized.
170+ ///
171+ /// `BorrowedBuf` assumes that bytes are never de-initialized, so this method does nothing when called with fewer
172+ /// bytes than are already known to be initialized.
173+ ///
174+ /// # Safety
175+ ///
176+ /// The caller must ensure that the first `n` unfilled bytes of the buffer have already been initialized.
177+ #[ inline]
178+ pub unsafe fn set_init ( & mut self , n : usize ) -> & mut Self {
179+ self . init = cmp:: max ( self . init , n) ;
180+ self
181+ }
153182}
154183
155184/// A writeable view of the unfilled portion of a [`BorrowedBuf`].
156185///
186+ /// The unfilled portion consists of an initialized and an uninitialized part; see [`BorrowedBuf`]
187+ /// for details.
188+ ///
157189/// Data can be written directly to the cursor by using [`append`](BorrowedCursor::append) or
158190/// indirectly by getting a slice of part or all of the cursor and writing into the slice. In the
159191/// indirect case, the caller must call [`advance`](BorrowedCursor::advance) after writing to inform
@@ -206,17 +238,48 @@ impl<'a> BorrowedCursor<'a> {
206238 self . buf . filled
207239 }
208240
241+ /// Returns a mutable reference to the initialized portion of the cursor.
242+ #[ inline]
243+ pub fn init_mut ( & mut self ) -> & mut [ u8 ] {
244+ // SAFETY: We only slice the initialized part of the buffer, which is always valid
245+ unsafe {
246+ let buf = self . buf . buf . get_unchecked_mut ( self . buf . filled ..self . buf . init ) ;
247+ buf. assume_init_mut ( )
248+ }
249+ }
250+
209251 /// Returns a mutable reference to the whole cursor.
210252 ///
211253 /// # Safety
212254 ///
213- /// The caller must not uninitialize any previously initialized bytes .
255+ /// The caller must not uninitialize any bytes in the initialized portion of the cursor .
214256 #[ inline]
215257 pub unsafe fn as_mut ( & mut self ) -> & mut [ MaybeUninit < u8 > ] {
216258 // SAFETY: always in bounds
217259 unsafe { self . buf . buf . get_unchecked_mut ( self . buf . filled ..) }
218260 }
219261
262+ /// Advances the cursor by asserting that `n` bytes have been filled.
263+ ///
264+ /// After advancing, the `n` bytes are no longer accessible via the cursor and can only be
265+ /// accessed via the underlying buffer. I.e., the buffer's filled portion grows by `n` elements
266+ /// and its unfilled portion (and the capacity of this cursor) shrinks by `n` elements.
267+ ///
268+ /// If less than `n` bytes initialized (by the cursor's point of view), `set_init` should be
269+ /// called first.
270+ ///
271+ /// # Panics
272+ ///
273+ /// Panics if there are less than `n` bytes initialized.
274+ #[ inline]
275+ pub fn advance ( & mut self , n : usize ) -> & mut Self {
276+ // The subtraction cannot underflow by invariant of this type.
277+ assert ! ( n <= self . buf. init - self . buf. filled) ;
278+
279+ self . buf . filled += n;
280+ self
281+ }
282+
220283 /// Advances the cursor by asserting that `n` bytes have been filled.
221284 ///
222285 /// After advancing, the `n` bytes are no longer accessible via the cursor and can only be
@@ -225,11 +288,42 @@ impl<'a> BorrowedCursor<'a> {
225288 ///
226289 /// # Safety
227290 ///
228- /// The caller must ensure that the first `n` bytes of the cursor have been initialized. `n`
229- /// must not exceed the remaining capacity of this cursor .
291+ /// The caller must ensure that the first `n` bytes of the cursor have been properly
292+ /// initialised .
230293 #[ inline]
231- pub unsafe fn advance ( & mut self , n : usize ) -> & mut Self {
294+ pub unsafe fn advance_unchecked ( & mut self , n : usize ) -> & mut Self {
232295 self . buf . filled += n;
296+ self . buf . init = cmp:: max ( self . buf . init , self . buf . filled ) ;
297+ self
298+ }
299+
300+ /// Initializes all bytes in the cursor.
301+ #[ inline]
302+ pub fn ensure_init ( & mut self ) -> & mut Self {
303+ // SAFETY: always in bounds and we never uninitialize these bytes.
304+ let uninit = unsafe { self . buf . buf . get_unchecked_mut ( self . buf . init ..) } ;
305+
306+ // SAFETY: 0 is a valid value for MaybeUninit<u8> and the length matches the allocation
307+ // since it is comes from a slice reference.
308+ unsafe {
309+ ptr:: write_bytes ( uninit. as_mut_ptr ( ) , 0 , uninit. len ( ) ) ;
310+ }
311+ self . buf . init = self . buf . capacity ( ) ;
312+
313+ self
314+ }
315+
316+ /// Asserts that the first `n` unfilled bytes of the cursor are initialized.
317+ ///
318+ /// `BorrowedBuf` assumes that bytes are never de-initialized, so this method does nothing when
319+ /// called with fewer bytes than are already known to be initialized.
320+ ///
321+ /// # Safety
322+ ///
323+ /// The caller must ensure that the first `n` bytes of the buffer have already been initialized.
324+ #[ inline]
325+ pub unsafe fn set_init ( & mut self , n : usize ) -> & mut Self {
326+ self . buf . init = cmp:: max ( self . buf . init , self . buf . filled + n) ;
233327 self
234328 }
235329
@@ -247,6 +341,10 @@ impl<'a> BorrowedCursor<'a> {
247341 self . as_mut ( ) [ ..buf. len ( ) ] . write_copy_of_slice ( buf) ;
248342 }
249343
344+ // SAFETY: We just added the entire contents of buf to the filled section.
345+ unsafe {
346+ self . set_init ( buf. len ( ) ) ;
347+ }
250348 self . buf . filled += buf. len ( ) ;
251349 }
252350
@@ -269,9 +367,17 @@ impl<'a> BorrowedCursor<'a> {
269367 // there, one could mark some bytes as initialized even though there aren't.
270368 assert ! ( core:: ptr:: addr_eq( prev_ptr, buf. buf) ) ;
271369
272- // SAFETY: These bytes were filled in the `BorrowedBuf`, so they're filled in the cursor
273- // too, because the buffer wasn't replaced.
274- self . buf . filled += buf. filled ;
370+ let filled = buf. filled ;
371+ let init = buf. init ;
372+
373+ // Update `init` and `filled` fields with what was written to the buffer.
374+ // `self.buf.filled` was the starting length of the `BorrowedBuf`.
375+ //
376+ // SAFETY: These amounts of bytes were initialized/filled in the `BorrowedBuf`,
377+ // and therefore they are initialized/filled in the cursor too, because the
378+ // buffer wasn't replaced.
379+ self . buf . init = self . buf . filled + init;
380+ self . buf . filled += filled;
275381
276382 res
277383 }
0 commit comments