Skip to content

Commit 136d24f

Browse files
committed
core: Add BorrowedCursor::with_unfilled_buf
Implementation of rust-lang/libs-team#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.
1 parent f46ce66 commit 136d24f

File tree

2 files changed

+87
-0
lines changed

2 files changed

+87
-0
lines changed

library/core/src/io/borrowed_buf.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
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+
7289
impl<'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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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]
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+
}

0 commit comments

Comments
 (0)