read_buf
This commit is contained in:
parent
3802025f40
commit
98c6200b16
@ -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, Seek, SeekFrom, Write};
|
||||
use crate::path::{Path, PathBuf};
|
||||
use crate::sys::fs as fs_imp;
|
||||
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
|
||||
@ -629,12 +629,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<u8>) -> io::Result<usize> {
|
||||
buf.reserve(buffer_capacity_required(self));
|
||||
@ -687,12 +681,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<u8>) -> io::Result<usize> {
|
||||
buf.reserve(buffer_capacity_required(self));
|
||||
|
@ -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<R>` struct adds buffering to any reader.
|
||||
///
|
||||
@ -47,9 +48,10 @@ use crate::io::{
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct BufReader<R> {
|
||||
inner: R,
|
||||
buf: Box<[u8]>,
|
||||
buf: Box<[MaybeUninit<u8>]>,
|
||||
pos: usize,
|
||||
cap: usize,
|
||||
init: usize,
|
||||
}
|
||||
|
||||
impl<R: Read> BufReader<R> {
|
||||
@ -91,11 +93,8 @@ impl<R: Read> BufReader<R> {
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> {
|
||||
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,7 @@ impl<R> BufReader<R> {
|
||||
/// ```
|
||||
#[stable(feature = "bufreader_buffer", since = "1.37.0")]
|
||||
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.
|
||||
@ -271,6 +270,25 @@ impl<R: Read> Read for BufReader<R> {
|
||||
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 +321,11 @@ impl<R: Read> Read for BufReader<R> {
|
||||
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<u8>) -> io::Result<usize> {
|
||||
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 +376,24 @@ impl<R: Read> BufRead for BufReader<R> {
|
||||
// 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 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])
|
||||
// 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) {
|
||||
|
@ -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];
|
||||
|
@ -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,23 @@ impl<I: Write> BufferedCopySpec for BufWriter<I> {
|
||||
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;
|
||||
|
||||
loop {
|
||||
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 {
|
||||
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.
|
||||
if read_buf.capacity() >= DEFAULT_BUF_SIZE {
|
||||
match reader.read_buf(&mut read_buf) {
|
||||
//Ok(0) => return Ok(len), // EOF reached
|
||||
Ok(()) => {
|
||||
let bytes_read = read_buf.filled_len();
|
||||
|
||||
if bytes_read == 0 {
|
||||
return Ok(len);
|
||||
}
|
||||
|
||||
// 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 +119,26 @@ fn stack_buffer_copy<R: Read + ?Sized, W: Write + ?Sized>(
|
||||
reader: &mut R,
|
||||
writer: &mut W,
|
||||
) -> Result<u64> {
|
||||
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)
|
||||
}
|
||||
|
@ -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<usize> {
|
||||
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")]
|
||||
|
@ -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<R: Read + ?Sized> 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<usize> {
|
||||
(**self).read_vectored(bufs)
|
||||
@ -29,11 +34,6 @@ impl<R: Read + ?Sized> 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<u8>) -> io::Result<usize> {
|
||||
(**self).read_to_end(buf)
|
||||
@ -123,6 +123,11 @@ impl<R: Read + ?Sized> Read for Box<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<usize> {
|
||||
(**self).read_vectored(bufs)
|
||||
@ -133,11 +138,6 @@ impl<R: Read + ?Sized> Read for Box<R> {
|
||||
(**self).is_read_vectored()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
(**self).initializer()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
(**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<usize> {
|
||||
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() {
|
||||
|
@ -256,7 +256,6 @@ use crate::convert::TryInto;
|
||||
use crate::fmt;
|
||||
use crate::mem::replace;
|
||||
use crate::ops::{Deref, DerefMut};
|
||||
use crate::ptr;
|
||||
use crate::slice;
|
||||
use crate::str;
|
||||
use crate::sys;
|
||||
@ -288,12 +287,16 @@ pub use self::stdio::{_eprint, _print};
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use self::util::{empty, repeat, sink, Empty, Repeat, Sink};
|
||||
|
||||
#[unstable(feature = "read_buf", issue = "78485")]
|
||||
pub use self::readbuf::ReadBuf;
|
||||
|
||||
mod buffered;
|
||||
pub(crate) mod copy;
|
||||
mod cursor;
|
||||
mod error;
|
||||
mod impls;
|
||||
pub mod prelude;
|
||||
mod readbuf;
|
||||
mod stdio;
|
||||
mod util;
|
||||
|
||||
@ -359,68 +362,39 @@ where
|
||||
// Because we're extending the buffer with uninitialized data for trusted
|
||||
// readers, we need to make sure to truncate that if any of this panics.
|
||||
pub(crate) fn default_read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> {
|
||||
let start_len = buf.len();
|
||||
let start_cap = buf.capacity();
|
||||
let mut g = Guard { len: buf.len(), buf };
|
||||
let initial_len = buf.len(); // need to know so we can return how many bytes we read
|
||||
|
||||
let mut initialized = 0; // Extra initalized bytes from previous loop iteration
|
||||
loop {
|
||||
// If we've read all the way up to the capacity, reserve more space.
|
||||
if g.len == g.buf.capacity() {
|
||||
g.buf.reserve(32);
|
||||
if buf.len() == buf.capacity() {
|
||||
buf.reserve(32); // buf is full, need more space
|
||||
}
|
||||
|
||||
// Initialize any excess capacity and adjust the length so we can write
|
||||
// to it.
|
||||
if g.buf.len() < g.buf.capacity() {
|
||||
unsafe {
|
||||
// FIXME(danielhenrymantilla): #42788
|
||||
//
|
||||
// - This creates a (mut) reference to a slice of
|
||||
// _uninitialized_ integers, which is **undefined behavior**
|
||||
//
|
||||
// - Only the standard library gets to soundly "ignore" this,
|
||||
// based on its privileged knowledge of unstable rustc
|
||||
// internals;
|
||||
let capacity = g.buf.capacity();
|
||||
g.buf.set_len(capacity);
|
||||
r.initializer().initialize(&mut g.buf[g.len..]);
|
||||
}
|
||||
let mut read_buf = ReadBuf::uninit(buf.spare_capacity_mut());
|
||||
unsafe {
|
||||
// add back extra initalized bytes, we don't want to reinitalize initalized bytes
|
||||
read_buf.assume_init(initialized);
|
||||
}
|
||||
|
||||
let buf = &mut g.buf[g.len..];
|
||||
match r.read(buf) {
|
||||
Ok(0) => return Ok(g.len - start_len),
|
||||
Ok(n) => {
|
||||
// We can't allow bogus values from read. If it is too large, the returned vec could have its length
|
||||
// set past its capacity, or if it overflows the vec could be shortened which could create an invalid
|
||||
// string if this is called via read_to_string.
|
||||
assert!(n <= buf.len());
|
||||
g.len += n;
|
||||
}
|
||||
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
|
||||
match r.read_buf(&mut read_buf) {
|
||||
Ok(()) => {}
|
||||
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
|
||||
if g.len == g.buf.capacity() && g.buf.capacity() == start_cap {
|
||||
// The buffer might be an exact fit. Let's read into a probe buffer
|
||||
// and see if it returns `Ok(0)`. If so, we've avoided an
|
||||
// unnecessary doubling of the capacity. But if not, append the
|
||||
// probe buffer to the primary buffer and let its capacity grow.
|
||||
let mut probe = [0u8; 32];
|
||||
if read_buf.filled_len() == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
loop {
|
||||
match r.read(&mut probe) {
|
||||
Ok(0) => return Ok(g.len - start_len),
|
||||
Ok(n) => {
|
||||
g.buf.extend_from_slice(&probe[..n]);
|
||||
g.len += n;
|
||||
break;
|
||||
}
|
||||
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
// store how much was initialized but not filled
|
||||
initialized = read_buf.initialized_len() - read_buf.filled_len();
|
||||
let new_len = read_buf.filled_len() + buf.len();
|
||||
unsafe {
|
||||
buf.set_len(new_len);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(buf.len() - initial_len)
|
||||
}
|
||||
|
||||
pub(crate) fn default_read_to_string<R: Read + ?Sized>(
|
||||
@ -656,31 +630,6 @@ pub trait Read {
|
||||
false
|
||||
}
|
||||
|
||||
/// Determines if this `Read`er can work with buffers of uninitialized
|
||||
/// memory.
|
||||
///
|
||||
/// The default implementation returns an initializer which will zero
|
||||
/// buffers.
|
||||
///
|
||||
/// If a `Read`er guarantees that it can work properly with uninitialized
|
||||
/// memory, it should call [`Initializer::nop()`]. See the documentation for
|
||||
/// [`Initializer`] for details.
|
||||
///
|
||||
/// The behavior of this method must be independent of the state of the
|
||||
/// `Read`er - the method only takes `&self` so that it can be used through
|
||||
/// trait objects.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This method is unsafe because a `Read`er could otherwise return a
|
||||
/// non-zeroing `Initializer` from another `Read` type without an `unsafe`
|
||||
/// block.
|
||||
#[unstable(feature = "read_initializer", issue = "42788")]
|
||||
#[inline]
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
Initializer::zeroing()
|
||||
}
|
||||
|
||||
/// Read all bytes until EOF in this source, placing them into `buf`.
|
||||
///
|
||||
/// All bytes read from this source will be appended to the specified buffer
|
||||
@ -830,7 +779,42 @@ pub trait Read {
|
||||
default_read_exact(self, buf)
|
||||
}
|
||||
|
||||
/// Creates a "by reference" adapter for this instance of `Read`.
|
||||
/// Pull some bytes from this source into the specified buffer.
|
||||
///
|
||||
/// This is equivalent to the [`read`](Read::read) method, except that it is passed a [`ReadBuf`] rather than `[u8]` to allow use
|
||||
/// with uninitialized buffers. The new data will be appended to any existing contents of `buf`.
|
||||
///
|
||||
/// The default implementation delegates to `read`.
|
||||
#[unstable(feature = "read_buf", issue = "78485")]
|
||||
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> {
|
||||
let n = self.read(buf.initialize_unfilled())?;
|
||||
buf.add_filled(n);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Read the exact number of bytes required to fill `buf`.
|
||||
///
|
||||
/// This is equivalent to the [`read_exact`](Read::read_exact) method, except that it is passed a [`ReadBuf`] rather than `[u8]` to
|
||||
/// allow use with uninitialized buffers.
|
||||
#[unstable(feature = "read_buf", issue = "78485")]
|
||||
fn read_buf_exact(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> {
|
||||
while buf.remaining() > 0 {
|
||||
let prev_filled = buf.filled().len();
|
||||
match self.read_buf(buf) {
|
||||
Ok(()) => {}
|
||||
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
|
||||
if buf.filled().len() == prev_filled {
|
||||
return Err(Error::new(ErrorKind::UnexpectedEof, "failed to fill buffer"));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Creates a "by reference" adaptor for this instance of `Read`.
|
||||
///
|
||||
/// The returned adapter also implements `Read` and will simply borrow this
|
||||
/// current reader.
|
||||
@ -1300,53 +1284,6 @@ impl<'a> Deref for IoSlice<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A type used to conditionally initialize buffers passed to `Read` methods.
|
||||
#[unstable(feature = "read_initializer", issue = "42788")]
|
||||
#[derive(Debug)]
|
||||
pub struct Initializer(bool);
|
||||
|
||||
impl Initializer {
|
||||
/// Returns a new `Initializer` which will zero out buffers.
|
||||
#[unstable(feature = "read_initializer", issue = "42788")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn zeroing() -> Initializer {
|
||||
Initializer(true)
|
||||
}
|
||||
|
||||
/// Returns a new `Initializer` which will not zero out buffers.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This may only be called by `Read`ers which guarantee that they will not
|
||||
/// read from buffers passed to `Read` methods, and that the return value of
|
||||
/// the method accurately reflects the number of bytes that have been
|
||||
/// written to the head of the buffer.
|
||||
#[unstable(feature = "read_initializer", issue = "42788")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub unsafe fn nop() -> Initializer {
|
||||
Initializer(false)
|
||||
}
|
||||
|
||||
/// Indicates if a buffer should be initialized.
|
||||
#[unstable(feature = "read_initializer", issue = "42788")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn should_initialize(&self) -> bool {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Initializes a buffer if necessary.
|
||||
#[unstable(feature = "read_initializer", issue = "42788")]
|
||||
#[inline]
|
||||
pub fn initialize(&self, buf: &mut [u8]) {
|
||||
if self.should_initialize() {
|
||||
unsafe { ptr::write_bytes(buf.as_mut_ptr(), 0, buf.len()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait for objects which are byte-oriented sinks.
|
||||
///
|
||||
/// Implementors of the `Write` trait are sometimes called 'writers'.
|
||||
@ -2403,11 +2340,6 @@ impl<T: Read, U: Read> Read for Chain<T, U> {
|
||||
}
|
||||
self.second.read_vectored(bufs)
|
||||
}
|
||||
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
let initializer = self.first.initializer();
|
||||
if initializer.should_initialize() { initializer } else { self.second.initializer() }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "chain_bufread", since = "1.9.0")]
|
||||
@ -2610,8 +2542,46 @@ impl<T: Read> Read for Take<T> {
|
||||
Ok(n)
|
||||
}
|
||||
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
self.inner.initializer()
|
||||
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> {
|
||||
// Don't call into inner reader at all at EOF because it may still block
|
||||
if self.limit == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let prev_filled = buf.filled_len();
|
||||
|
||||
if self.limit <= buf.remaining() as u64 {
|
||||
let extra_init = buf.initialized_len() - buf.filled_len();
|
||||
let ibuf = unsafe { &mut buf.unfilled_mut()[..self.limit as usize] };
|
||||
|
||||
let mut sliced_buf = ReadBuf::uninit(ibuf);
|
||||
|
||||
unsafe {
|
||||
sliced_buf.assume_init(extra_init);
|
||||
}
|
||||
|
||||
self.inner.read_buf(&mut sliced_buf)?;
|
||||
|
||||
let new_init = sliced_buf.initialized_len();
|
||||
let filled = sliced_buf.filled_len();
|
||||
|
||||
// sliced_buf / ibuf must drop here
|
||||
|
||||
unsafe {
|
||||
buf.assume_init(new_init);
|
||||
}
|
||||
|
||||
buf.add_filled(filled);
|
||||
|
||||
self.limit -= filled as u64;
|
||||
} else {
|
||||
self.inner.read_buf(buf)?;
|
||||
|
||||
//inner may unfill
|
||||
self.limit -= buf.filled_len().saturating_sub(prev_filled) as u64;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
245
library/std/src/io/readbuf.rs
Normal file
245
library/std/src/io/readbuf.rs
Normal 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
|
||||
}
|
||||
}
|
169
library/std/src/io/readbuf/tests.rs
Normal file
169
library/std/src/io/readbuf/tests.rs
Normal 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]);
|
||||
}
|
@ -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<u8>) -> io::Result<usize> {
|
||||
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<u8>) -> io::Result<usize> {
|
||||
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<u8>) -> io::Result<usize> {
|
||||
self.inner.read_to_end(buf)
|
||||
}
|
||||
|
@ -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();
|
||||
});
|
||||
}
|
||||
|
@ -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,22 @@ impl Read for Repeat {
|
||||
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]
|
||||
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
let mut nwritten = 0;
|
||||
@ -143,11 +159,6 @@ impl Read for Repeat {
|
||||
fn is_read_vectored(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
Initializer::nop()
|
||||
}
|
||||
}
|
||||
|
||||
impl SizeHint for Repeat {
|
||||
|
@ -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]
|
||||
|
@ -306,6 +306,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)]
|
||||
@ -321,6 +322,7 @@
|
||||
#![feature(panic_unwind)]
|
||||
#![feature(pin_static_ref)]
|
||||
#![feature(prelude_import)]
|
||||
#![feature(ptr_as_uninit)]
|
||||
#![feature(ptr_internals)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(rustc_private)]
|
||||
|
@ -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 {
|
||||
|
@ -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")]
|
||||
|
@ -109,7 +109,7 @@ use crate::io::prelude::*;
|
||||
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;
|
||||
@ -361,12 +361,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<AnonPipe> for ChildStdout {
|
||||
@ -428,12 +422,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<AnonPipe> for ChildStderr {
|
||||
|
@ -4,7 +4,7 @@
|
||||
mod tests;
|
||||
|
||||
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::sys::cvt;
|
||||
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> {
|
||||
(**self).read(buf)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
Initializer::nop()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<OwnedFd> for FileDesc {
|
||||
|
Loading…
x
Reference in New Issue
Block a user