diff options
Diffstat (limited to 'library/std/src/io/mod.rs')
| -rw-r--r-- | library/std/src/io/mod.rs | 236 | 
1 files changed, 103 insertions, 133 deletions
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 8cc91566418..c1e3afd389d 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -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]; - - 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), - } - } + if read_buf.filled_len() == 0 { + break; + } + + // 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(()) } }  | 
