mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-19 18:34:08 +00:00
Add Read::initializer
.
This is an API that allows types to indicate that they can be passed buffers of uninitialized memory which can improve performance.
This commit is contained in:
parent
445077963c
commit
ecbb896b9e
@ -0,0 +1,7 @@
|
||||
# `read_initializer`
|
||||
|
||||
The tracking issue for this feature is: [#42788]
|
||||
|
||||
[#0]: https://github.com/rust-lang/rust/issues/42788
|
||||
|
||||
------------------------
|
@ -19,7 +19,7 @@
|
||||
|
||||
use fmt;
|
||||
use ffi::OsString;
|
||||
use io::{self, SeekFrom, Seek, Read, Write};
|
||||
use io::{self, SeekFrom, Seek, Read, Initializer, Write};
|
||||
use path::{Path, PathBuf};
|
||||
use sys::fs as fs_imp;
|
||||
use sys_common::{AsInnerMut, FromInner, AsInner, IntoInner};
|
||||
@ -446,8 +446,10 @@ impl Read for File {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.inner.read(buf)
|
||||
}
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
self.inner.read_to_end(buf)
|
||||
|
||||
#[inline]
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
Initializer::nop()
|
||||
}
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -468,8 +470,10 @@ impl<'a> Read for &'a File {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.inner.read(buf)
|
||||
}
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
self.inner.read_to_end(buf)
|
||||
|
||||
#[inline]
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
Initializer::nop()
|
||||
}
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -15,7 +15,7 @@ use io::prelude::*;
|
||||
use cmp;
|
||||
use error;
|
||||
use fmt;
|
||||
use io::{self, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom};
|
||||
use io::{self, Initializer, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom};
|
||||
use memchr;
|
||||
|
||||
/// The `BufReader` struct adds buffering to any reader.
|
||||
@ -92,11 +92,16 @@ impl<R: Read> BufReader<R> {
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn with_capacity(cap: usize, inner: R) -> BufReader<R> {
|
||||
BufReader {
|
||||
inner: inner,
|
||||
buf: vec![0; cap].into_boxed_slice(),
|
||||
pos: 0,
|
||||
cap: 0,
|
||||
unsafe {
|
||||
let mut buffer = Vec::with_capacity(cap);
|
||||
buffer.set_len(cap);
|
||||
inner.initializer().initialize(&mut buffer);
|
||||
BufReader {
|
||||
inner: inner,
|
||||
buf: buffer.into_boxed_slice(),
|
||||
pos: 0,
|
||||
cap: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,6 +185,11 @@ impl<R: Read> Read for BufReader<R> {
|
||||
self.consume(nread);
|
||||
Ok(nread)
|
||||
}
|
||||
|
||||
// we can't skip unconditionally because of the large buffer case in read.
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
self.inner.initializer()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -12,7 +12,7 @@ use io::prelude::*;
|
||||
|
||||
use core::convert::TryInto;
|
||||
use cmp;
|
||||
use io::{self, SeekFrom, Error, ErrorKind};
|
||||
use io::{self, Initializer, SeekFrom, Error, ErrorKind};
|
||||
|
||||
/// A `Cursor` wraps another type and provides it with a
|
||||
/// [`Seek`] implementation.
|
||||
@ -229,6 +229,11 @@ impl<T> Read for Cursor<T> where T: AsRef<[u8]> {
|
||||
self.pos += n as u64;
|
||||
Ok(n)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
Initializer::nop()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -9,7 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
use cmp;
|
||||
use io::{self, SeekFrom, Read, Write, Seek, BufRead, Error, ErrorKind};
|
||||
use io::{self, SeekFrom, Read, Initializer, Write, Seek, BufRead, Error, ErrorKind};
|
||||
use fmt;
|
||||
use mem;
|
||||
|
||||
@ -23,6 +23,11 @@ impl<'a, R: Read + ?Sized> Read for &'a mut R {
|
||||
(**self).read(buf)
|
||||
}
|
||||
|
||||
#[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)
|
||||
@ -87,6 +92,11 @@ impl<R: Read + ?Sized> Read for Box<R> {
|
||||
(**self).read(buf)
|
||||
}
|
||||
|
||||
#[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)
|
||||
@ -171,6 +181,11 @@ impl<'a> Read for &'a [u8] {
|
||||
Ok(amt)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
Initializer::nop()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
|
||||
if buf.len() > self.len() {
|
||||
|
@ -275,6 +275,7 @@ use fmt;
|
||||
use result;
|
||||
use str;
|
||||
use memchr;
|
||||
use ptr;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use self::buffered::{BufReader, BufWriter, LineWriter};
|
||||
@ -292,7 +293,7 @@ pub use self::stdio::{stdin, stdout, stderr, Stdin, Stdout, Stderr};
|
||||
pub use self::stdio::{StdoutLock, StderrLock, StdinLock};
|
||||
#[unstable(feature = "print_internals", issue = "0")]
|
||||
pub use self::stdio::{_print, _eprint};
|
||||
#[unstable(feature = "libstd_io_internals", issue = "0")]
|
||||
#[unstable(feature = "libstd_io_internals", issue = "42788")]
|
||||
#[doc(no_inline, hidden)]
|
||||
pub use self::stdio::{set_panic, set_print};
|
||||
|
||||
@ -307,6 +308,14 @@ mod stdio;
|
||||
|
||||
const DEFAULT_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
|
||||
|
||||
struct Guard<'a> { buf: &'a mut Vec<u8>, len: usize }
|
||||
|
||||
impl<'a> Drop for Guard<'a> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { self.buf.set_len(self.len); }
|
||||
}
|
||||
}
|
||||
|
||||
// A few methods below (read_to_string, read_line) will append data into a
|
||||
// `String` buffer, but we need to be pretty careful when doing this. The
|
||||
// implementation will just call `.as_mut_vec()` and then delegate to a
|
||||
@ -328,23 +337,16 @@ const DEFAULT_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
|
||||
fn append_to_string<F>(buf: &mut String, f: F) -> Result<usize>
|
||||
where F: FnOnce(&mut Vec<u8>) -> Result<usize>
|
||||
{
|
||||
struct Guard<'a> { s: &'a mut Vec<u8>, len: usize }
|
||||
impl<'a> Drop for Guard<'a> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { self.s.set_len(self.len); }
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let mut g = Guard { len: buf.len(), s: buf.as_mut_vec() };
|
||||
let ret = f(g.s);
|
||||
if str::from_utf8(&g.s[g.len..]).is_err() {
|
||||
let mut g = Guard { len: buf.len(), buf: buf.as_mut_vec() };
|
||||
let ret = f(g.buf);
|
||||
if str::from_utf8(&g.buf[g.len..]).is_err() {
|
||||
ret.and_then(|_| {
|
||||
Err(Error::new(ErrorKind::InvalidData,
|
||||
"stream did not contain valid UTF-8"))
|
||||
})
|
||||
} else {
|
||||
g.len = g.s.len();
|
||||
g.len = g.buf.len();
|
||||
ret
|
||||
}
|
||||
}
|
||||
@ -356,25 +358,32 @@ fn append_to_string<F>(buf: &mut String, f: F) -> Result<usize>
|
||||
// of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every
|
||||
// time is 4,500 times (!) slower than this if the reader has a very small
|
||||
// amount of data to return.
|
||||
//
|
||||
// Because we're extending the buffer with uninitialized data for trusted
|
||||
// readers, we need to make sure to truncate that if any of this panics.
|
||||
fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> {
|
||||
let start_len = buf.len();
|
||||
let mut len = start_len;
|
||||
let mut g = Guard { len: buf.len(), buf: buf };
|
||||
let mut new_write_size = 16;
|
||||
let ret;
|
||||
loop {
|
||||
if len == buf.len() {
|
||||
if g.len == g.buf.len() {
|
||||
if new_write_size < DEFAULT_BUF_SIZE {
|
||||
new_write_size *= 2;
|
||||
}
|
||||
buf.resize(len + new_write_size, 0);
|
||||
unsafe {
|
||||
g.buf.reserve(new_write_size);
|
||||
g.buf.set_len(g.len + new_write_size);
|
||||
r.initializer().initialize(&mut g.buf[g.len..]);
|
||||
}
|
||||
}
|
||||
|
||||
match r.read(&mut buf[len..]) {
|
||||
match r.read(&mut g.buf[g.len..]) {
|
||||
Ok(0) => {
|
||||
ret = Ok(len - start_len);
|
||||
ret = Ok(g.len - start_len);
|
||||
break;
|
||||
}
|
||||
Ok(n) => len += n,
|
||||
Ok(n) => g.len += n,
|
||||
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
|
||||
Err(e) => {
|
||||
ret = Err(e);
|
||||
@ -383,7 +392,6 @@ fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize>
|
||||
}
|
||||
}
|
||||
|
||||
buf.truncate(len);
|
||||
ret
|
||||
}
|
||||
|
||||
@ -494,6 +502,31 @@ pub trait Read {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// # Unsafety
|
||||
///
|
||||
/// 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
|
||||
@ -829,6 +862,50 @@ pub trait Read {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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")]
|
||||
#[inline]
|
||||
pub fn zeroing() -> Initializer {
|
||||
Initializer(true)
|
||||
}
|
||||
|
||||
/// Returns a new `Initializer` which will not zero out buffers.
|
||||
///
|
||||
/// # Unsafety
|
||||
///
|
||||
/// 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")]
|
||||
#[inline]
|
||||
pub unsafe fn nop() -> Initializer {
|
||||
Initializer(false)
|
||||
}
|
||||
|
||||
/// Indicates if a buffer should be initialized.
|
||||
#[unstable(feature = "read_initializer", issue = "42788")]
|
||||
#[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'.
|
||||
@ -1608,6 +1685,15 @@ impl<T: Read, U: Read> Read for Chain<T, U> {
|
||||
}
|
||||
self.second.read(buf)
|
||||
}
|
||||
|
||||
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")]
|
||||
@ -1772,6 +1858,10 @@ impl<T: Read> Read for Take<T> {
|
||||
self.limit -= n as u64;
|
||||
Ok(n)
|
||||
}
|
||||
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
self.inner.initializer()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -13,7 +13,7 @@ use io::prelude::*;
|
||||
use cell::RefCell;
|
||||
use fmt;
|
||||
use io::lazy::Lazy;
|
||||
use io::{self, BufReader, LineWriter};
|
||||
use io::{self, Initializer, BufReader, LineWriter};
|
||||
use sync::{Arc, Mutex, MutexGuard};
|
||||
use sys::stdio;
|
||||
use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
|
||||
@ -75,8 +75,10 @@ fn stderr_raw() -> io::Result<StderrRaw> { stdio::Stderr::new().map(StderrRaw) }
|
||||
|
||||
impl Read for StdinRaw {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
self.0.read_to_end(buf)
|
||||
|
||||
#[inline]
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
Initializer::nop()
|
||||
}
|
||||
}
|
||||
impl Write for StdoutRaw {
|
||||
@ -116,12 +118,6 @@ impl<R: io::Read> io::Read for Maybe<R> {
|
||||
Maybe::Fake => Ok(0)
|
||||
}
|
||||
}
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
match *self {
|
||||
Maybe::Real(ref mut r) => handle_ebadf(r.read_to_end(buf), 0),
|
||||
Maybe::Fake => Ok(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
|
||||
@ -294,6 +290,10 @@ impl Read for Stdin {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.lock().read(buf)
|
||||
}
|
||||
#[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)
|
||||
}
|
||||
@ -310,8 +310,9 @@ impl<'a> Read for StdinLock<'a> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.inner.read(buf)
|
||||
}
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
self.inner.read_to_end(buf)
|
||||
#[inline]
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
Initializer::nop()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,8 @@
|
||||
#![allow(missing_copy_implementations)]
|
||||
|
||||
use fmt;
|
||||
use io::{self, Read, Write, ErrorKind, BufRead};
|
||||
use io::{self, Read, Initializer, Write, ErrorKind, BufRead};
|
||||
use mem;
|
||||
|
||||
/// Copies the entire contents of a reader into a writer.
|
||||
///
|
||||
@ -47,7 +48,12 @@ use io::{self, Read, Write, ErrorKind, BufRead};
|
||||
pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> io::Result<u64>
|
||||
where R: Read, W: Write
|
||||
{
|
||||
let mut buf = [0; super::DEFAULT_BUF_SIZE];
|
||||
let mut buf = unsafe {
|
||||
let mut buf: [u8; super::DEFAULT_BUF_SIZE] = mem::uninitialized();
|
||||
reader.initializer().initialize(&mut buf);
|
||||
buf
|
||||
};
|
||||
|
||||
let mut written = 0;
|
||||
loop {
|
||||
let len = match reader.read(&mut buf) {
|
||||
@ -90,11 +96,19 @@ pub fn empty() -> Empty { Empty { _priv: () } }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Read for Empty {
|
||||
#[inline]
|
||||
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> { Ok(0) }
|
||||
|
||||
#[inline]
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
Initializer::nop()
|
||||
}
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl BufRead for Empty {
|
||||
#[inline]
|
||||
fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(&[]) }
|
||||
#[inline]
|
||||
fn consume(&mut self, _n: usize) {}
|
||||
}
|
||||
|
||||
@ -133,12 +147,18 @@ pub fn repeat(byte: u8) -> Repeat { Repeat { byte: byte } }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Read for Repeat {
|
||||
#[inline]
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
for slot in &mut *buf {
|
||||
*slot = self.byte;
|
||||
}
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
Initializer::nop()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "std_debug", since = "1.16.0")]
|
||||
@ -176,7 +196,9 @@ pub fn sink() -> Sink { Sink { _priv: () } }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Write for Sink {
|
||||
#[inline]
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { Ok(buf.len()) }
|
||||
#[inline]
|
||||
fn flush(&mut self) -> io::Result<()> { Ok(()) }
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
use io::prelude::*;
|
||||
|
||||
use fmt;
|
||||
use io;
|
||||
use io::{self, Initializer};
|
||||
use net::{ToSocketAddrs, SocketAddr, Shutdown};
|
||||
use sys_common::net as net_imp;
|
||||
use sys_common::{AsInner, FromInner, IntoInner};
|
||||
@ -481,8 +481,10 @@ impl TcpStream {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Read for TcpStream {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
self.0.read_to_end(buf)
|
||||
|
||||
#[inline]
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
Initializer::nop()
|
||||
}
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -493,8 +495,10 @@ impl Write for TcpStream {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a> Read for &'a TcpStream {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
self.0.read_to_end(buf)
|
||||
|
||||
#[inline]
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
Initializer::nop()
|
||||
}
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -60,7 +60,7 @@ use io::prelude::*;
|
||||
use ffi::OsStr;
|
||||
use fmt;
|
||||
use fs;
|
||||
use io;
|
||||
use io::{self, Initializer};
|
||||
use path::Path;
|
||||
use str;
|
||||
use sys::pipe::{read2, AnonPipe};
|
||||
@ -208,8 +208,9 @@ impl Read for ChildStdout {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.inner.read(buf)
|
||||
}
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
self.inner.read_to_end(buf)
|
||||
#[inline]
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
Initializer::nop()
|
||||
}
|
||||
}
|
||||
|
||||
@ -250,8 +251,9 @@ impl Read for ChildStderr {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.inner.read(buf)
|
||||
}
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
self.inner.read_to_end(buf)
|
||||
#[inline]
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
Initializer::nop()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,6 @@ use io::{self, Read};
|
||||
use mem;
|
||||
use sys::{cvt, syscall};
|
||||
use sys_common::AsInner;
|
||||
use sys_common::io::read_to_end_uninitialized;
|
||||
|
||||
pub struct FileDesc {
|
||||
fd: usize,
|
||||
@ -78,10 +77,6 @@ impl<'a> Read for &'a FileDesc {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
(**self).read(buf)
|
||||
}
|
||||
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
unsafe { read_to_end_uninitialized(self, buf) }
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<usize> for FileDesc {
|
||||
|
@ -285,10 +285,6 @@ impl File {
|
||||
self.0.read(buf)
|
||||
}
|
||||
|
||||
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
self.0.read_to_end(buf)
|
||||
}
|
||||
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.0.write(buf)
|
||||
}
|
||||
|
@ -41,10 +41,6 @@ impl TcpStream {
|
||||
self.0.read(buf)
|
||||
}
|
||||
|
||||
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> Result<usize> {
|
||||
self.0.read_to_end(buf)
|
||||
}
|
||||
|
||||
pub fn write(&self, buf: &[u8]) -> Result<usize> {
|
||||
self.0.write(buf)
|
||||
}
|
||||
|
@ -34,10 +34,6 @@ impl AnonPipe {
|
||||
self.0.read(buf)
|
||||
}
|
||||
|
||||
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
self.0.read_to_end(buf)
|
||||
}
|
||||
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.0.write(buf)
|
||||
}
|
||||
|
@ -25,13 +25,6 @@ impl Stdin {
|
||||
fd.into_raw();
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
let fd = FileDesc::new(0);
|
||||
let ret = fd.read_to_end(buf);
|
||||
fd.into_raw();
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl Stdout {
|
||||
|
@ -17,7 +17,7 @@ use libc;
|
||||
use ascii;
|
||||
use ffi::OsStr;
|
||||
use fmt;
|
||||
use io;
|
||||
use io::{self, Initializer};
|
||||
use mem;
|
||||
use net::Shutdown;
|
||||
use os::unix::ffi::OsStrExt;
|
||||
@ -516,8 +516,9 @@ impl io::Read for UnixStream {
|
||||
io::Read::read(&mut &*self, buf)
|
||||
}
|
||||
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
io::Read::read_to_end(&mut &*self, buf)
|
||||
#[inline]
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
Initializer::nop()
|
||||
}
|
||||
}
|
||||
|
||||
@ -527,8 +528,9 @@ impl<'a> io::Read for &'a UnixStream {
|
||||
self.0.read(buf)
|
||||
}
|
||||
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
self.0.read_to_end(buf)
|
||||
#[inline]
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
Initializer::nop()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,6 @@ use mem;
|
||||
use sync::atomic::{AtomicBool, Ordering};
|
||||
use sys::cvt;
|
||||
use sys_common::AsInner;
|
||||
use sys_common::io::read_to_end_uninitialized;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FileDesc {
|
||||
@ -232,10 +231,6 @@ impl<'a> Read for &'a FileDesc {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
(**self).read(buf)
|
||||
}
|
||||
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
unsafe { read_to_end_uninitialized(self, buf) }
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<c_int> for FileDesc {
|
||||
|
@ -491,10 +491,6 @@ impl File {
|
||||
self.0.read(buf)
|
||||
}
|
||||
|
||||
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
self.0.read_to_end(buf)
|
||||
}
|
||||
|
||||
pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
|
||||
self.0.read_at(buf, offset)
|
||||
}
|
||||
|
@ -198,10 +198,6 @@ impl Socket {
|
||||
self.recv_from_with_flags(buf, MSG_PEEK)
|
||||
}
|
||||
|
||||
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
self.0.read_to_end(buf)
|
||||
}
|
||||
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.0.write(buf)
|
||||
}
|
||||
|
@ -71,10 +71,6 @@ impl AnonPipe {
|
||||
self.0.read(buf)
|
||||
}
|
||||
|
||||
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
self.0.read_to_end(buf)
|
||||
}
|
||||
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.0.write(buf)
|
||||
}
|
||||
|
@ -25,13 +25,6 @@ impl Stdin {
|
||||
fd.into_raw();
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
let fd = FileDesc::new(libc::STDIN_FILENO);
|
||||
let ret = fd.read_to_end(buf);
|
||||
fd.into_raw();
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl Stdout {
|
||||
|
@ -324,10 +324,6 @@ impl File {
|
||||
self.handle.read_at(buf, offset)
|
||||
}
|
||||
|
||||
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
self.handle.read_to_end(buf)
|
||||
}
|
||||
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.handle.write(buf)
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ use ops::Deref;
|
||||
use ptr;
|
||||
use sys::c;
|
||||
use sys::cvt;
|
||||
use sys_common::io::read_to_end_uninitialized;
|
||||
|
||||
/// An owned container for `HANDLE` object, closing them on Drop.
|
||||
///
|
||||
@ -216,8 +215,4 @@ impl<'a> Read for &'a RawHandle {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
(**self).read(buf)
|
||||
}
|
||||
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
unsafe { read_to_end_uninitialized(self, buf) }
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ use sync::Once;
|
||||
use sys::c;
|
||||
use sys;
|
||||
use sys_common::{self, AsInner, FromInner, IntoInner};
|
||||
use sys_common::io::read_to_end_uninitialized;
|
||||
use sys_common::net;
|
||||
use time::Duration;
|
||||
|
||||
@ -200,11 +199,6 @@ impl Socket {
|
||||
self.recv_from_with_flags(buf, c::MSG_PEEK)
|
||||
}
|
||||
|
||||
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
let mut me = self;
|
||||
(&mut me).read_to_end(buf)
|
||||
}
|
||||
|
||||
pub fn set_timeout(&self, dur: Option<Duration>,
|
||||
kind: c_int) -> io::Result<()> {
|
||||
let timeout = match dur {
|
||||
@ -283,10 +277,6 @@ impl<'a> Read for &'a Socket {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
(**self).read(buf)
|
||||
}
|
||||
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
unsafe { read_to_end_uninitialized(self, buf) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Socket {
|
||||
|
@ -164,10 +164,6 @@ impl AnonPipe {
|
||||
self.inner.read(buf)
|
||||
}
|
||||
|
||||
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
self.inner.read_to_end(buf)
|
||||
}
|
||||
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.inner.write(buf)
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ use sync::Mutex;
|
||||
use sys::c;
|
||||
use sys::cvt;
|
||||
use sys::handle::Handle;
|
||||
use sys_common::io::read_to_end_uninitialized;
|
||||
|
||||
pub enum Output {
|
||||
Console(c::HANDLE),
|
||||
@ -151,10 +150,6 @@ impl<'a> Read for &'a Stdin {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
(**self).read(buf)
|
||||
}
|
||||
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
unsafe { read_to_end_uninitialized(self, buf) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Stdout {
|
||||
|
@ -7,51 +7,8 @@
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
use io;
|
||||
use io::ErrorKind;
|
||||
use io::Read;
|
||||
use slice::from_raw_parts_mut;
|
||||
|
||||
pub const DEFAULT_BUF_SIZE: usize = 8 * 1024;
|
||||
|
||||
// Provides read_to_end functionality over an uninitialized buffer.
|
||||
// This function is unsafe because it calls the underlying
|
||||
// read function with a slice into uninitialized memory. The default
|
||||
// implementation of read_to_end for readers will zero out new memory in
|
||||
// the buf before passing it to read, but avoiding this zero can often
|
||||
// lead to a fairly significant performance win.
|
||||
//
|
||||
// Implementations using this method have to adhere to two guarantees:
|
||||
// * The implementation of read never reads the buffer provided.
|
||||
// * The implementation of read correctly reports how many bytes were written.
|
||||
pub unsafe fn read_to_end_uninitialized(r: &mut Read, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
|
||||
let start_len = buf.len();
|
||||
buf.reserve(16);
|
||||
|
||||
// Always try to read into the empty space of the vector (from the length to the capacity).
|
||||
// If the vector ever fills up then we reserve an extra byte which should trigger the normal
|
||||
// reallocation routines for the vector, which will likely double the size.
|
||||
//
|
||||
// This function is similar to the read_to_end function in std::io, but the logic about
|
||||
// reservations and slicing is different enough that this is duplicated here.
|
||||
loop {
|
||||
if buf.len() == buf.capacity() {
|
||||
buf.reserve(1);
|
||||
}
|
||||
|
||||
let buf_slice = from_raw_parts_mut(buf.as_mut_ptr().offset(buf.len() as isize),
|
||||
buf.capacity() - buf.len());
|
||||
|
||||
match r.read(buf_slice) {
|
||||
Ok(0) => { return Ok(buf.len() - start_len); }
|
||||
Ok(n) => { let len = buf.len() + n; buf.set_len(len); },
|
||||
Err(ref e) if e.kind() == ErrorKind::Interrupted => { }
|
||||
Err(e) => { return Err(e); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code)] // not used on emscripten
|
||||
pub mod test {
|
||||
@ -91,89 +48,3 @@ pub mod test {
|
||||
TempDir(ret)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use io::prelude::*;
|
||||
use super::*;
|
||||
use io;
|
||||
use io::{ErrorKind, Take, Repeat, repeat};
|
||||
use slice::from_raw_parts;
|
||||
|
||||
struct ErrorRepeat {
|
||||
lr: Take<Repeat>
|
||||
}
|
||||
|
||||
fn error_repeat(byte: u8, limit: u64) -> ErrorRepeat {
|
||||
ErrorRepeat { lr: repeat(byte).take(limit) }
|
||||
}
|
||||
|
||||
impl Read for ErrorRepeat {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let ret = self.lr.read(buf);
|
||||
if let Ok(0) = ret {
|
||||
return Err(io::Error::new(ErrorKind::Other, ""))
|
||||
}
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
fn init_vec_data() -> Vec<u8> {
|
||||
let mut vec = vec![10u8; 200];
|
||||
unsafe { vec.set_len(0); }
|
||||
vec
|
||||
}
|
||||
|
||||
fn assert_all_eq(buf: &[u8], value: u8) {
|
||||
for n in buf {
|
||||
assert_eq!(*n, value);
|
||||
}
|
||||
}
|
||||
|
||||
fn validate(buf: &Vec<u8>, good_read_len: usize) {
|
||||
assert_all_eq(buf, 1u8);
|
||||
let cap = buf.capacity();
|
||||
let end_slice = unsafe { from_raw_parts(buf.as_ptr().offset(good_read_len as isize),
|
||||
cap - good_read_len) };
|
||||
assert_all_eq(end_slice, 10u8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_to_end_uninit_error() {
|
||||
let mut er = error_repeat(1,100);
|
||||
let mut vec = init_vec_data();
|
||||
if let Err(_) = unsafe { read_to_end_uninitialized(&mut er, &mut vec) } {
|
||||
validate(&vec, 100);
|
||||
} else {
|
||||
assert!(false);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_to_end_uninit_zero_len_vec() {
|
||||
let mut er = repeat(1).take(100);
|
||||
let mut vec = Vec::new();
|
||||
let n = unsafe{ read_to_end_uninitialized(&mut er, &mut vec).unwrap() };
|
||||
assert_all_eq(&vec, 1u8);
|
||||
assert_eq!(vec.len(), n);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_to_end_uninit_good() {
|
||||
let mut er = repeat(1).take(100);
|
||||
let mut vec = init_vec_data();
|
||||
let n = unsafe{ read_to_end_uninitialized(&mut er, &mut vec).unwrap() };
|
||||
validate(&vec, 100);
|
||||
assert_eq!(vec.len(), n);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
#[cfg_attr(target_os = "emscripten", ignore)]
|
||||
fn bench_uninitialized(b: &mut ::test::Bencher) {
|
||||
b.iter(|| {
|
||||
let mut lr = repeat(1).take(10000000);
|
||||
let mut vec = Vec::with_capacity(1024);
|
||||
unsafe { read_to_end_uninitialized(&mut lr, &mut vec) }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -243,10 +243,6 @@ impl TcpStream {
|
||||
self.inner.read(buf)
|
||||
}
|
||||
|
||||
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
self.inner.read_to_end(buf)
|
||||
}
|
||||
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
|
||||
let ret = cvt(unsafe {
|
||||
|
Loading…
Reference in New Issue
Block a user