diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index a14f1e2ecb2c4..014d5119b05fd 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -13,7 +13,7 @@ mod tests; use crate::ffi::OsString; use crate::fmt; -use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; +use crate::io::{self, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write}; use crate::path::{Path, PathBuf}; use crate::sys::fs as fs_imp; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; @@ -623,15 +623,13 @@ impl Read for File { self.inner.read_vectored(bufs) } - #[inline] - fn is_read_vectored(&self) -> bool { - self.inner.is_read_vectored() + fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + self.inner.read_buf(buf) } #[inline] - unsafe fn initializer(&self) -> Initializer { - // SAFETY: Read is guaranteed to work on uninitialized memory - unsafe { Initializer::nop() } + fn is_read_vectored(&self) -> bool { + self.inner.is_read_vectored() } // Reserves space in the buffer based on the file size when available. @@ -677,6 +675,10 @@ impl Read for &File { self.inner.read(buf) } + fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + self.inner.read_buf(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.inner.read_vectored(bufs) } @@ -686,12 +688,6 @@ impl Read for &File { self.inner.is_read_vectored() } - #[inline] - unsafe fn initializer(&self) -> Initializer { - // SAFETY: Read is guaranteed to work on uninitialized memory - unsafe { Initializer::nop() } - } - // Reserves space in the buffer based on the file size when available. fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { buf.reserve(buffer_capacity_required(self)); diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index 2864e94f60f2c..b56dc65f0b2f3 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -1,8 +1,9 @@ use crate::cmp; use crate::fmt; use crate::io::{ - self, BufRead, Initializer, IoSliceMut, Read, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE, + self, BufRead, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE, }; +use crate::mem::MaybeUninit; /// The `BufReader` struct adds buffering to any reader. /// @@ -47,9 +48,10 @@ use crate::io::{ #[stable(feature = "rust1", since = "1.0.0")] pub struct BufReader { inner: R, - buf: Box<[u8]>, + buf: Box<[MaybeUninit]>, pos: usize, cap: usize, + init: usize, } impl BufReader { @@ -91,11 +93,8 @@ impl BufReader { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(capacity: usize, inner: R) -> BufReader { - unsafe { - let mut buf = Box::new_uninit_slice(capacity).assume_init(); - inner.initializer().initialize(&mut buf); - BufReader { inner, buf, pos: 0, cap: 0 } - } + let buf = Box::new_uninit_slice(capacity); + BufReader { inner, buf, pos: 0, cap: 0, init: 0 } } } @@ -171,7 +170,8 @@ impl BufReader { /// ``` #[stable(feature = "bufreader_buffer", since = "1.37.0")] pub fn buffer(&self) -> &[u8] { - &self.buf[self.pos..self.cap] + // SAFETY: self.cap is always <= self.init, so self.buf[self.pos..self.cap] is always init + unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[self.pos..self.cap]) } } /// Returns the number of bytes the internal buffer can hold at once. @@ -271,6 +271,25 @@ impl Read for BufReader { Ok(nread) } + fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + // If we don't have any buffered data and we're doing a massive read + // (larger than our internal buffer), bypass our internal buffer + // entirely. + if self.pos == self.cap && buf.remaining() >= self.buf.len() { + self.discard_buffer(); + return self.inner.read_buf(buf); + } + + let prev = buf.filled_len(); + + let mut rem = self.fill_buf()?; + rem.read_buf(buf)?; + + self.consume(buf.filled_len() - prev); //slice impl of read_buf known to never unfill buf + + Ok(()) + } + // Small read_exacts from a BufReader are extremely common when used with a deserializer. // The default implementation calls read in a loop, which results in surprisingly poor code // generation for the common path where the buffer has enough bytes to fill the passed-in @@ -303,16 +322,11 @@ impl Read for BufReader { self.inner.is_read_vectored() } - // we can't skip unconditionally because of the large buffer case in read. - unsafe fn initializer(&self) -> Initializer { - self.inner.initializer() - } - // The inner reader might have an optimized `read_to_end`. Drain our buffer and then // delegate to the inner implementation. fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { let nread = self.cap - self.pos; - buf.extend_from_slice(&self.buf[self.pos..self.cap]); + buf.extend_from_slice(&self.buffer()); self.discard_buffer(); Ok(nread + self.inner.read_to_end(buf)?) } @@ -363,10 +377,23 @@ impl BufRead for BufReader { // to tell the compiler that the pos..cap slice is always valid. if self.pos >= self.cap { debug_assert!(self.pos == self.cap); - self.cap = self.inner.read(&mut self.buf)?; + + let mut readbuf = ReadBuf::uninit(&mut self.buf); + + // SAFETY: `self.init` is either 0 or set to `readbuf.initialized_len()` + // from the last time this function was called + unsafe { + readbuf.assume_init(self.init); + } + + self.inner.read_buf(&mut readbuf)?; + + self.cap = readbuf.filled_len(); + self.init = readbuf.initialized_len(); + self.pos = 0; } - Ok(&self.buf[self.pos..self.cap]) + Ok(self.buffer()) } fn consume(&mut self, amt: usize) { diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs index feb149c07a525..9d429e7090e83 100644 --- a/library/std/src/io/buffered/tests.rs +++ b/library/std/src/io/buffered/tests.rs @@ -1,5 +1,6 @@ use crate::io::prelude::*; -use crate::io::{self, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, SeekFrom}; +use crate::io::{self, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, ReadBuf, SeekFrom}; +use crate::mem::MaybeUninit; use crate::panic; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::thread; @@ -55,6 +56,55 @@ fn test_buffered_reader() { assert_eq!(reader.read(&mut buf).unwrap(), 0); } +#[test] +fn test_buffered_reader_read_buf() { + let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; + let mut reader = BufReader::with_capacity(2, inner); + + let mut buf = [MaybeUninit::uninit(); 3]; + let mut buf = ReadBuf::uninit(&mut buf); + + reader.read_buf(&mut buf).unwrap(); + + assert_eq!(buf.filled(), [5, 6, 7]); + assert_eq!(reader.buffer(), []); + + let mut buf = [MaybeUninit::uninit(); 2]; + let mut buf = ReadBuf::uninit(&mut buf); + + reader.read_buf(&mut buf).unwrap(); + + assert_eq!(buf.filled(), [0, 1]); + assert_eq!(reader.buffer(), []); + + let mut buf = [MaybeUninit::uninit(); 1]; + let mut buf = ReadBuf::uninit(&mut buf); + + reader.read_buf(&mut buf).unwrap(); + + assert_eq!(buf.filled(), [2]); + assert_eq!(reader.buffer(), [3]); + + let mut buf = [MaybeUninit::uninit(); 3]; + let mut buf = ReadBuf::uninit(&mut buf); + + reader.read_buf(&mut buf).unwrap(); + + assert_eq!(buf.filled(), [3]); + assert_eq!(reader.buffer(), []); + + reader.read_buf(&mut buf).unwrap(); + + assert_eq!(buf.filled(), [3, 4]); + assert_eq!(reader.buffer(), []); + + buf.clear(); + + reader.read_buf(&mut buf).unwrap(); + + assert_eq!(buf.filled_len(), 0); +} + #[test] fn test_buffered_reader_seek() { let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs index eb60df214c489..6ab9666230524 100644 --- a/library/std/src/io/copy.rs +++ b/library/std/src/io/copy.rs @@ -1,4 +1,4 @@ -use super::{BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE}; +use super::{BufWriter, ErrorKind, Read, ReadBuf, Result, Write, DEFAULT_BUF_SIZE}; use crate::mem::MaybeUninit; /// Copies the entire contents of a reader into a writer. @@ -82,33 +82,30 @@ impl BufferedCopySpec for BufWriter { return stack_buffer_copy(reader, writer); } - // FIXME: #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; - unsafe { - let spare_cap = writer.buffer_mut().spare_capacity_mut(); - reader.initializer().initialize(MaybeUninit::slice_assume_init_mut(spare_cap)); - } - let mut len = 0; + let mut init = 0; loop { let buf = writer.buffer_mut(); - let spare_cap = buf.spare_capacity_mut(); - - if spare_cap.len() >= DEFAULT_BUF_SIZE { - match reader.read(unsafe { MaybeUninit::slice_assume_init_mut(spare_cap) }) { - Ok(0) => return Ok(len), // EOF reached - Ok(bytes_read) => { - assert!(bytes_read <= spare_cap.len()); - // SAFETY: The initializer contract guarantees that either it or `read` - // will have initialized these bytes. And we just checked that the number - // of bytes is within the buffer capacity. + let mut read_buf = ReadBuf::uninit(buf.spare_capacity_mut()); + + // SAFETY: init is either 0 or the initialized_len of the previous iteration + unsafe { + read_buf.assume_init(init); + } + + if read_buf.capacity() >= DEFAULT_BUF_SIZE { + match reader.read_buf(&mut read_buf) { + Ok(()) => { + let bytes_read = read_buf.filled_len(); + + if bytes_read == 0 { + return Ok(len); + } + + init = read_buf.initialized_len() - bytes_read; + + // SAFETY: ReadBuf guarantees all of its filled bytes are init unsafe { buf.set_len(buf.len() + bytes_read) }; len += bytes_read as u64; // Read again if the buffer still has enough capacity, as BufWriter itself would do @@ -129,28 +126,26 @@ fn stack_buffer_copy( reader: &mut R, writer: &mut W, ) -> Result { - let mut buf = MaybeUninit::<[u8; DEFAULT_BUF_SIZE]>::uninit(); - // FIXME: #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; - unsafe { - reader.initializer().initialize(buf.assume_init_mut()); - } + let mut buf = [MaybeUninit::uninit(); DEFAULT_BUF_SIZE]; + let mut buf = ReadBuf::uninit(&mut buf); + + let mut len = 0; - let mut written = 0; loop { - let len = match reader.read(unsafe { buf.assume_init_mut() }) { - Ok(0) => return Ok(written), - Ok(len) => len, - Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, + match reader.read_buf(&mut buf) { + Ok(()) => {} + Err(e) if e.kind() == ErrorKind::Interrupted => continue, Err(e) => return Err(e), }; - writer.write_all(unsafe { &buf.assume_init_ref()[..len] })?; - written += len as u64; + + if buf.filled().is_empty() { + break; + } + + len += buf.filled().len() as u64; + writer.write_all(buf.filled())?; + buf.clear(); } + + Ok(len) } diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index 980b2531192e8..416cc906e65a5 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -4,7 +4,7 @@ mod tests; use crate::io::prelude::*; use crate::cmp; -use crate::io::{self, Error, ErrorKind, Initializer, IoSlice, IoSliceMut, SeekFrom}; +use crate::io::{self, Error, ErrorKind, IoSlice, IoSliceMut, ReadBuf, SeekFrom}; use core::convert::TryInto; @@ -324,6 +324,16 @@ where Ok(n) } + fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + let prev_filled = buf.filled_len(); + + Read::read_buf(&mut self.fill_buf()?, buf)?; + + self.pos += (buf.filled_len() - prev_filled) as u64; + + Ok(()) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { let mut nread = 0; for buf in bufs { @@ -346,11 +356,6 @@ where self.pos += n as u64; Ok(()) } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index 7a2a49ba7d707..23201f9fc5c94 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -5,7 +5,7 @@ use crate::alloc::Allocator; use crate::cmp; use crate::fmt; use crate::io::{ - self, BufRead, Error, ErrorKind, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write, + self, BufRead, Error, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write, }; use crate::mem; @@ -19,6 +19,11 @@ impl Read for &mut R { (**self).read(buf) } + #[inline] + fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + (**self).read_buf(buf) + } + #[inline] fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { (**self).read_vectored(bufs) @@ -29,11 +34,6 @@ impl Read for &mut R { (**self).is_read_vectored() } - #[inline] - unsafe fn initializer(&self) -> Initializer { - (**self).initializer() - } - #[inline] fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { (**self).read_to_end(buf) @@ -123,6 +123,11 @@ impl Read for Box { (**self).read(buf) } + #[inline] + fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + (**self).read_buf(buf) + } + #[inline] fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { (**self).read_vectored(bufs) @@ -133,11 +138,6 @@ impl Read for Box { (**self).is_read_vectored() } - #[inline] - unsafe fn initializer(&self) -> Initializer { - (**self).initializer() - } - #[inline] fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { (**self).read_to_end(buf) @@ -247,6 +247,17 @@ impl Read for &[u8] { Ok(amt) } + #[inline] + fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + let amt = cmp::min(buf.remaining(), self.len()); + let (a, b) = self.split_at(amt); + + buf.append(a); + + *self = b; + Ok(()) + } + #[inline] fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { let mut nread = 0; @@ -265,11 +276,6 @@ impl Read for &[u8] { true } - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } - #[inline] fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { if buf.len() > self.len() { diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 8cc91566418dc..dd182c059b9cb 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; @@ -355,52 +358,43 @@ where // of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every // time is 4,500 times (!) slower than a default reservation size of 32 if the // reader has a very small amount of data to return. -// -// 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: &mut R, buf: &mut Vec) -> Result { let start_len = buf.len(); let start_cap = buf.capacity(); - let mut g = Guard { len: buf.len(), buf }; + + 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()); + + // SAFETY: These bytes were initalized but not filled in the previous loop + unsafe { + 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 { + if read_buf.filled_len() == 0 { + return Ok(buf.len() - start_len); + } + + // 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(); + + // SAFETY: ReadBuf's invariants mean this much memory is init + unsafe { + buf.set_len(new_len); + } + + if buf.len() == buf.capacity() && 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 @@ -409,10 +403,9 @@ pub(crate) fn default_read_to_end(r: &mut R, buf: &mut Vec loop { match r.read(&mut probe) { - Ok(0) => return Ok(g.len - start_len), + Ok(0) => return Ok(buf.len() - start_len), Ok(n) => { - g.buf.extend_from_slice(&probe[..n]); - g.len += n; + buf.extend_from_slice(&probe[..n]); break; } Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, @@ -474,6 +467,15 @@ pub(crate) fn default_read_exact(this: &mut R, mut buf: &mut [ } } +pub(crate) fn default_read_buf(read: F, buf: &mut ReadBuf<'_>) -> Result<()> +where + F: FnOnce(&mut [u8]) -> Result, +{ + let n = read(buf.initialize_unfilled())?; + buf.add_filled(n); + Ok(()) +} + /// The `Read` trait allows for reading bytes from a source. /// /// Implementors of the `Read` trait are called 'readers'. @@ -656,31 +658,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 +807,40 @@ 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<()> { + default_read_buf(|b| self.read(b), buf) + } + + /// 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 +1310,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 +2366,6 @@ impl Read for Chain { } 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 +2568,53 @@ impl Read for Take { 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 { + // if we just use an as cast to convert, limit may wrap around on a 32 bit target + let limit = cmp::min(self.limit, usize::MAX as u64) as usize; + + let extra_init = cmp::min(limit as usize, buf.initialized_len() - buf.filled_len()); + + // SAFETY: no uninit data is written to ibuf + let ibuf = unsafe { &mut buf.unfilled_mut()[..limit] }; + + let mut sliced_buf = ReadBuf::uninit(ibuf); + + // SAFETY: extra_init bytes of ibuf are known to be initialized + 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 + + // SAFETY: new_init bytes of buf's unfilled buffer have been initialized + 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(()) } } diff --git a/library/std/src/io/readbuf.rs b/library/std/src/io/readbuf.rs new file mode 100644 index 0000000000000..d84a500e07800 --- /dev/null +++ b/library/std/src/io/readbuf.rs @@ -0,0 +1,245 @@ +#![unstable(feature = "read_buf", issue = "78485")] + +#[cfg(test)] +mod tests; + +use crate::cmp; +use crate::fmt::{self, Debug, Formatter}; +use crate::mem::MaybeUninit; + +/// 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 ] +/// ``` +pub struct ReadBuf<'a> { + buf: &'a mut [MaybeUninit], + filled: usize, + initialized: usize, +} + +impl Debug for ReadBuf<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("ReadBuf") + .field("init", &self.initialized()) + .field("filled", &self.filled) + .field("capacity", &self.capacity()) + .finish() + } +} + +impl<'a> ReadBuf<'a> { + /// Creates a new `ReadBuf` from a fully initialized buffer. + #[inline] + pub fn new(buf: &'a mut [u8]) -> ReadBuf<'a> { + let len = buf.len(); + + ReadBuf { + //SAFETY: initialized data never becoming uninitialized is an invariant of ReadBuf + buf: unsafe { (buf as *mut [u8]).as_uninit_slice_mut().unwrap() }, + filled: 0, + initialized: len, + } + } + + /// Creates a new `ReadBuf` from a fully uninitialized buffer. + /// + /// Use `assume_init` if part of the buffer is known to be already inintialized. + #[inline] + pub fn uninit(buf: &'a mut [MaybeUninit]) -> ReadBuf<'a> { + ReadBuf { buf, filled: 0, initialized: 0 } + } + + /// Returns the total capacity of the buffer. + #[inline] + pub fn capacity(&self) -> usize { + self.buf.len() + } + + /// Returns a shared reference to the filled portion of the buffer. + #[inline] + pub fn filled(&self) -> &[u8] { + //SAFETY: We only slice the filled part of the buffer, which is always valid + unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[0..self.filled]) } + } + + /// Returns a mutable reference to the filled portion of the buffer. + #[inline] + pub fn filled_mut(&mut self) -> &mut [u8] { + //SAFETY: We only slice the filled part of the buffer, which is always valid + unsafe { MaybeUninit::slice_assume_init_mut(&mut self.buf[0..self.filled]) } + } + + /// Returns a shared reference to the initialized portion of the buffer. + /// + /// This includes the filled portion. + #[inline] + pub fn initialized(&self) -> &[u8] { + //SAFETY: We only slice the initialized part of the buffer, which is always valid + unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[0..self.initialized]) } + } + + /// Returns a mutable reference to the initialized portion of the buffer. + /// + /// This includes the filled portion. + #[inline] + pub fn initialized_mut(&mut self) -> &mut [u8] { + //SAFETY: We only slice the initialized part of the buffer, which is always valid + unsafe { MaybeUninit::slice_assume_init_mut(&mut self.buf[0..self.initialized]) } + } + + /// 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] + pub unsafe fn unfilled_mut(&mut self) -> &mut [MaybeUninit] { + &mut self.buf[self.filled..] + } + + /// Returns a mutable reference to the uninitialized part of the buffer. + /// + /// It is safe to uninitialize any of these bytes. + #[inline] + pub fn uninitialized_mut(&mut self) -> &mut [MaybeUninit] { + &mut self.buf[self.initialized..] + } + + /// 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] + pub fn initialize_unfilled(&mut self) -> &mut [u8] { + // should optimize out the assertion + 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] + pub fn initialize_unfilled_to(&mut self, n: usize) -> &mut [u8] { + assert!(self.remaining() >= n); + + let extra_init = self.initialized - self.filled; + // If we don't have enough initialized, do zeroing + if n > extra_init { + let uninit = n - extra_init; + let unfilled = &mut self.uninitialized_mut()[0..uninit]; + + for byte in unfilled.iter_mut() { + byte.write(0); + } + + // SAFETY: we just inintialized uninit bytes, and the previous bytes were already init + unsafe { + self.assume_init(n); + } + } + + let filled = self.filled; + + &mut self.initialized_mut()[filled..filled + n] + } + + /// Returns the number of bytes at the end of the slice that have not yet been filled. + #[inline] + pub fn 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] + pub fn clear(&mut self) { + self.set_filled(0); // The assertion in `set_filled` is optimized out + } + + /// 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] + pub fn add_filled(&mut self, n: usize) { + self.set_filled(self.filled + n); + } + + /// 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] + pub fn set_filled(&mut self, n: usize) { + assert!(n <= self.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 the first `n` unfilled bytes of the buffer have already been initialized. + #[inline] + pub unsafe fn assume_init(&mut self, n: usize) { + self.initialized = cmp::max(self.initialized, self.filled + n); + } + + /// 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] + pub fn append(&mut self, buf: &[u8]) { + assert!(self.remaining() >= buf.len()); + + // SAFETY: we do not de-initialize any of the elements of the slice + unsafe { + MaybeUninit::write_slice(&mut self.unfilled_mut()[..buf.len()], buf); + } + + // SAFETY: We just added the entire contents of buf to the filled section. + unsafe { self.assume_init(buf.len()) } + self.add_filled(buf.len()); + } + + /// Returns the amount of bytes that have been filled. + #[inline] + pub fn filled_len(&self) -> usize { + self.filled + } + + /// Returns the amount of bytes that have been initialized. + #[inline] + pub fn initialized_len(&self) -> usize { + self.initialized + } +} diff --git a/library/std/src/io/readbuf/tests.rs b/library/std/src/io/readbuf/tests.rs new file mode 100644 index 0000000000000..3b7a5a56d2252 --- /dev/null +++ b/library/std/src/io/readbuf/tests.rs @@ -0,0 +1,181 @@ +use super::ReadBuf; +use crate::mem::MaybeUninit; + +/// Test that ReadBuf has the correct numbers when created with new +#[test] +fn new() { + let mut buf = [0; 16]; + let rbuf = ReadBuf::new(&mut buf); + + assert_eq!(rbuf.filled_len(), 0); + assert_eq!(rbuf.initialized_len(), 16); + assert_eq!(rbuf.capacity(), 16); + assert_eq!(rbuf.remaining(), 16); +} + +/// Test that ReadBuf has the correct numbers when created with uninit +#[test] +fn uninit() { + let mut buf = [MaybeUninit::uninit(); 16]; + let rbuf = ReadBuf::uninit(&mut buf); + + assert_eq!(rbuf.filled_len(), 0); + assert_eq!(rbuf.initialized_len(), 0); + assert_eq!(rbuf.capacity(), 16); + assert_eq!(rbuf.remaining(), 16); +} + +#[test] +fn initialize_unfilled() { + let mut buf = [MaybeUninit::uninit(); 16]; + let mut rbuf = ReadBuf::uninit(&mut buf); + + rbuf.initialize_unfilled(); + + assert_eq!(rbuf.initialized_len(), 16); +} + +#[test] +fn initialize_unfilled_to() { + let mut buf = [MaybeUninit::uninit(); 16]; + let mut rbuf = ReadBuf::uninit(&mut buf); + + rbuf.initialize_unfilled_to(8); + + assert_eq!(rbuf.initialized_len(), 8); + + rbuf.initialize_unfilled_to(4); + + assert_eq!(rbuf.initialized_len(), 8); + + rbuf.set_filled(8); + + rbuf.initialize_unfilled_to(6); + + assert_eq!(rbuf.initialized_len(), 14); + + rbuf.initialize_unfilled_to(8); + + assert_eq!(rbuf.initialized_len(), 16); +} + +#[test] +fn add_filled() { + let mut buf = [0; 16]; + let mut rbuf = ReadBuf::new(&mut buf); + + rbuf.add_filled(1); + + assert_eq!(rbuf.filled_len(), 1); + assert_eq!(rbuf.remaining(), 15); +} + +#[test] +#[should_panic] +fn add_filled_panic() { + let mut buf = [MaybeUninit::uninit(); 16]; + let mut rbuf = ReadBuf::uninit(&mut buf); + + rbuf.add_filled(1); +} + +#[test] +fn set_filled() { + let mut buf = [0; 16]; + let mut rbuf = ReadBuf::new(&mut buf); + + rbuf.set_filled(16); + + assert_eq!(rbuf.filled_len(), 16); + assert_eq!(rbuf.remaining(), 0); + + rbuf.set_filled(6); + + assert_eq!(rbuf.filled_len(), 6); + assert_eq!(rbuf.remaining(), 10); +} + +#[test] +#[should_panic] +fn set_filled_panic() { + let mut buf = [MaybeUninit::uninit(); 16]; + let mut rbuf = ReadBuf::uninit(&mut buf); + + rbuf.set_filled(16); +} + +#[test] +fn clear() { + let mut buf = [255; 16]; + let mut rbuf = ReadBuf::new(&mut buf); + + rbuf.set_filled(16); + + assert_eq!(rbuf.filled_len(), 16); + assert_eq!(rbuf.remaining(), 0); + + rbuf.clear(); + + assert_eq!(rbuf.filled_len(), 0); + assert_eq!(rbuf.remaining(), 16); + + assert_eq!(rbuf.initialized(), [255; 16]); +} + +#[test] +fn assume_init() { + let mut buf = [MaybeUninit::uninit(); 16]; + let mut rbuf = ReadBuf::uninit(&mut buf); + + unsafe { + rbuf.assume_init(8); + } + + assert_eq!(rbuf.initialized_len(), 8); + + rbuf.add_filled(4); + + unsafe { + rbuf.assume_init(2); + } + + assert_eq!(rbuf.initialized_len(), 8); + + unsafe { + rbuf.assume_init(8); + } + + assert_eq!(rbuf.initialized_len(), 12); +} + +#[test] +fn append() { + let mut buf = [MaybeUninit::new(255); 16]; + let mut rbuf = ReadBuf::uninit(&mut buf); + + rbuf.append(&[0; 8]); + + assert_eq!(rbuf.initialized_len(), 8); + assert_eq!(rbuf.filled_len(), 8); + assert_eq!(rbuf.filled(), [0; 8]); + + rbuf.clear(); + + rbuf.append(&[1; 16]); + + assert_eq!(rbuf.initialized_len(), 16); + assert_eq!(rbuf.filled_len(), 16); + assert_eq!(rbuf.filled(), [1; 16]); +} + +#[test] +fn filled_mut() { + let mut buf = [0; 16]; + let mut rbuf = ReadBuf::new(&mut buf); + + rbuf.add_filled(8); + + let filled = rbuf.filled().to_vec(); + + assert_eq!(&*filled, &*rbuf.filled_mut()); +} diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index f7fc23c1e829c..9888d3a09c48d 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -7,7 +7,7 @@ use crate::io::prelude::*; use crate::cell::{Cell, RefCell}; use crate::fmt; -use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter, Lines, Split}; +use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines, Split}; use crate::lazy::SyncOnceCell; use crate::pin::Pin; use crate::sync::atomic::{AtomicBool, Ordering}; @@ -108,11 +108,6 @@ impl Read for StdinRaw { self.0.is_read_vectored() } - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { handle_ebadf(self.0.read_to_end(buf), 0) } @@ -514,10 +509,6 @@ impl Read for Stdin { fn is_read_vectored(&self) -> bool { self.lock().is_read_vectored() } - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { self.lock().read_to_end(buf) } @@ -552,11 +543,6 @@ impl Read for StdinLock<'_> { self.inner.is_read_vectored() } - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { self.inner.read_to_end(buf) } diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index 0321a2b60b108..ea49bfe3421d1 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -1,7 +1,8 @@ -use super::{repeat, Cursor, SeekFrom}; +use super::{repeat, Cursor, ReadBuf, SeekFrom}; use crate::cmp::{self, min}; use crate::io::{self, IoSlice, IoSliceMut}; use crate::io::{BufRead, BufReader, Read, Seek, Write}; +use crate::mem::MaybeUninit; use crate::ops::Deref; #[test] @@ -156,6 +157,28 @@ fn read_exact_slice() { assert_eq!(c, b"9"); } +#[test] +fn read_buf_exact() { + let mut buf = [0; 4]; + let mut buf = ReadBuf::new(&mut buf); + + let mut c = Cursor::new(&b""[..]); + assert_eq!(c.read_buf_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof); + + let mut c = Cursor::new(&b"123456789"[..]); + c.read_buf_exact(&mut buf).unwrap(); + assert_eq!(buf.filled(), b"1234"); + + buf.clear(); + + c.read_buf_exact(&mut buf).unwrap(); + assert_eq!(buf.filled(), b"5678"); + + buf.clear(); + + assert_eq!(c.read_buf_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof); +} + #[test] fn take_eof() { struct R; @@ -559,3 +582,23 @@ fn test_write_all_vectored() { } } } + +#[bench] +fn bench_take_read(b: &mut test::Bencher) { + b.iter(|| { + let mut buf = [0; 64]; + + [255; 128].take(64).read(&mut buf).unwrap(); + }); +} + +#[bench] +fn bench_take_read_buf(b: &mut test::Bencher) { + b.iter(|| { + let mut buf = [MaybeUninit::uninit(); 64]; + + let mut rbuf = ReadBuf::uninit(&mut buf); + + [255; 128].take(64).read_buf(&mut rbuf).unwrap(); + }); +} diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index 9cd7c5148499d..c1300cd67c086 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -5,7 +5,7 @@ mod tests; use crate::fmt; use crate::io::{ - self, BufRead, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, SizeHint, Write, + self, BufRead, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, SizeHint, Write, }; /// A reader which is always at EOF. @@ -47,8 +47,8 @@ impl Read for Empty { } #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() + fn read_buf(&mut self, _buf: &mut ReadBuf<'_>) -> io::Result<()> { + Ok(()) } } #[stable(feature = "rust1", since = "1.0.0")] @@ -130,6 +130,24 @@ impl Read for Repeat { Ok(buf.len()) } + fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + // SAFETY: No uninit bytes are being written + for slot in unsafe { buf.unfilled_mut() } { + slot.write(self.byte); + } + + let remaining = buf.remaining(); + + // SAFETY: the entire unfilled portion of buf has been initialized + unsafe { + buf.assume_init(remaining); + } + + buf.add_filled(remaining); + + Ok(()) + } + #[inline] fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { let mut nwritten = 0; @@ -143,11 +161,6 @@ impl Read for Repeat { fn is_read_vectored(&self) -> bool { true } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } } impl SizeHint for Repeat { diff --git a/library/std/src/io/util/tests.rs b/library/std/src/io/util/tests.rs index 7632eaf872a5b..08972a59a833f 100644 --- a/library/std/src/io/util/tests.rs +++ b/library/std/src/io/util/tests.rs @@ -1,9 +1,12 @@ use crate::cmp::{max, min}; use crate::io::prelude::*; use crate::io::{ - copy, empty, repeat, sink, BufWriter, Empty, Repeat, Result, SeekFrom, Sink, DEFAULT_BUF_SIZE, + copy, empty, repeat, sink, BufWriter, Empty, ReadBuf, Repeat, Result, SeekFrom, Sink, + DEFAULT_BUF_SIZE, }; +use crate::mem::MaybeUninit; + #[test] fn copy_copies() { let mut r = repeat(0).take(4); @@ -75,6 +78,30 @@ fn empty_reads() { assert_eq!(e.read(&mut [0]).unwrap(), 0); assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0); assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0); + + let mut buf = []; + let mut buf = ReadBuf::uninit(&mut buf); + e.read_buf(&mut buf).unwrap(); + assert_eq!(buf.filled_len(), 0); + assert_eq!(buf.initialized_len(), 0); + + let mut buf = [MaybeUninit::uninit()]; + let mut buf = ReadBuf::uninit(&mut buf); + e.read_buf(&mut buf).unwrap(); + assert_eq!(buf.filled_len(), 0); + assert_eq!(buf.initialized_len(), 0); + + let mut buf = [MaybeUninit::uninit(); 1024]; + let mut buf = ReadBuf::uninit(&mut buf); + e.read_buf(&mut buf).unwrap(); + assert_eq!(buf.filled_len(), 0); + assert_eq!(buf.initialized_len(), 0); + + let mut buf = [MaybeUninit::uninit(); 1024]; + let mut buf = ReadBuf::uninit(&mut buf); + e.by_ref().read_buf(&mut buf).unwrap(); + assert_eq!(buf.filled_len(), 0); + assert_eq!(buf.initialized_len(), 0); } #[test] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 367f072ffc7f8..d4ff642cd133a 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -304,6 +304,7 @@ #![feature(maybe_uninit_extra)] #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array)] +#![feature(maybe_uninit_write_slice)] #![feature(min_specialization)] #![feature(mixed_integer_ops)] #![feature(must_not_suspend)] @@ -320,6 +321,7 @@ #![feature(pin_static_ref)] #![feature(portable_simd)] #![feature(prelude_import)] +#![feature(ptr_as_uninit)] #![feature(ptr_internals)] #![feature(rustc_attrs)] #![feature(rustc_private)] diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 5738862fb58b2..1ba54d892e3ce 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -6,7 +6,7 @@ mod tests; use crate::io::prelude::*; use crate::fmt; -use crate::io::{self, Initializer, IoSlice, IoSliceMut}; +use crate::io::{self, IoSlice, IoSliceMut}; use crate::net::{Shutdown, SocketAddr, ToSocketAddrs}; use crate::sys_common::net as net_imp; use crate::sys_common::{AsInner, FromInner, IntoInner}; @@ -626,12 +626,6 @@ impl Read for TcpStream { fn is_read_vectored(&self) -> bool { self.0.is_read_vectored() } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - // SAFETY: Read is guaranteed to work on uninitialized memory - unsafe { Initializer::nop() } - } } #[stable(feature = "rust1", since = "1.0.0")] impl Write for TcpStream { @@ -666,12 +660,6 @@ impl Read for &TcpStream { fn is_read_vectored(&self) -> bool { self.0.is_read_vectored() } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - // SAFETY: Read is guaranteed to work on uninitialized memory - unsafe { Initializer::nop() } - } } #[stable(feature = "rust1", since = "1.0.0")] impl Write for &TcpStream { diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index 6120d557227af..583f861a92535 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -11,7 +11,7 @@ use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary}; use super::{sockaddr_un, SocketAddr}; use crate::fmt; -use crate::io::{self, Initializer, IoSlice, IoSliceMut}; +use crate::io::{self, IoSlice, IoSliceMut}; use crate::net::Shutdown; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; #[cfg(any( @@ -624,11 +624,6 @@ impl io::Read for UnixStream { fn is_read_vectored(&self) -> bool { io::Read::is_read_vectored(&&*self) } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } } #[stable(feature = "unix_socket", since = "1.10.0")] @@ -645,11 +640,6 @@ impl<'a> io::Read for &'a UnixStream { fn is_read_vectored(&self) -> bool { self.0.is_read_vectored() } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } } #[stable(feature = "unix_socket", since = "1.10.0")] diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 4e9fd51f28229..bf35d71bc4f05 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -110,7 +110,7 @@ use crate::convert::Infallible; use crate::ffi::OsStr; use crate::fmt; use crate::fs; -use crate::io::{self, Initializer, IoSlice, IoSliceMut}; +use crate::io::{self, IoSlice, IoSliceMut}; use crate::num::NonZeroI32; use crate::path::Path; use crate::str; @@ -362,12 +362,6 @@ impl Read for ChildStdout { fn is_read_vectored(&self) -> bool { self.inner.is_read_vectored() } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - // SAFETY: Read is guaranteed to work on uninitialized memory - unsafe { Initializer::nop() } - } } impl AsInner for ChildStdout { @@ -429,12 +423,6 @@ impl Read for ChildStderr { fn is_read_vectored(&self) -> bool { self.inner.is_read_vectored() } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - // SAFETY: Read is guaranteed to work on uninitialized memory - unsafe { Initializer::nop() } - } } impl AsInner for ChildStderr { diff --git a/library/std/src/sys/hermit/fd.rs b/library/std/src/sys/hermit/fd.rs index c400f5f2c2e84..1179a49c22fd0 100644 --- a/library/std/src/sys/hermit/fd.rs +++ b/library/std/src/sys/hermit/fd.rs @@ -1,6 +1,6 @@ #![unstable(reason = "not public", issue = "none", feature = "fd")] -use crate::io::{self, Read}; +use crate::io::{self, Read, ReadBuf}; use crate::mem; use crate::sys::cvt; use crate::sys::hermit::abi; diff --git a/library/std/src/sys/hermit/fs.rs b/library/std/src/sys/hermit/fs.rs index be019d4435db5..974c44eb8dd5e 100644 --- a/library/std/src/sys/hermit/fs.rs +++ b/library/std/src/sys/hermit/fs.rs @@ -2,7 +2,7 @@ use crate::ffi::{CStr, CString, OsString}; use crate::fmt; use crate::hash::{Hash, Hasher}; use crate::io::{self, Error, ErrorKind}; -use crate::io::{IoSlice, IoSliceMut, SeekFrom}; +use crate::io::{IoSlice, IoSliceMut, ReadBuf, SeekFrom}; use crate::os::unix::ffi::OsStrExt; use crate::path::{Path, PathBuf}; use crate::sys::cvt; @@ -312,6 +312,10 @@ impl File { false } + pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + crate::io::default_read_buf(|buf| self.read(buf), buf) + } + pub fn write(&self, buf: &[u8]) -> io::Result { self.0.write(buf) } diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index ea688571a9891..2362bff913f13 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -4,7 +4,7 @@ mod tests; use crate::cmp; -use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read}; +use crate::io::{self, IoSlice, IoSliceMut, Read, ReadBuf}; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::sys::cvt; use crate::sys_common::{AsInner, FromInner, IntoInner}; @@ -115,6 +115,23 @@ impl FileDesc { } } + pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + let ret = cvt(unsafe { + libc::read( + self.as_raw_fd(), + buf.unfilled_mut().as_mut_ptr() as *mut c_void, + cmp::min(buf.remaining(), READ_LIMIT), + ) + })?; + + // Safety: `ret` bytes were written to the initialized portion of the buffer + unsafe { + buf.assume_init(ret as usize); + } + buf.add_filled(ret as usize); + Ok(()) + } + pub fn write(&self, buf: &[u8]) -> io::Result { let ret = cvt(unsafe { libc::write( @@ -265,11 +282,6 @@ impl<'a> Read for &'a FileDesc { fn read(&mut self, buf: &mut [u8]) -> io::Result { (**self).read(buf) } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } } impl AsInner for FileDesc { diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index d77e5cae3ad73..bcf2be0e95fb7 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -2,7 +2,7 @@ use crate::os::unix::prelude::*; use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::fmt; -use crate::io::{self, Error, IoSlice, IoSliceMut, SeekFrom}; +use crate::io::{self, Error, IoSlice, IoSliceMut, ReadBuf, SeekFrom}; use crate::mem; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd}; use crate::path::{Path, PathBuf}; @@ -858,6 +858,10 @@ impl File { self.0.read_at(buf, offset) } + pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + self.0.read_buf(buf) + } + pub fn write(&self, buf: &[u8]) -> io::Result { self.0.write(buf) } diff --git a/library/std/src/sys/unsupported/fs.rs b/library/std/src/sys/unsupported/fs.rs index 6b45e29c1458e..d1d2847cd33be 100644 --- a/library/std/src/sys/unsupported/fs.rs +++ b/library/std/src/sys/unsupported/fs.rs @@ -1,7 +1,7 @@ use crate::ffi::OsString; use crate::fmt; use crate::hash::{Hash, Hasher}; -use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; +use crate::io::{self, IoSlice, IoSliceMut, ReadBuf, SeekFrom}; use crate::path::{Path, PathBuf}; use crate::sys::time::SystemTime; use crate::sys::unsupported; @@ -206,6 +206,10 @@ impl File { self.0 } + pub fn read_buf(&self, _buf: &mut ReadBuf<'_>) -> io::Result<()> { + self.0 + } + pub fn write(&self, _buf: &[u8]) -> io::Result { self.0 } diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs index 984dda8dc0b4e..1a3da3746ac61 100644 --- a/library/std/src/sys/wasi/fs.rs +++ b/library/std/src/sys/wasi/fs.rs @@ -3,7 +3,7 @@ use super::fd::WasiFd; use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::fmt; -use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; +use crate::io::{self, IoSlice, IoSliceMut, ReadBuf, SeekFrom}; use crate::iter; use crate::mem::{self, ManuallyDrop}; use crate::os::raw::c_int; @@ -411,6 +411,10 @@ impl File { true } + pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + crate::io::default_read_buf(|buf| self.read(buf), buf) + } + pub fn write(&self, buf: &[u8]) -> io::Result { self.write_vectored(&[IoSlice::new(buf)]) } diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index 9859000c8d417..b258fc0478bdc 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -2,7 +2,7 @@ use crate::os::windows::prelude::*; use crate::ffi::OsString; use crate::fmt; -use crate::io::{self, Error, IoSlice, IoSliceMut, SeekFrom}; +use crate::io::{self, Error, IoSlice, IoSliceMut, ReadBuf, SeekFrom}; use crate::mem; use crate::os::windows::io::{AsHandle, BorrowedHandle}; use crate::path::{Path, PathBuf}; @@ -420,6 +420,10 @@ impl File { self.handle.read_at(buf, offset) } + pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + self.handle.read_buf(buf) + } + pub fn write(&self, buf: &[u8]) -> io::Result { self.handle.write(buf) } diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs index 21d86b002264a..c3a3482f91051 100644 --- a/library/std/src/sys/windows/handle.rs +++ b/library/std/src/sys/windows/handle.rs @@ -1,7 +1,7 @@ #![unstable(issue = "none", feature = "windows_handle")] use crate::cmp; -use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, Read}; +use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf}; use crate::mem; use crate::os::windows::io::{ AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle, @@ -130,6 +130,39 @@ impl Handle { } } + pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + let mut read = 0; + let len = cmp::min(buf.remaining(), ::MAX as usize) as c::DWORD; + let res = cvt(unsafe { + c::ReadFile( + self.as_raw_handle(), + buf.unfilled_mut().as_mut_ptr() as c::LPVOID, + len, + &mut read, + ptr::null_mut(), + ) + }); + + match res { + Ok(_) => { + // Safety: `read` bytes were written to the initialized portion of the buffer + unsafe { + buf.assume_init(read as usize); + } + buf.add_filled(read as usize); + Ok(()) + } + + // The special treatment of BrokenPipe is to deal with Windows + // pipe semantics, which yields this error when *reading* from + // a pipe after the other end has closed; we interpret that as + // EOF on the pipe. + Err(ref e) if e.kind() == ErrorKind::BrokenPipe => Ok(()), + + Err(e) => Err(e), + } + } + pub unsafe fn read_overlapped( &self, buf: &mut [u8],