/// A wrapper around a byte buffer that is incrementally filled and initialized. /// /// This type is a sort of "double cursor". It tracks three regions in the /// buffer: a region at the beginning of the buffer that has been logically /// filled with data, a region that has been initialized at some point but not /// yet logically filled, and a region at the end that may be uninitialized. /// The filled region is guaranteed to be a subset of the initialized region. /// /// In summary, the contents of the buffer can be visualized as: /// /// ```not_rust /// [ capacity ] /// [ filled | unfilled ] /// [ initialized | uninitialized ] /// ``` /// /// It is undefined behavior to de-initialize any bytes from the uninitialized /// region, since it is merely unknown whether this region is uninitialized or /// not, and if part of it turns out to be initialized, it must stay initialized. pubstruct ReadBuf<'a> {
buf: &'a mut [MaybeUninit<u8>],
filled: usize,
initialized: usize,
}
impl<'a> ReadBuf<'a> { /// Creates a new `ReadBuf` from a fully initialized buffer. #[inline] pubfn new(buf: &'a mut [u8]) -> ReadBuf<'a> { let initialized = buf.len(); let buf = unsafe { slice_to_uninit_mut(buf) };
ReadBuf {
buf,
filled: 0,
initialized,
}
}
/// Creates a new `ReadBuf` from a fully uninitialized buffer. /// /// Use `assume_init` if part of the buffer is known to be already initialized. #[inline] pubfn uninit(buf: &'a mut [MaybeUninit<u8>]) -> ReadBuf<'a> {
ReadBuf {
buf,
filled: 0,
initialized: 0,
}
}
/// Returns the total capacity of the buffer. #[inline] pubfn capacity(&self) -> usize { self.buf.len()
}
/// Returns a shared reference to the filled portion of the buffer. #[inline] pubfn filled(&self) -> &[u8] { let slice = &self.buf[..self.filled]; // safety: filled describes how far into the buffer that the // user has filled with bytes, so it's been initialized. unsafe { slice_assume_init(slice) }
}
/// Returns a mutable reference to the filled portion of the buffer. #[inline] pubfn filled_mut(&mutself) -> &mut [u8] { let slice = &mutself.buf[..self.filled]; // safety: filled describes how far into the buffer that the // user has filled with bytes, so it's been initialized. unsafe { slice_assume_init_mut(slice) }
}
/// Returns a new `ReadBuf` comprised of the unfilled section up to `n`. #[inline] pubfn take(&mutself, n: usize) -> ReadBuf<'_> { let max = std::cmp::min(self.remaining(), n); // Safety: We don't set any of the `unfilled_mut` with `MaybeUninit::uninit`. unsafe { ReadBuf::uninit(&mutself.unfilled_mut()[..max]) }
}
/// Returns a shared reference to the initialized portion of the buffer. /// /// This includes the filled portion. #[inline] pubfn initialized(&self) -> &[u8] { let slice = &self.buf[..self.initialized]; // safety: initialized describes how far into the buffer that the // user has at some point initialized with bytes. unsafe { slice_assume_init(slice) }
}
/// Returns a mutable reference to the initialized portion of the buffer. /// /// This includes the filled portion. #[inline] pubfn initialized_mut(&mutself) -> &mut [u8] { let slice = &mutself.buf[..self.initialized]; // safety: initialized describes how far into the buffer that the // user has at some point initialized with bytes. unsafe { slice_assume_init_mut(slice) }
}
/// Returns a mutable reference to the entire buffer, without ensuring that it has been fully /// initialized. /// /// The elements between 0 and `self.filled().len()` are filled, and those between 0 and /// `self.initialized().len()` are initialized (and so can be converted to a `&mut [u8]`). /// /// The caller of this method must ensure that these invariants are upheld. For example, if the /// caller initializes some of the uninitialized section of the buffer, it must call /// [`assume_init`](Self::assume_init) with the number of bytes initialized. /// /// # Safety /// /// The caller must not de-initialize portions of the buffer that have already been initialized. /// This includes any bytes in the region marked as uninitialized by `ReadBuf`. #[inline] pubunsafefn inner_mut(&mutself) -> &mut [MaybeUninit<u8>] { self.buf
}
/// Returns a mutable reference to the unfilled part of the buffer without ensuring that it has been fully /// initialized. /// /// # Safety /// /// The caller must not de-initialize portions of the buffer that have already been initialized. /// This includes any bytes in the region marked as uninitialized by `ReadBuf`. #[inline] pubunsafefn unfilled_mut(&mutself) -> &mut [MaybeUninit<u8>] {
&mutself.buf[self.filled..]
}
/// Returns a mutable reference to the unfilled part of the buffer, ensuring it is fully initialized. /// /// Since `ReadBuf` tracks the region of the buffer that has been initialized, this is effectively "free" after /// the first use. #[inline] pubfn initialize_unfilled(&mutself) -> &mut [u8] { self.initialize_unfilled_to(self.remaining())
}
/// Returns a mutable reference to the first `n` bytes of the unfilled part of the buffer, ensuring it is /// fully initialized. /// /// # Panics /// /// Panics if `self.remaining()` is less than `n`. #[inline] #[track_caller] pubfn initialize_unfilled_to(&mutself, n: usize) -> &mut [u8] {
assert!(self.remaining() >= n, "n overflows remaining");
// This can't overflow, otherwise the assert above would have failed. let end = self.filled + n;
ifself.initialized < end { unsafe { self.buf[self.initialized..end]
.as_mut_ptr()
.write_bytes(0, end - self.initialized);
} self.initialized = end;
}
let slice = &mutself.buf[self.filled..end]; // safety: just above, we checked that the end of the buf has // been initialized to some value. unsafe { slice_assume_init_mut(slice) }
}
/// Returns the number of bytes at the end of the slice that have not yet been filled. #[inline] pubfn remaining(&self) -> usize { self.capacity() - self.filled
}
/// Clears the buffer, resetting the filled region to empty. /// /// The number of initialized bytes is not changed, and the contents of the buffer are not modified. #[inline] pubfn clear(&mutself) { self.filled = 0;
}
/// Advances the size of the filled region of the buffer. /// /// The number of initialized bytes is not changed. /// /// # Panics /// /// Panics if the filled region of the buffer would become larger than the initialized region. #[inline] #[track_caller] pubfn advance(&mutself, n: usize) { let new = self.filled.checked_add(n).expect("filled overflow"); self.set_filled(new);
}
/// Sets the size of the filled region of the buffer. /// /// The number of initialized bytes is not changed. /// /// Note that this can be used to *shrink* the filled region of the buffer in addition to growing it (for /// example, by a `AsyncRead` implementation that compresses data in-place). /// /// # Panics /// /// Panics if the filled region of the buffer would become larger than the initialized region. #[inline] #[track_caller] pubfn set_filled(&mutself, n: usize) {
assert!(
n <= self.initialized, "filled must not become larger than initialized"
); self.filled = n;
}
/// Asserts that the first `n` unfilled bytes of the buffer are initialized. /// /// `ReadBuf` assumes that bytes are never de-initialized, so this method does nothing when called with fewer /// bytes than are already known to be initialized. /// /// # Safety /// /// The caller must ensure that `n` unfilled bytes of the buffer have already been initialized. #[inline] pubunsafefn assume_init(&mutself, n: usize) { let new = self.filled + n; if new > self.initialized { self.initialized = new;
}
}
/// Appends data to the buffer, advancing the written position and possibly also the initialized position. /// /// # Panics /// /// Panics if `self.remaining()` is less than `buf.len()`. #[inline] #[track_caller] pubfn put_slice(&mutself, buf: &[u8]) {
assert!( self.remaining() >= buf.len(), "buf.len() must fit in remaining(); buf.len() = {}, remaining() = {}",
buf.len(), self.remaining()
);
let amt = buf.len(); // Cannot overflow, asserted above let end = self.filled + amt;
// Safety: the length is asserted above unsafe { self.buf[self.filled..end]
.as_mut_ptr()
.cast::<u8>()
.copy_from_nonoverlapping(buf.as_ptr(), amt);
}
// SAFETY: The caller guarantees that at least `cnt` unfilled bytes have been initialized. unsafefn advance_mut(&mutself, cnt: usize) { self.assume_init(cnt); self.advance(cnt);
}
fn chunk_mut(&mutself) -> &mut bytes::buf::UninitSlice { // SAFETY: No region of `unfilled` will be deinitialized because it is // exposed as an `UninitSlice`, whose API guarantees that the memory is // never deinitialized. let unfilled = unsafe { self.unfilled_mut() }; let len = unfilled.len(); let ptr = unfilled.as_mut_ptr() as *mut u8;
// SAFETY: The pointer is valid for `len` bytes because it comes from a // slice of that length. unsafe { bytes::buf::UninitSlice::from_raw_parts_mut(ptr, len) }
}
}
unsafefn slice_to_uninit_mut(slice: &mut [u8]) -> &mut [MaybeUninit<u8>] {
&mut *(slice as *mut [u8] as *mut [MaybeUninit<u8>])
}
// TODO: This could use `MaybeUninit::slice_assume_init` when it is stable. unsafefn slice_assume_init(slice: &[MaybeUninit<u8>]) -> &[u8] {
&*(slice as *const [MaybeUninit<u8>] as *const [u8])
}
// TODO: This could use `MaybeUninit::slice_assume_init_mut` when it is stable. unsafefn slice_assume_init_mut(slice: &mut [MaybeUninit<u8>]) -> &pan style='color:red'>mut [u8] {
&mut *(slice as *mut [MaybeUninit<u8>] as *mut [u8])
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.16 Sekunden
(vorverarbeitet am 2026-06-18)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.