read_buf
This commit is contained in:
parent
3802025f40
commit
98c6200b16
18 changed files with 772 additions and 294 deletions
|
@ -256,7 +256,6 @@ use crate::convert::TryInto;
|
|||
use crate::fmt;
|
||||
use crate::mem::replace;
|
||||
use crate::ops::{Deref, DerefMut};
|
||||
use crate::ptr;
|
||||
use crate::slice;
|
||||
use crate::str;
|
||||
use crate::sys;
|
||||
|
@ -288,12 +287,16 @@ pub use self::stdio::{_eprint, _print};
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use self::util::{empty, repeat, sink, Empty, Repeat, Sink};
|
||||
|
||||
#[unstable(feature = "read_buf", issue = "78485")]
|
||||
pub use self::readbuf::ReadBuf;
|
||||
|
||||
mod buffered;
|
||||
pub(crate) mod copy;
|
||||
mod cursor;
|
||||
mod error;
|
||||
mod impls;
|
||||
pub mod prelude;
|
||||
mod readbuf;
|
||||
mod stdio;
|
||||
mod util;
|
||||
|
||||
|
@ -359,68 +362,39 @@ where
|
|||
// Because we're extending the buffer with uninitialized data for trusted
|
||||
// readers, we need to make sure to truncate that if any of this panics.
|
||||
pub(crate) fn default_read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> {
|
||||
let start_len = buf.len();
|
||||
let start_cap = buf.capacity();
|
||||
let mut g = Guard { len: buf.len(), buf };
|
||||
let initial_len = buf.len(); // need to know so we can return how many bytes we read
|
||||
|
||||
let mut initialized = 0; // Extra initalized bytes from previous loop iteration
|
||||
loop {
|
||||
// If we've read all the way up to the capacity, reserve more space.
|
||||
if g.len == g.buf.capacity() {
|
||||
g.buf.reserve(32);
|
||||
if buf.len() == buf.capacity() {
|
||||
buf.reserve(32); // buf is full, need more space
|
||||
}
|
||||
|
||||
// Initialize any excess capacity and adjust the length so we can write
|
||||
// to it.
|
||||
if g.buf.len() < g.buf.capacity() {
|
||||
unsafe {
|
||||
// FIXME(danielhenrymantilla): #42788
|
||||
//
|
||||
// - This creates a (mut) reference to a slice of
|
||||
// _uninitialized_ integers, which is **undefined behavior**
|
||||
//
|
||||
// - Only the standard library gets to soundly "ignore" this,
|
||||
// based on its privileged knowledge of unstable rustc
|
||||
// internals;
|
||||
let capacity = g.buf.capacity();
|
||||
g.buf.set_len(capacity);
|
||||
r.initializer().initialize(&mut g.buf[g.len..]);
|
||||
}
|
||||
let mut read_buf = ReadBuf::uninit(buf.spare_capacity_mut());
|
||||
unsafe {
|
||||
// add back extra initalized bytes, we don't want to reinitalize initalized bytes
|
||||
read_buf.assume_init(initialized);
|
||||
}
|
||||
|
||||
let buf = &mut g.buf[g.len..];
|
||||
match r.read(buf) {
|
||||
Ok(0) => return Ok(g.len - start_len),
|
||||
Ok(n) => {
|
||||
// We can't allow bogus values from read. If it is too large, the returned vec could have its length
|
||||
// set past its capacity, or if it overflows the vec could be shortened which could create an invalid
|
||||
// string if this is called via read_to_string.
|
||||
assert!(n <= buf.len());
|
||||
g.len += n;
|
||||
}
|
||||
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
|
||||
match r.read_buf(&mut read_buf) {
|
||||
Ok(()) => {}
|
||||
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
|
||||
if g.len == g.buf.capacity() && g.buf.capacity() == start_cap {
|
||||
// The buffer might be an exact fit. Let's read into a probe buffer
|
||||
// and see if it returns `Ok(0)`. If so, we've avoided an
|
||||
// unnecessary doubling of the capacity. But if not, append the
|
||||
// probe buffer to the primary buffer and let its capacity grow.
|
||||
let mut probe = [0u8; 32];
|
||||
if read_buf.filled_len() == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
loop {
|
||||
match r.read(&mut probe) {
|
||||
Ok(0) => return Ok(g.len - start_len),
|
||||
Ok(n) => {
|
||||
g.buf.extend_from_slice(&probe[..n]);
|
||||
g.len += n;
|
||||
break;
|
||||
}
|
||||
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
// store how much was initialized but not filled
|
||||
initialized = read_buf.initialized_len() - read_buf.filled_len();
|
||||
let new_len = read_buf.filled_len() + buf.len();
|
||||
unsafe {
|
||||
buf.set_len(new_len);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(buf.len() - initial_len)
|
||||
}
|
||||
|
||||
pub(crate) fn default_read_to_string<R: Read + ?Sized>(
|
||||
|
@ -656,31 +630,6 @@ pub trait Read {
|
|||
false
|
||||
}
|
||||
|
||||
/// Determines if this `Read`er can work with buffers of uninitialized
|
||||
/// memory.
|
||||
///
|
||||
/// The default implementation returns an initializer which will zero
|
||||
/// buffers.
|
||||
///
|
||||
/// If a `Read`er guarantees that it can work properly with uninitialized
|
||||
/// memory, it should call [`Initializer::nop()`]. See the documentation for
|
||||
/// [`Initializer`] for details.
|
||||
///
|
||||
/// The behavior of this method must be independent of the state of the
|
||||
/// `Read`er - the method only takes `&self` so that it can be used through
|
||||
/// trait objects.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This method is unsafe because a `Read`er could otherwise return a
|
||||
/// non-zeroing `Initializer` from another `Read` type without an `unsafe`
|
||||
/// block.
|
||||
#[unstable(feature = "read_initializer", issue = "42788")]
|
||||
#[inline]
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
Initializer::zeroing()
|
||||
}
|
||||
|
||||
/// Read all bytes until EOF in this source, placing them into `buf`.
|
||||
///
|
||||
/// All bytes read from this source will be appended to the specified buffer
|
||||
|
@ -830,7 +779,42 @@ pub trait Read {
|
|||
default_read_exact(self, buf)
|
||||
}
|
||||
|
||||
/// Creates a "by reference" adapter for this instance of `Read`.
|
||||
/// Pull some bytes from this source into the specified buffer.
|
||||
///
|
||||
/// This is equivalent to the [`read`](Read::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`.
|
||||
#[unstable(feature = "read_buf", issue = "78485")]
|
||||
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> {
|
||||
let n = self.read(buf.initialize_unfilled())?;
|
||||
buf.add_filled(n);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Read the exact number of bytes required to fill `buf`.
|
||||
///
|
||||
/// This is equivalent to the [`read_exact`](Read::read_exact) method, except that it is passed a [`ReadBuf`] rather than `[u8]` to
|
||||
/// allow use with uninitialized buffers.
|
||||
#[unstable(feature = "read_buf", issue = "78485")]
|
||||
fn read_buf_exact(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> {
|
||||
while buf.remaining() > 0 {
|
||||
let prev_filled = buf.filled().len();
|
||||
match self.read_buf(buf) {
|
||||
Ok(()) => {}
|
||||
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
|
||||
if buf.filled().len() == prev_filled {
|
||||
return Err(Error::new(ErrorKind::UnexpectedEof, "failed to fill buffer"));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Creates a "by reference" adaptor for this instance of `Read`.
|
||||
///
|
||||
/// The returned adapter also implements `Read` and will simply borrow this
|
||||
/// current reader.
|
||||
|
@ -1300,53 +1284,6 @@ impl<'a> Deref for IoSlice<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// A type used to conditionally initialize buffers passed to `Read` methods.
|
||||
#[unstable(feature = "read_initializer", issue = "42788")]
|
||||
#[derive(Debug)]
|
||||
pub struct Initializer(bool);
|
||||
|
||||
impl Initializer {
|
||||
/// Returns a new `Initializer` which will zero out buffers.
|
||||
#[unstable(feature = "read_initializer", issue = "42788")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn zeroing() -> Initializer {
|
||||
Initializer(true)
|
||||
}
|
||||
|
||||
/// Returns a new `Initializer` which will not zero out buffers.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This may only be called by `Read`ers which guarantee that they will not
|
||||
/// read from buffers passed to `Read` methods, and that the return value of
|
||||
/// the method accurately reflects the number of bytes that have been
|
||||
/// written to the head of the buffer.
|
||||
#[unstable(feature = "read_initializer", issue = "42788")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub unsafe fn nop() -> Initializer {
|
||||
Initializer(false)
|
||||
}
|
||||
|
||||
/// Indicates if a buffer should be initialized.
|
||||
#[unstable(feature = "read_initializer", issue = "42788")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn should_initialize(&self) -> bool {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Initializes a buffer if necessary.
|
||||
#[unstable(feature = "read_initializer", issue = "42788")]
|
||||
#[inline]
|
||||
pub fn initialize(&self, buf: &mut [u8]) {
|
||||
if self.should_initialize() {
|
||||
unsafe { ptr::write_bytes(buf.as_mut_ptr(), 0, buf.len()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait for objects which are byte-oriented sinks.
|
||||
///
|
||||
/// Implementors of the `Write` trait are sometimes called 'writers'.
|
||||
|
@ -2403,11 +2340,6 @@ impl<T: Read, U: Read> Read for Chain<T, U> {
|
|||
}
|
||||
self.second.read_vectored(bufs)
|
||||
}
|
||||
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
let initializer = self.first.initializer();
|
||||
if initializer.should_initialize() { initializer } else { self.second.initializer() }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "chain_bufread", since = "1.9.0")]
|
||||
|
@ -2610,8 +2542,46 @@ impl<T: Read> Read for Take<T> {
|
|||
Ok(n)
|
||||
}
|
||||
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
self.inner.initializer()
|
||||
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> {
|
||||
// Don't call into inner reader at all at EOF because it may still block
|
||||
if self.limit == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let prev_filled = buf.filled_len();
|
||||
|
||||
if self.limit <= buf.remaining() as u64 {
|
||||
let extra_init = buf.initialized_len() - buf.filled_len();
|
||||
let ibuf = unsafe { &mut buf.unfilled_mut()[..self.limit as usize] };
|
||||
|
||||
let mut sliced_buf = ReadBuf::uninit(ibuf);
|
||||
|
||||
unsafe {
|
||||
sliced_buf.assume_init(extra_init);
|
||||
}
|
||||
|
||||
self.inner.read_buf(&mut sliced_buf)?;
|
||||
|
||||
let new_init = sliced_buf.initialized_len();
|
||||
let filled = sliced_buf.filled_len();
|
||||
|
||||
// sliced_buf / ibuf must drop here
|
||||
|
||||
unsafe {
|
||||
buf.assume_init(new_init);
|
||||
}
|
||||
|
||||
buf.add_filled(filled);
|
||||
|
||||
self.limit -= filled as u64;
|
||||
} else {
|
||||
self.inner.read_buf(buf)?;
|
||||
|
||||
//inner may unfill
|
||||
self.limit -= buf.filled_len().saturating_sub(prev_filled) as u64;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue