#![allow(unused)]fnmain() {
pubtraitRead {
/// Reads data into `buf`, returning the number of bytes written.fnread(&mutself, buf: &mut [u8]) -> io::Result<usize>;
}
}
#![allow(unused)]fnmain() {
// The base level buffer uses the `MaybeUninit` type to avoid having to initialize the whole 8kb of memory up-front.letmut buf = [MaybeUninit::<u8>::uninit(); 8192];
// We then wrap that in a `ReadBuf` to track the state of the buffer.letmut buf = ReadBuf::uninit(&mut buf);
loop {
// Read some data into the buffer.
some_reader.read_buf(&mut buf)?;
// If nothing was written into the buffer, we're at EOF.if buf.filled().is_empty() {
break;
}
// Otherwise, process the data.
process_data(buf.filled());
// And then clear the buffer out so we can read into it again. This just resets the amount of filled data to 0,// but preserves the memory of how much of the buffer has been initialized.
buf.clear();
}
}
#![allow(unused)]fnmain() {
impl Read for MyReader {
fnread_buf(&mutself, buf: &mut ReadBuf<'_>) -> io::Result<()> {
// Get access to the unwritten part of the buffer, making sure it has been fully initialized. Since `ReadBuf`// tracks the initialization state of the buffer, this is "free" after the first time it's called.let unfilled: &mut [u8] = buf.initialize_unfilled();
// Fill the whole buffer with some nonsense.for (i, byte) in unfilled.iter_mut().enumerate() {
*byte = i asu8;
}
// And indicate that we've written the whole thing.let len = unfilled.len();
buf.add_filled(len);
Ok(())
}
}
}
AnunsafeReadimplementation:
実装
#![allow(unused)]fnmain() {
impl Read for TcpStream {
fnread_buf(&mutself, buf: &mut ReadBuf<'_>) -> io::Result<()> {
unsafe {
// Get access to the filled part of the buffer, without initializing it. This method is unsafe; we are// responsible for ensuring that we don't "de-initialize" portions of it that have previously been// initialized.let unfilled: &mut [MaybeUninit<u8>] = buf.unfilled_mut();
// We're just delegating to the libc read function, which returns an `isize`. The return value indicates// an error if negative and the number of bytes read otherwise.let nread = libc::read(self.fd, unfilled.as_mut_ptr().cast::<libc::c_void>(), unfilled.len());
if nread < 0 {
returnErr(io::Error::last_os_error());
}
let nread = nread asusize;
// If the read succeeded, tell the buffer that the read-to portion has been initialized. This method is// unsafe; we are responsible for ensuring that this portion of the buffer has actually been initialized.
buf.assume_init(nread);
// And indicate that we've written the bytes as well. Unlike `assume_initialized`, this method is safe,// and asserts that the written portion of the buffer does not advance beyond the initialized portion of// the buffer. If we didn't call `assume_init` above, this call could panic.
buf.add_filled(nread);
Ok(())
}
}
}
}
#![allow(unused)]fnmain() {
/// 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 is fully 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 ]/// ```pubstructReadBuf<'a> {
buf: &'amut [MaybeUninit<u8>],
filled: usize,
initialized: usize,
}
impl<'a> ReadBuf<'a> {
/// Creates a new `ReadBuf` from a fully initialized buffer.#[inline]pubfnnew(buf: &'amut [u8]) -> ReadBuf<'a> { ... }
/// Creates a new `ReadBuf` from a fully uninitialized buffer.////// Use `assume_init` if part of the buffer is known to be already inintialized.#[inline]pubfnuninit(buf: &'amut [MaybeUninit<u8>]) -> ReadBuf<'a> { ... }
/// Returns the total capacity of the buffer.#[inline]pubfncapacity(&self) -> usize { ... }
/// Returns a shared reference to the filled portion of the buffer.#[inline]pubfnfilled(&self) -> &[u8] { ... }
/// Returns a mutable reference to the filled portion of the buffer.#[inline]pubfnfilled_mut(&mutself) -> &mut [u8] { ... }
/// Returns a shared reference to the initialized portion of the buffer.////// This includes the filled portion.#[inline]pubfninitialized(&self) -> &[u8] { ... }
/// Returns a mutable reference to the initialized portion of the buffer.////// This includes the filled portion.#[inline]pubfninitialized_mut(&mutself) -> &mut [u8] { ... }
/// 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.#[inline]pubunsafefnunfilled_mut(&mutself) -> &mut [MaybeUninit<u8>] { ... }
/// 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]pubfninitialize_unfilled(&mutself) -> &mut [u8] { ... }
/// 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]pubfninitialize_unfilled_to(&mutself, n: usize) -> &mut [u8] { ... }
/// Returns the number of bytes at the end of the slice that have not yet been filled.#[inline]pubfnremaining(&self) -> usize { ... }
/// 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]pubfnclear(&mutself) { ... }
/// Increases 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]pubfnadd_filled(&mutself, n: usize) { ... }
/// 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 `Read` implementation that compresses data in-place).////// # Panics////// Panics if the filled region of the buffer would become larger than the initialized region.#[inline]pubfnset_filled(&mutself, n: usize) { ... }
/// 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 the first `n` unfilled bytes of the buffer have already been initialized.#[inline]pubunsafefnassume_init(&mutself, n: usize) { ... }
/// 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]pubfnappend(&mutself, buf: &[u8]) { ... }
}
}
TheReadtraitusesthistypeinsomeofitsmethods:
#![allow(unused)]fnmain() {
pubtraitRead {
/// Pull some bytes from this source into the specified buffer.////// This is equivalent to the `read` method, except that it is passed a `ReadBuf` rather than `[u8]` to allow use/// with uninitialized buffers. The new data will be appended to any existing contents of `buf`.////// The default implementation delegates to `read`.fnread_buf(&mutself, buf: &mut ReadBuf<'_>) -> io::Result<()> {
let n = self.read(buf.initialize_unfilled())?;
buf.add_filled(n);
Ok(())
}
...
}
}
#![allow(unused)]fnmain() {
/// A possibly-uninitialized version of `IoSliceMut`.////// It is guaranteed to have exactly the same layout and ABI as `IoSliceMut`.pubstructMaybeUninitIoSliceMut<'a> { ... }
impl<'a> MaybeUninitIoSliceMut<'a> {
/// Creates a new `MaybeUninitIoSliceMut` from a slice of maybe-uninitialized bytes.#[inline]pubfnnew(buf: &'amut [MaybeUninit<u8>]) -> MaybeUninitIoSliceMut<'a> { ... }
}
impl<'a> Deref for MaybeUninitIoSliceMut<'a> {
typeTarget = [MaybeUninit<u8>];
...
}
impl<'a> DerefMut for MaybeUninitIoSliceMut<'a> { ... }
/// A wrapper over a set of incrementally-initialized buffers.pubstructReadBufs<'a> { ... }
impl<'a> ReadBufs<'a> {
/// Creates a new `ReadBufs` from a set of fully initialized buffers.#[inline]pubfnnew(bufs: &'amut [IoSliceMut<'a>]) -> ReadBufs<'a> { ... }
/// Creates a new `ReadBufs` from a set of fully uninitialized buffers.////// Use `assume_init` if part of the buffers are known to be already initialized.#[inline]pubfnuninit(bufs: &'amut [MaybeUninitIoSliceMut<'a>]) -> ReadBufs<'a> { ... }
...
}
pubtraitRead {
/// Pull some bytes from this source into the specified set of buffers.////// This is equivalent to the `read_vectored` method, except that it is passed a `ReadBufs` rather than/// `[IoSliceMut]` to allow use with uninitialized buffers. The new data will be appended to any existing contents/// of `bufs`.////// The default implementation delegates to `read_vectored`.fnread_buf_vectored(&mutself, bufs: &mut ReadBufs<'_>) -> io::Result<()> {
...
}
}
}