| author | bors <bors@rust-lang.org> 2025-07-14 23:45:18 UTC |
| committer | bors <bors@rust-lang.org> 2025-07-14 23:45:18 UTC |
| log | 7f2065a4bae1faed5bab928c670964eafbf43b55 |
| tree | 0267da187683353f1bd499bb44531639285b08c8 |
| parent | a001497644bc229f1abcc5b2528733386591647f |
| parent | 136d24fd7f2cd8685d0f92e672f7d43aac62fedf |
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#1176932 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> { |
| 69 | 69 | } |
| 70 | 70 | } |
| 71 | 71 | |
| 72 | /// Creates a new `BorrowedBuf` from a cursor. | |
| 73 | /// | |
| 74 | /// Use `BorrowedCursor::with_unfilled_buf` instead for a safer alternative. | |
| 75 | impl<'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 | ||
| 72 | 89 | impl<'data> BorrowedBuf<'data> { |
| 73 | 90 | /// Returns the total capacity of the buffer. |
| 74 | 91 | #[inline] |
| ... | ... | @@ -353,4 +370,38 @@ impl<'a> BorrowedCursor<'a> { |
| 353 | 370 | } |
| 354 | 371 | self.buf.filled += buf.len(); |
| 355 | 372 | } |
| 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 | } | |
| 356 | 407 | } |
library/coretests/tests/io/borrowed_buf.rs+36| ... | ... | @@ -165,3 +165,39 @@ fn cursor_set_init() { |
| 165 | 165 | assert_eq!(rbuf.unfilled().uninit_mut().len(), 4); |
| 166 | 166 | assert_eq!(unsafe { rbuf.unfilled().as_mut().len() }, 12); |
| 167 | 167 | } |
| 168 | ||
| 169 | #[test] | |
| 170 | fn 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 | } |