authorbors <bors@rust-lang.org> 2025-07-14 23:45:18 UTC
committerbors <bors@rust-lang.org> 2025-07-14 23:45:18 UTC
log7f2065a4bae1faed5bab928c670964eafbf43b55
tree0267da187683353f1bd499bb44531639285b08c8
parenta001497644bc229f1abcc5b2528733386591647f
parent136d24fd7f2cd8685d0f92e672f7d43aac62fedf

Auto merge of #142885 - a1phyr:borrowed_cursor_to_buf, r=Mark-Simulacrum

core: Add `BorrowedCursor::with_unfilled_buf` Implementation of https://github.com/rust-lang/libs-team/issues/367. This mainly adds `BorrowedCursor::with_unfilled_buf`, with enables using the unfilled part of a cursor as a `BorrowedBuf`. Note that unlike the ACP, `BorrowedCursor::unfilled_buf` was moved to a `From` conversion. This is more consistent with other ways of creating a `BorrowedBuf` and hides a bit this conversion that requires unsafe code to be used correctly. Cc rust-lang/rust#78485 rust-lang/rust#117693

2 files changed, 87 insertions(+), 0 deletions(-)

library/core/src/io/borrowed_buf.rs+51
......@@ -69,6 +69,23 @@ impl<'data> From<&'data mut [MaybeUninit<u8>]> for BorrowedBuf<'data> {
6969 }
7070}
7171
72/// Creates a new `BorrowedBuf` from a cursor.
73///
74/// Use `BorrowedCursor::with_unfilled_buf` instead for a safer alternative.
75impl<'data> From<BorrowedCursor<'data>> for BorrowedBuf<'data> {
76 #[inline]
77 fn from(mut buf: BorrowedCursor<'data>) -> BorrowedBuf<'data> {
78 let init = buf.init_mut().len();
79 BorrowedBuf {
80 // SAFETY: no initialized byte is ever uninitialized as per
81 // `BorrowedBuf`'s invariant
82 buf: unsafe { buf.buf.buf.get_unchecked_mut(buf.buf.filled..) },
83 filled: 0,
84 init,
85 }
86 }
87}
88
7289impl<'data> BorrowedBuf<'data> {
7390 /// Returns the total capacity of the buffer.
7491 #[inline]
......@@ -353,4 +370,38 @@ impl<'a> BorrowedCursor<'a> {
353370 }
354371 self.buf.filled += buf.len();
355372 }
373
374 /// Runs the given closure with a `BorrowedBuf` containing the unfilled part
375 /// of the cursor.
376 ///
377 /// This enables inspecting what was written to the cursor.
378 ///
379 /// # Panics
380 ///
381 /// Panics if the `BorrowedBuf` given to the closure is replaced by another
382 /// one.
383 pub fn with_unfilled_buf<T>(&mut self, f: impl FnOnce(&mut BorrowedBuf<'_>) -> T) -> T {
384 let mut buf = BorrowedBuf::from(self.reborrow());
385 let prev_ptr = buf.buf as *const _;
386 let res = f(&mut buf);
387
388 // Check that the caller didn't replace the `BorrowedBuf`.
389 // This is necessary for the safety of the code below: if the check wasn't
390 // there, one could mark some bytes as initialized even though there aren't.
391 assert!(core::ptr::addr_eq(prev_ptr, buf.buf));
392
393 let filled = buf.filled;
394 let init = buf.init;
395
396 // Update `init` and `filled` fields with what was written to the buffer.
397 // `self.buf.filled` was the starting length of the `BorrowedBuf`.
398 //
399 // SAFETY: These amounts of bytes were initialized/filled in the `BorrowedBuf`,
400 // and therefore they are initialized/filled in the cursor too, because the
401 // buffer wasn't replaced.
402 self.buf.init = self.buf.filled + init;
403 self.buf.filled += filled;
404
405 res
406 }
356407}
library/coretests/tests/io/borrowed_buf.rs+36
......@@ -165,3 +165,39 @@ fn cursor_set_init() {
165165 assert_eq!(rbuf.unfilled().uninit_mut().len(), 4);
166166 assert_eq!(unsafe { rbuf.unfilled().as_mut().len() }, 12);
167167}
168
169#[test]
170fn cursor_with_unfilled_buf() {
171 let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16];
172 let mut rbuf = BorrowedBuf::from(buf);
173 let mut cursor = rbuf.unfilled();
174
175 cursor.with_unfilled_buf(|buf| {
176 buf.unfilled().append(&[1, 2, 3]);
177 assert_eq!(buf.filled(), &[1, 2, 3]);
178 });
179
180 assert_eq!(cursor.init_mut().len(), 0);
181 assert_eq!(cursor.written(), 3);
182
183 cursor.with_unfilled_buf(|buf| {
184 assert_eq!(buf.capacity(), 13);
185 assert_eq!(buf.init_len(), 0);
186
187 buf.unfilled().ensure_init();
188 buf.unfilled().advance(4);
189 });
190
191 assert_eq!(cursor.init_mut().len(), 9);
192 assert_eq!(cursor.written(), 7);
193
194 cursor.with_unfilled_buf(|buf| {
195 assert_eq!(buf.capacity(), 9);
196 assert_eq!(buf.init_len(), 9);
197 });
198
199 assert_eq!(cursor.init_mut().len(), 9);
200 assert_eq!(cursor.written(), 7);
201
202 assert_eq!(rbuf.filled(), &[1, 2, 3, 0, 0, 0, 0]);
203}