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:
Steven Fackler 2017-05-14 21:29:18 -04:00
parent 445077963c
commit ecbb896b9e
28 changed files with 222 additions and 269 deletions

View file

@ -0,0 +1,7 @@
# `read_initializer`
The tracking issue for this feature is: [#42788]
[#0]: https://github.com/rust-lang/rust/issues/42788
------------------------

View file

@ -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")]

View file

@ -15,7 +15,7 @@
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 @@ pub fn new(inner: R) -> 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 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
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")]

View file

@ -12,7 +12,7 @@
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 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.pos += n as u64;
Ok(n)
}
#[inline]
unsafe fn initializer(&self) -> Initializer {
Initializer::nop()
}
}
#[stable(feature = "rust1", since = "1.0.0")]

View file

@ -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 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
(**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 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
(**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 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
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() {

View file

@ -275,6 +275,7 @@
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::{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 @@
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 @@
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 drop(&mut self) {
// 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 @@ fn take(self, limit: u64) -> Take<Self> where Self: Sized {
}
}
/// 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 @@ fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
}
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 @@ fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
self.limit -= n as u64;
Ok(n)
}
unsafe fn initializer(&self) -> Initializer {
self.inner.initializer()
}
}
#[stable(feature = "rust1", since = "1.0.0")]

View file

@ -13,7 +13,7 @@
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 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
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()
}
}

View file

@ -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 @@
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(()) }
}

View file

@ -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 @@ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
#[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 @@ fn flush(&mut self) -> io::Result<()> { Ok(()) }
#[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")]

View file

@ -60,7 +60,7 @@
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()
}
}

View file

@ -14,7 +14,6 @@
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 {

View file

@ -285,10 +285,6 @@ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
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)
}

View file

@ -41,10 +41,6 @@ pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
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)
}

View file

@ -34,10 +34,6 @@ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
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)
}

View file

@ -25,13 +25,6 @@ pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
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 {

View file

@ -17,7 +17,7 @@
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 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
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 @@ 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()
}
}

View file

@ -17,7 +17,6 @@
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 {

View file

@ -491,10 +491,6 @@ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
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)
}

View file

@ -198,10 +198,6 @@ pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
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)
}

View file

@ -71,10 +71,6 @@ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
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)
}

View file

@ -25,13 +25,6 @@ pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
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 {

View file

@ -324,10 +324,6 @@ pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
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)
}

View file

@ -18,7 +18,6 @@
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) }
}
}

View file

@ -20,7 +20,6 @@
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 @@ pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
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 {

View file

@ -164,10 +164,6 @@ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
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)
}

View file

@ -20,7 +20,6 @@
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 {

View file

@ -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 fn tmpdir() -> TempDir {
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) }
});
}
}

View file

@ -243,10 +243,6 @@ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
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 {