This commit is contained in:
DrMeepster 2021-01-17 22:28:18 -08:00
parent 3802025f40
commit 98c6200b16
18 changed files with 772 additions and 294 deletions

View File

@ -13,7 +13,7 @@ mod tests;
use crate::ffi::OsString; use crate::ffi::OsString;
use crate::fmt; use crate::fmt;
use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; use crate::io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
use crate::path::{Path, PathBuf}; use crate::path::{Path, PathBuf};
use crate::sys::fs as fs_imp; use crate::sys::fs as fs_imp;
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
@ -629,12 +629,6 @@ impl Read for File {
self.inner.is_read_vectored() 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. // Reserves space in the buffer based on the file size when available.
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
buf.reserve(buffer_capacity_required(self)); buf.reserve(buffer_capacity_required(self));
@ -687,12 +681,6 @@ impl Read for &File {
self.inner.is_read_vectored() 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. // Reserves space in the buffer based on the file size when available.
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
buf.reserve(buffer_capacity_required(self)); buf.reserve(buffer_capacity_required(self));

View File

@ -1,8 +1,9 @@
use crate::cmp; use crate::cmp;
use crate::fmt; use crate::fmt;
use crate::io::{ 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<R>` struct adds buffering to any reader. /// The `BufReader<R>` struct adds buffering to any reader.
/// ///
@ -47,9 +48,10 @@ use crate::io::{
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub struct BufReader<R> { pub struct BufReader<R> {
inner: R, inner: R,
buf: Box<[u8]>, buf: Box<[MaybeUninit<u8>]>,
pos: usize, pos: usize,
cap: usize, cap: usize,
init: usize,
} }
impl<R: Read> BufReader<R> { impl<R: Read> BufReader<R> {
@ -91,11 +93,8 @@ impl<R: Read> BufReader<R> {
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> { pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> {
unsafe { let buf = Box::new_uninit_slice(capacity);
let mut buf = Box::new_uninit_slice(capacity).assume_init(); BufReader { inner, buf, pos: 0, cap: 0, init: 0 }
inner.initializer().initialize(&mut buf);
BufReader { inner, buf, pos: 0, cap: 0 }
}
} }
} }
@ -171,7 +170,7 @@ impl<R> BufReader<R> {
/// ``` /// ```
#[stable(feature = "bufreader_buffer", since = "1.37.0")] #[stable(feature = "bufreader_buffer", since = "1.37.0")]
pub fn buffer(&self) -> &[u8] { pub fn buffer(&self) -> &[u8] {
&self.buf[self.pos..self.cap] unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[self.pos..self.cap]) }
} }
/// Returns the number of bytes the internal buffer can hold at once. /// Returns the number of bytes the internal buffer can hold at once.
@ -271,6 +270,25 @@ impl<R: Read> Read for BufReader<R> {
Ok(nread) 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. // 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 // 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 // generation for the common path where the buffer has enough bytes to fill the passed-in
@ -303,16 +321,11 @@ impl<R: Read> Read for BufReader<R> {
self.inner.is_read_vectored() 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 // The inner reader might have an optimized `read_to_end`. Drain our buffer and then
// delegate to the inner implementation. // delegate to the inner implementation.
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
let nread = self.cap - self.pos; 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(); self.discard_buffer();
Ok(nread + self.inner.read_to_end(buf)?) Ok(nread + self.inner.read_to_end(buf)?)
} }
@ -363,10 +376,24 @@ impl<R: Read> BufRead for BufReader<R> {
// to tell the compiler that the pos..cap slice is always valid. // to tell the compiler that the pos..cap slice is always valid.
if self.pos >= self.cap { if self.pos >= self.cap {
debug_assert!(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 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; self.pos = 0;
} }
Ok(&self.buf[self.pos..self.cap]) // SAFETY: self.cap is always <= self.init, so self.buf[self.pos..self.cap] is always init
unsafe { Ok(MaybeUninit::slice_assume_init_ref(&self.buf[self.pos..self.cap])) }
} }
fn consume(&mut self, amt: usize) { fn consume(&mut self, amt: usize) {

View File

@ -1,5 +1,6 @@
use crate::io::prelude::*; 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::panic;
use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::thread; use crate::thread;
@ -55,6 +56,55 @@ fn test_buffered_reader() {
assert_eq!(reader.read(&mut buf).unwrap(), 0); 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] #[test]
fn test_buffered_reader_seek() { fn test_buffered_reader_seek() {
let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];

View File

@ -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; use crate::mem::MaybeUninit;
/// Copies the entire contents of a reader into a writer. /// Copies the entire contents of a reader into a writer.
@ -82,33 +82,23 @@ impl<I: Write> BufferedCopySpec for BufWriter<I> {
return stack_buffer_copy(reader, writer); 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 len = 0;
loop { loop {
let buf = writer.buffer_mut(); let buf = writer.buffer_mut();
let spare_cap = buf.spare_capacity_mut(); let mut read_buf = ReadBuf::uninit(buf.spare_capacity_mut());
if spare_cap.len() >= DEFAULT_BUF_SIZE { if read_buf.capacity() >= DEFAULT_BUF_SIZE {
match reader.read(unsafe { MaybeUninit::slice_assume_init_mut(spare_cap) }) { match reader.read_buf(&mut read_buf) {
Ok(0) => return Ok(len), // EOF reached //Ok(0) => return Ok(len), // EOF reached
Ok(bytes_read) => { Ok(()) => {
assert!(bytes_read <= spare_cap.len()); let bytes_read = read_buf.filled_len();
// SAFETY: The initializer contract guarantees that either it or `read`
// will have initialized these bytes. And we just checked that the number if bytes_read == 0 {
// of bytes is within the buffer capacity. return Ok(len);
}
// SAFETY: ReadBuf guarantees all of its filled bytes are init
unsafe { buf.set_len(buf.len() + bytes_read) }; unsafe { buf.set_len(buf.len() + bytes_read) };
len += bytes_read as u64; len += bytes_read as u64;
// Read again if the buffer still has enough capacity, as BufWriter itself would do // Read again if the buffer still has enough capacity, as BufWriter itself would do
@ -129,28 +119,26 @@ fn stack_buffer_copy<R: Read + ?Sized, W: Write + ?Sized>(
reader: &mut R, reader: &mut R,
writer: &mut W, writer: &mut W,
) -> Result<u64> { ) -> Result<u64> {
let mut buf = MaybeUninit::<[u8; DEFAULT_BUF_SIZE]>::uninit(); let mut buf = [MaybeUninit::uninit(); DEFAULT_BUF_SIZE];
// FIXME: #42788 let mut buf = ReadBuf::uninit(&mut buf);
//
// - This creates a (mut) reference to a slice of let mut len = 0;
// _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 written = 0;
loop { loop {
let len = match reader.read(unsafe { buf.assume_init_mut() }) { match reader.read_buf(&mut buf) {
Ok(0) => return Ok(written), Ok(()) => {}
Ok(len) => len, Err(e) if e.kind() == ErrorKind::Interrupted => continue,
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e), 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)
} }

View File

@ -4,7 +4,7 @@ mod tests;
use crate::io::prelude::*; use crate::io::prelude::*;
use crate::cmp; 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; use core::convert::TryInto;
@ -324,6 +324,16 @@ where
Ok(n) 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<usize> { fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
let mut nread = 0; let mut nread = 0;
for buf in bufs { for buf in bufs {
@ -346,11 +356,6 @@ where
self.pos += n as u64; self.pos += n as u64;
Ok(()) Ok(())
} }
#[inline]
unsafe fn initializer(&self) -> Initializer {
Initializer::nop()
}
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]

View File

@ -5,7 +5,7 @@ use crate::alloc::Allocator;
use crate::cmp; use crate::cmp;
use crate::fmt; use crate::fmt;
use crate::io::{ 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; use crate::mem;
@ -19,6 +19,11 @@ impl<R: Read + ?Sized> Read for &mut R {
(**self).read(buf) (**self).read(buf)
} }
#[inline]
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
(**self).read_buf(buf)
}
#[inline] #[inline]
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
(**self).read_vectored(bufs) (**self).read_vectored(bufs)
@ -29,11 +34,6 @@ impl<R: Read + ?Sized> Read for &mut R {
(**self).is_read_vectored() (**self).is_read_vectored()
} }
#[inline]
unsafe fn initializer(&self) -> Initializer {
(**self).initializer()
}
#[inline] #[inline]
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
(**self).read_to_end(buf) (**self).read_to_end(buf)
@ -123,6 +123,11 @@ impl<R: Read + ?Sized> Read for Box<R> {
(**self).read(buf) (**self).read(buf)
} }
#[inline]
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
(**self).read_buf(buf)
}
#[inline] #[inline]
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
(**self).read_vectored(bufs) (**self).read_vectored(bufs)
@ -133,11 +138,6 @@ impl<R: Read + ?Sized> Read for Box<R> {
(**self).is_read_vectored() (**self).is_read_vectored()
} }
#[inline]
unsafe fn initializer(&self) -> Initializer {
(**self).initializer()
}
#[inline] #[inline]
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
(**self).read_to_end(buf) (**self).read_to_end(buf)
@ -247,6 +247,17 @@ impl Read for &[u8] {
Ok(amt) 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] #[inline]
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
let mut nread = 0; let mut nread = 0;
@ -265,11 +276,6 @@ impl Read for &[u8] {
true true
} }
#[inline]
unsafe fn initializer(&self) -> Initializer {
Initializer::nop()
}
#[inline] #[inline]
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
if buf.len() > self.len() { if buf.len() > self.len() {

View File

@ -256,7 +256,6 @@ use crate::convert::TryInto;
use crate::fmt; use crate::fmt;
use crate::mem::replace; use crate::mem::replace;
use crate::ops::{Deref, DerefMut}; use crate::ops::{Deref, DerefMut};
use crate::ptr;
use crate::slice; use crate::slice;
use crate::str; use crate::str;
use crate::sys; use crate::sys;
@ -288,12 +287,16 @@ pub use self::stdio::{_eprint, _print};
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub use self::util::{empty, repeat, sink, Empty, Repeat, Sink}; pub use self::util::{empty, repeat, sink, Empty, Repeat, Sink};
#[unstable(feature = "read_buf", issue = "78485")]
pub use self::readbuf::ReadBuf;
mod buffered; mod buffered;
pub(crate) mod copy; pub(crate) mod copy;
mod cursor; mod cursor;
mod error; mod error;
mod impls; mod impls;
pub mod prelude; pub mod prelude;
mod readbuf;
mod stdio; mod stdio;
mod util; mod util;
@ -359,68 +362,39 @@ where
// Because we're extending the buffer with uninitialized data for trusted // 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. // 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> { 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 initial_len = buf.len(); // need to know so we can return how many bytes we read
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 { loop {
// If we've read all the way up to the capacity, reserve more space. if buf.len() == buf.capacity() {
if g.len == g.buf.capacity() { buf.reserve(32); // buf is full, need more space
g.buf.reserve(32);
} }
// Initialize any excess capacity and adjust the length so we can write let mut read_buf = ReadBuf::uninit(buf.spare_capacity_mut());
// to it. unsafe {
if g.buf.len() < g.buf.capacity() { // add back extra initalized bytes, we don't want to reinitalize initalized bytes
unsafe { read_buf.assume_init(initialized);
// 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 buf = &mut g.buf[g.len..]; match r.read_buf(&mut read_buf) {
match r.read(buf) { Ok(()) => {}
Ok(0) => return Ok(g.len - start_len), Err(e) if e.kind() == ErrorKind::Interrupted => continue,
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,
Err(e) => return Err(e), Err(e) => return Err(e),
} }
if g.len == g.buf.capacity() && g.buf.capacity() == start_cap { if read_buf.filled_len() == 0 {
// The buffer might be an exact fit. Let's read into a probe buffer break;
// 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 { // store how much was initialized but not filled
match r.read(&mut probe) { initialized = read_buf.initialized_len() - read_buf.filled_len();
Ok(0) => return Ok(g.len - start_len), let new_len = read_buf.filled_len() + buf.len();
Ok(n) => { unsafe {
g.buf.extend_from_slice(&probe[..n]); buf.set_len(new_len);
g.len += n;
break;
}
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e),
}
}
} }
} }
Ok(buf.len() - initial_len)
} }
pub(crate) fn default_read_to_string<R: Read + ?Sized>( pub(crate) fn default_read_to_string<R: Read + ?Sized>(
@ -656,31 +630,6 @@ pub trait Read {
false 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`. /// 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 /// 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) 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 /// The returned adapter also implements `Read` and will simply borrow this
/// current reader. /// 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. /// A trait for objects which are byte-oriented sinks.
/// ///
/// Implementors of the `Write` trait are sometimes called 'writers'. /// 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) 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")] #[stable(feature = "chain_bufread", since = "1.9.0")]
@ -2610,8 +2542,46 @@ impl<T: Read> Read for Take<T> {
Ok(n) Ok(n)
} }
unsafe fn initializer(&self) -> Initializer { fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> {
self.inner.initializer() // 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(())
} }
} }

View File

@ -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<u8>],
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: inintialized 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<u8>]) -> 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<u8>] {
&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<u8>] {
&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);
//dont try to do any zeroing if we already have enough initialized
if n > (self.initialized - self.filled) {
let uninit = (n + self.filled) - self.initialized;
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
}
}

View File

@ -0,0 +1,169 @@
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]);
}

View File

@ -7,7 +7,7 @@ use crate::io::prelude::*;
use crate::cell::{Cell, RefCell}; use crate::cell::{Cell, RefCell};
use crate::fmt; 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::lazy::SyncOnceCell;
use crate::pin::Pin; use crate::pin::Pin;
use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::atomic::{AtomicBool, Ordering};
@ -108,11 +108,6 @@ impl Read for StdinRaw {
self.0.is_read_vectored() self.0.is_read_vectored()
} }
#[inline]
unsafe fn initializer(&self) -> Initializer {
Initializer::nop()
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
handle_ebadf(self.0.read_to_end(buf), 0) handle_ebadf(self.0.read_to_end(buf), 0)
} }
@ -514,10 +509,6 @@ impl Read for Stdin {
fn is_read_vectored(&self) -> bool { fn is_read_vectored(&self) -> bool {
self.lock().is_read_vectored() self.lock().is_read_vectored()
} }
#[inline]
unsafe fn initializer(&self) -> Initializer {
Initializer::nop()
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.lock().read_to_end(buf) self.lock().read_to_end(buf)
} }
@ -552,11 +543,6 @@ impl Read for StdinLock<'_> {
self.inner.is_read_vectored() self.inner.is_read_vectored()
} }
#[inline]
unsafe fn initializer(&self) -> Initializer {
Initializer::nop()
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.inner.read_to_end(buf) self.inner.read_to_end(buf)
} }

View File

@ -1,7 +1,8 @@
use super::{repeat, Cursor, SeekFrom}; use super::{repeat, Cursor, ReadBuf, SeekFrom};
use crate::cmp::{self, min}; use crate::cmp::{self, min};
use crate::io::{self, IoSlice, IoSliceMut}; use crate::io::{self, IoSlice, IoSliceMut};
use crate::io::{BufRead, BufReader, Read, Seek, Write}; use crate::io::{BufRead, BufReader, Read, Seek, Write};
use crate::mem::MaybeUninit;
use crate::ops::Deref; use crate::ops::Deref;
#[test] #[test]
@ -156,6 +157,28 @@ fn read_exact_slice() {
assert_eq!(c, b"9"); 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] #[test]
fn take_eof() { fn take_eof() {
struct R; 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();
});
}

View File

@ -5,7 +5,7 @@ mod tests;
use crate::fmt; use crate::fmt;
use crate::io::{ 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. /// A reader which is always at EOF.
@ -47,8 +47,8 @@ impl Read for Empty {
} }
#[inline] #[inline]
unsafe fn initializer(&self) -> Initializer { fn read_buf(&mut self, _buf: &mut ReadBuf<'_>) -> io::Result<()> {
Initializer::nop() Ok(())
} }
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
@ -130,6 +130,22 @@ impl Read for Repeat {
Ok(buf.len()) Ok(buf.len())
} }
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
for slot in unsafe { buf.unfilled_mut() } {
slot.write(self.byte);
}
let remaining = buf.remaining();
unsafe {
buf.assume_init(remaining);
}
buf.add_filled(remaining);
Ok(())
}
#[inline] #[inline]
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
let mut nwritten = 0; let mut nwritten = 0;
@ -143,11 +159,6 @@ impl Read for Repeat {
fn is_read_vectored(&self) -> bool { fn is_read_vectored(&self) -> bool {
true true
} }
#[inline]
unsafe fn initializer(&self) -> Initializer {
Initializer::nop()
}
} }
impl SizeHint for Repeat { impl SizeHint for Repeat {

View File

@ -1,9 +1,12 @@
use crate::cmp::{max, min}; use crate::cmp::{max, min};
use crate::io::prelude::*; use crate::io::prelude::*;
use crate::io::{ 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] #[test]
fn copy_copies() { fn copy_copies() {
let mut r = repeat(0).take(4); 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]).unwrap(), 0);
assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0); assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0);
assert_eq!(e.by_ref().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] #[test]

View File

@ -306,6 +306,7 @@
#![feature(maybe_uninit_extra)] #![feature(maybe_uninit_extra)]
#![feature(maybe_uninit_slice)] #![feature(maybe_uninit_slice)]
#![feature(maybe_uninit_uninit_array)] #![feature(maybe_uninit_uninit_array)]
#![feature(maybe_uninit_write_slice)]
#![feature(min_specialization)] #![feature(min_specialization)]
#![feature(mixed_integer_ops)] #![feature(mixed_integer_ops)]
#![feature(must_not_suspend)] #![feature(must_not_suspend)]
@ -321,6 +322,7 @@
#![feature(panic_unwind)] #![feature(panic_unwind)]
#![feature(pin_static_ref)] #![feature(pin_static_ref)]
#![feature(prelude_import)] #![feature(prelude_import)]
#![feature(ptr_as_uninit)]
#![feature(ptr_internals)] #![feature(ptr_internals)]
#![feature(rustc_attrs)] #![feature(rustc_attrs)]
#![feature(rustc_private)] #![feature(rustc_private)]

View File

@ -6,7 +6,7 @@ mod tests;
use crate::io::prelude::*; use crate::io::prelude::*;
use crate::fmt; use crate::fmt;
use crate::io::{self, Initializer, IoSlice, IoSliceMut}; use crate::io::{self, IoSlice, IoSliceMut};
use crate::net::{Shutdown, SocketAddr, ToSocketAddrs}; use crate::net::{Shutdown, SocketAddr, ToSocketAddrs};
use crate::sys_common::net as net_imp; use crate::sys_common::net as net_imp;
use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::sys_common::{AsInner, FromInner, IntoInner};
@ -626,12 +626,6 @@ impl Read for TcpStream {
fn is_read_vectored(&self) -> bool { fn is_read_vectored(&self) -> bool {
self.0.is_read_vectored() 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")] #[stable(feature = "rust1", since = "1.0.0")]
impl Write for TcpStream { impl Write for TcpStream {
@ -666,12 +660,6 @@ impl Read for &TcpStream {
fn is_read_vectored(&self) -> bool { fn is_read_vectored(&self) -> bool {
self.0.is_read_vectored() 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")] #[stable(feature = "rust1", since = "1.0.0")]
impl Write for &TcpStream { impl Write for &TcpStream {

View File

@ -11,7 +11,7 @@
use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary}; use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary};
use super::{sockaddr_un, SocketAddr}; use super::{sockaddr_un, SocketAddr};
use crate::fmt; use crate::fmt;
use crate::io::{self, Initializer, IoSlice, IoSliceMut}; use crate::io::{self, IoSlice, IoSliceMut};
use crate::net::Shutdown; use crate::net::Shutdown;
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
#[cfg(any( #[cfg(any(
@ -624,11 +624,6 @@ impl io::Read for UnixStream {
fn is_read_vectored(&self) -> bool { fn is_read_vectored(&self) -> bool {
io::Read::is_read_vectored(&&*self) io::Read::is_read_vectored(&&*self)
} }
#[inline]
unsafe fn initializer(&self) -> Initializer {
Initializer::nop()
}
} }
#[stable(feature = "unix_socket", since = "1.10.0")] #[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 { fn is_read_vectored(&self) -> bool {
self.0.is_read_vectored() self.0.is_read_vectored()
} }
#[inline]
unsafe fn initializer(&self) -> Initializer {
Initializer::nop()
}
} }
#[stable(feature = "unix_socket", since = "1.10.0")] #[stable(feature = "unix_socket", since = "1.10.0")]

View File

@ -109,7 +109,7 @@ use crate::io::prelude::*;
use crate::ffi::OsStr; use crate::ffi::OsStr;
use crate::fmt; use crate::fmt;
use crate::fs; use crate::fs;
use crate::io::{self, Initializer, IoSlice, IoSliceMut}; use crate::io::{self, IoSlice, IoSliceMut};
use crate::num::NonZeroI32; use crate::num::NonZeroI32;
use crate::path::Path; use crate::path::Path;
use crate::str; use crate::str;
@ -361,12 +361,6 @@ impl Read for ChildStdout {
fn is_read_vectored(&self) -> bool { fn is_read_vectored(&self) -> bool {
self.inner.is_read_vectored() 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<AnonPipe> for ChildStdout { impl AsInner<AnonPipe> for ChildStdout {
@ -428,12 +422,6 @@ impl Read for ChildStderr {
fn is_read_vectored(&self) -> bool { fn is_read_vectored(&self) -> bool {
self.inner.is_read_vectored() 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<AnonPipe> for ChildStderr { impl AsInner<AnonPipe> for ChildStderr {

View File

@ -4,7 +4,7 @@
mod tests; mod tests;
use crate::cmp; use crate::cmp;
use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read}; use crate::io::{self, IoSlice, IoSliceMut, Read};
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
use crate::sys::cvt; use crate::sys::cvt;
use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::sys_common::{AsInner, FromInner, IntoInner};
@ -289,11 +289,6 @@ impl<'a> Read for &'a FileDesc {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
(**self).read(buf) (**self).read(buf)
} }
#[inline]
unsafe fn initializer(&self) -> Initializer {
Initializer::nop()
}
} }
impl AsInner<OwnedFd> for FileDesc { impl AsInner<OwnedFd> for FileDesc {