提交 31bcec64 编写于 作者: S Steven Fackler

Add vectored read and write support

This functionality has lived for a while in the tokio ecosystem, where
it can improve performance by minimizing copies.
上级 4772dc80
......@@ -5,7 +5,7 @@
use cmp;
use error;
use fmt;
use io::{self, Initializer, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom};
use io::{self, Initializer, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom, IoVec, IoVecMut};
use memchr;
/// The `BufReader` struct adds buffering to any reader.
......@@ -235,6 +235,19 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
Ok(nread)
}
fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
let total_len = bufs.iter().map(|b| b.as_slice().len()).sum::<usize>();
if self.pos == self.cap && total_len >= self.buf.len() {
return self.inner.read_vectored(bufs);
}
let nread = {
let mut rem = self.fill_buf()?;
rem.read_vectored(bufs)?
};
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()
......@@ -577,9 +590,25 @@ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.panicked = false;
r
} else {
Write::write(&mut self.buf, buf)
self.buf.write(buf)
}
}
fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
let total_len = bufs.iter().map(|b| b.as_slice().len()).sum::<usize>();
if self.buf.len() + total_len > self.buf.capacity() {
self.flush_buf()?;
}
if total_len >= self.buf.capacity() {
self.panicked = true;
let r = self.inner.as_mut().unwrap().write_vectored(bufs);
self.panicked = false;
r
} else {
self.buf.write_vectored(bufs)
}
}
fn flush(&mut self) -> io::Result<()> {
self.flush_buf().and_then(|()| self.get_mut().flush())
}
......
......@@ -2,7 +2,7 @@
use core::convert::TryInto;
use cmp;
use io::{self, Initializer, SeekFrom, Error, ErrorKind};
use io::{self, Initializer, SeekFrom, Error, ErrorKind, IoVec, IoVecMut};
/// A `Cursor` wraps an in-memory buffer and provides it with a
/// [`Seek`] implementation.
......@@ -221,6 +221,19 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
Ok(n)
}
fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
let mut nread = 0;
for buf in bufs {
let buf = buf.as_mut_slice();
let n = self.read(buf)?;
nread += n;
if n < buf.len() {
break;
}
}
Ok(nread)
}
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
let n = buf.len();
Read::read_exact(&mut self.fill_buf()?, buf)?;
......@@ -251,6 +264,24 @@ fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result<us
Ok(amt)
}
fn slice_write_vectored(
pos_mut: &mut u64,
slice: &mut [u8],
bufs: &[IoVec<'_>],
) -> io::Result<usize>
{
let mut nwritten = 0;
for buf in bufs {
let buf = buf.as_slice();
let n = slice_write(pos_mut, slice, buf)?;
nwritten += n;
if n < buf.len() {
break;
}
}
Ok(nwritten)
}
// Resizing write implementation
fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usize> {
let pos: usize = (*pos_mut).try_into().map_err(|_| {
......@@ -278,12 +309,31 @@ fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usi
Ok(buf.len())
}
fn vec_write_vectored(
pos_mut: &mut u64,
vec: &mut Vec<u8>,
bufs: &[IoVec<'_>],
) -> io::Result<usize>
{
let mut nwritten = 0;
for buf in bufs {
nwritten += vec_write(pos_mut, vec, buf.as_slice())?;
}
Ok(nwritten)
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Write for Cursor<&'a mut [u8]> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
slice_write(&mut self.pos, self.inner, buf)
}
#[inline]
fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
slice_write_vectored(&mut self.pos, self.inner, bufs)
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
......@@ -292,6 +342,11 @@ impl<'a> Write for Cursor<&'a mut Vec<u8>> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
vec_write(&mut self.pos, self.inner, buf)
}
fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
vec_write_vectored(&mut self.pos, self.inner, bufs)
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
......@@ -300,6 +355,11 @@ impl Write for Cursor<Vec<u8>> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
vec_write(&mut self.pos, &mut self.inner, buf)
}
fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
vec_write_vectored(&mut self.pos, &mut self.inner, bufs)
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
......@@ -309,13 +369,19 @@ impl Write for Cursor<Box<[u8]>> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
slice_write(&mut self.pos, &mut self.inner, buf)
}
#[inline]
fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
slice_write_vectored(&mut self.pos, &mut self.inner, bufs)
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
#[cfg(test)]
mod tests {
use io::prelude::*;
use io::{Cursor, SeekFrom};
use io::{Cursor, SeekFrom, IoVec, IoVecMut};
#[test]
fn test_vec_writer() {
......@@ -323,7 +389,10 @@ fn test_vec_writer() {
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
assert_eq!(writer.write_vectored(
&[IoVec::new(&[]), IoVec::new(&[8, 9]), IoVec::new(&[10])],
).unwrap(), 3);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert_eq!(writer, b);
}
......@@ -333,7 +402,10 @@ fn test_mem_writer() {
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
assert_eq!(writer.write_vectored(
&[IoVec::new(&[]), IoVec::new(&[8, 9]), IoVec::new(&[10])],
).unwrap(), 3);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert_eq!(&writer.get_ref()[..], b);
}
......@@ -344,7 +416,10 @@ fn test_mem_mut_writer() {
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
assert_eq!(writer.write_vectored(
&[IoVec::new(&[]), IoVec::new(&[8, 9]), IoVec::new(&[10])],
).unwrap(), 3);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert_eq!(&writer.get_ref()[..], b);
}
......@@ -366,6 +441,26 @@ fn test_box_slice_writer() {
assert_eq!(&**writer.get_ref(), b);
}
#[test]
fn test_box_slice_writer_vectored() {
let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
assert_eq!(writer.position(), 0);
assert_eq!(writer.write_vectored(&[IoVec::new(&[0])]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(
writer.write_vectored(&[IoVec::new(&[1, 2, 3]), IoVec::new(&[4, 5, 6, 7])]).unwrap(),
7,
);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write_vectored(&[]).unwrap(), 0);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write_vectored(&[IoVec::new(&[8, 9])]).unwrap(), 1);
assert_eq!(writer.write_vectored(&[IoVec::new(&[10])]).unwrap(), 0);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(&**writer.get_ref(), b);
}
#[test]
fn test_buf_writer() {
let mut buf = [0 as u8; 9];
......@@ -387,6 +482,31 @@ fn test_buf_writer() {
assert_eq!(buf, b);
}
#[test]
fn test_buf_writer_vectored() {
let mut buf = [0 as u8; 9];
{
let mut writer = Cursor::new(&mut buf[..]);
assert_eq!(writer.position(), 0);
assert_eq!(writer.write_vectored(&[IoVec::new(&[0])]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(
writer.write_vectored(
&[IoVec::new(&[1, 2, 3]), IoVec::new(&[4, 5, 6, 7])],
).unwrap(),
7,
);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write_vectored(&[]).unwrap(), 0);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write_vectored(&[IoVec::new(&[8, 9])]).unwrap(), 1);
assert_eq!(writer.write_vectored(&[IoVec::new(&[10])]).unwrap(), 0);
}
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(buf, b);
}
#[test]
fn test_buf_writer_seek() {
let mut buf = [0 as u8; 8];
......@@ -447,6 +567,35 @@ fn test_mem_reader() {
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_mem_reader_vectored() {
let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]);
let mut buf = [];
assert_eq!(reader.read_vectored(&mut [IoVecMut::new(&mut buf)]).unwrap(), 0);
assert_eq!(reader.position(), 0);
let mut buf = [0];
assert_eq!(
reader.read_vectored(&mut [IoVecMut::new(&mut []), IoVecMut::new(&mut buf)]).unwrap(),
1,
);
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf1 = [0; 4];
let mut buf2 = [0; 4];
assert_eq!(
reader.read_vectored(
&mut [IoVecMut::new(&mut buf1), IoVecMut::new(&mut buf2)],
).unwrap(),
7,
);
let b1: &[_] = &[1, 2, 3, 4];
let b2: &[_] = &[5, 6, 7];
assert_eq!(buf1, b1);
assert_eq!(&buf2[..3], b2);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_boxed_slice_reader() {
let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice());
......@@ -469,6 +618,35 @@ fn test_boxed_slice_reader() {
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_boxed_slice_reader_vectored() {
let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice());
let mut buf = [];
assert_eq!(reader.read_vectored(&mut [IoVecMut::new(&mut buf)]).unwrap(), 0);
assert_eq!(reader.position(), 0);
let mut buf = [0];
assert_eq!(
reader.read_vectored(&mut [IoVecMut::new(&mut []), IoVecMut::new(&mut buf)]).unwrap(),
1,
);
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf1 = [0; 4];
let mut buf2 = [0; 4];
assert_eq!(
reader.read_vectored(
&mut [IoVecMut::new(&mut buf1), IoVecMut::new(&mut buf2)],
).unwrap(),
7,
);
let b1: &[_] = &[1, 2, 3, 4];
let b2: &[_] = &[5, 6, 7];
assert_eq!(buf1, b1);
assert_eq!(&buf2[..3], b2);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn read_to_end() {
let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]);
......@@ -499,6 +677,35 @@ fn test_slice_reader() {
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_slice_reader_vectored() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
let reader = &mut &in_buf[..];
let mut buf = [];
assert_eq!(reader.read_vectored(&mut [IoVecMut::new(&mut buf)]).unwrap(), 0);
let mut buf = [0];
assert_eq!(
reader.read_vectored(&mut [IoVecMut::new(&mut []), IoVecMut::new(&mut buf)]).unwrap(),
1,
);
assert_eq!(reader.len(), 7);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf1 = [0; 4];
let mut buf2 = [0; 4];
assert_eq!(
reader.read_vectored(
&mut [IoVecMut::new(&mut buf1), IoVecMut::new(&mut buf2)],
).unwrap(),
7,
);
let b1: &[_] = &[1, 2, 3, 4];
let b2: &[_] = &[5, 6, 7];
assert_eq!(buf1, b1);
assert_eq!(&buf2[..3], b2);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_read_exact() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
......
use cmp;
use io::{self, SeekFrom, Read, Initializer, Write, Seek, BufRead, Error, ErrorKind};
use io::{self, SeekFrom, Read, Initializer, Write, Seek, BufRead, Error, ErrorKind, IoVecMut,
IoVec};
use fmt;
use mem;
......@@ -13,6 +14,11 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
(**self).read(buf)
}
#[inline]
fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
(**self).read_vectored(bufs)
}
#[inline]
unsafe fn initializer(&self) -> Initializer {
(**self).initializer()
......@@ -38,6 +44,11 @@ impl<'a, W: Write + ?Sized> Write for &'a mut W {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { (**self).write(buf) }
#[inline]
fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
(**self).write_vectored(bufs)
}
#[inline]
fn flush(&mut self) -> io::Result<()> { (**self).flush() }
......@@ -82,6 +93,11 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
(**self).read(buf)
}
#[inline]
fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
(**self).read_vectored(bufs)
}
#[inline]
unsafe fn initializer(&self) -> Initializer {
(**self).initializer()
......@@ -107,6 +123,11 @@ impl<W: Write + ?Sized> Write for Box<W> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { (**self).write(buf) }
#[inline]
fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
(**self).write_vectored(bufs)
}
#[inline]
fn flush(&mut self) -> io::Result<()> { (**self).flush() }
......@@ -171,6 +192,19 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
Ok(amt)
}
#[inline]
fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
let mut nread = 0;
for buf in bufs {
nread += self.read(buf.as_mut_slice())?;
if self.is_empty() {
break;
}
}
Ok(nread)
}
#[inline]
unsafe fn initializer(&self) -> Initializer {
Initializer::nop()
......@@ -231,6 +265,19 @@ fn write(&mut self, data: &[u8]) -> io::Result<usize> {
Ok(amt)
}
#[inline]
fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
let mut nwritten = 0;
for buf in bufs {
nwritten += self.write(buf.as_slice())?;
if self.is_empty() {
break;
}
}
Ok(nwritten)
}
#[inline]
fn write_all(&mut self, data: &[u8]) -> io::Result<()> {
if self.write(data)? == data.len() {
......@@ -254,6 +301,16 @@ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
Ok(buf.len())
}
#[inline]
fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
let len = bufs.iter().map(|b| b.as_slice().len()).sum();
self.reserve(len);
for buf in bufs {
self.extend_from_slice(buf.as_slice());
}
Ok(len)
}
#[inline]
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
self.extend_from_slice(buf);
......
......@@ -265,6 +265,7 @@
use str;
use memchr;
use ptr;
use sys;
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::buffered::{BufReader, BufWriter, LineWriter};
......@@ -520,6 +521,22 @@ pub trait Read {
#[stable(feature = "rust1", since = "1.0.0")]
fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
/// Like `read`, except that it reads into a slice of buffers.
///
/// Data is copied to fill each buffer in order, with the final buffer
/// written to possibly being only partially filled. This method must behave
/// as a single call to `read` with the buffers concatenated would.
///
/// The default implementation simply passes the first nonempty buffer to
/// `read`.
#[unstable(feature = "iovec", issue = "0")]
fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> Result<usize> {
match bufs.iter_mut().map(|b| b.as_mut_slice()).find(|b| !b.is_empty()) {
Some(buf) => self.read(buf),
None => Ok(0),
}
}
/// Determines if this `Read`er can work with buffers of uninitialized
/// memory.
///
......@@ -867,6 +884,85 @@ fn take(self, limit: u64) -> Take<Self> where Self: Sized {
}
}
/// A buffer type used with `Read::read_vectored`.
///
/// It is semantically a wrapper around an `&mut [u8]`, but is guaranteed to be
/// ABI compatible with the `iovec` type on Unix platforms and `WSABUF` on
/// Windows.
#[unstable(feature = "iovec", issue = "0")]
#[repr(transparent)]
pub struct IoVecMut<'a>(sys::io::IoVecMut<'a>);
#[unstable(feature = "iovec", issue = "0")]
impl<'a> fmt::Debug for IoVecMut<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self.as_slice(), fmt)
}
}
impl<'a> IoVecMut<'a> {
/// Creates a new `IoVecMut` wrapping a byte slice.
///
/// # Panics
///
/// Panics on Windows if the slice is larger than 4GB.
#[unstable(feature = "iovec", issue = "0")]
#[inline]
pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> {
IoVecMut(sys::io::IoVecMut::new(buf))
}
/// Returns a shared reference to the inner slice.
#[unstable(feature = "iovec", issue = "0")]
#[inline]
pub fn as_slice(&self) -> &'a [u8] {
self.0.as_slice()
}
/// Returns a mutable reference to the inner slice.
#[unstable(feature = "iovec", issue = "0")]
#[inline]
pub fn as_mut_slice(&mut self) -> &'a mut [u8] {
self.0.as_mut_slice()
}
}
/// A buffer type used with `Write::write_vectored`.
///
/// It is semantically a wrapper around an `&[u8]`, but is guaranteed to be
/// ABI compatible with the `iovec` type on Unix platforms and `WSABUF` on
/// Windows.
#[unstable(feature = "iovec", issue = "0")]
#[repr(transparent)]
pub struct IoVec<'a>(sys::io::IoVec<'a>);
#[unstable(feature = "iovec", issue = "0")]
impl<'a> fmt::Debug for IoVec<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self.as_slice(), fmt)
}
}
impl<'a> IoVec<'a> {
/// Creates a new `IoVec` wrapping a byte slice.
///
/// # Panics
///
/// Panics on Windows if the slice is larger than 4GB.
#[unstable(feature = "iovec", issue = "0")]
#[inline]
pub fn new(buf: &'a [u8]) -> IoVec<'a> {
IoVec(sys::io::IoVec::new(buf))
}
/// Returns a shared reference to the inner slice.
#[unstable(feature = "iovec", issue = "0")]
#[inline]
pub fn as_slice(&self) -> &'a [u8] {
self.0.as_slice()
}
}
/// A type used to conditionally initialize buffers passed to `Read` methods.
#[unstable(feature = "read_initializer", issue = "42788")]
#[derive(Debug)]
......@@ -997,6 +1093,22 @@ pub trait Write {
#[stable(feature = "rust1", since = "1.0.0")]
fn write(&mut self, buf: &[u8]) -> Result<usize>;
/// Like `write`, except that it writes from a slice of buffers.
///
/// Data is copied to from each buffer in order, with the final buffer
/// read from possibly being only partially consumed. This method must
/// behave as a call to `write` with the buffers concatenated would.
///
/// The default implementation simply passes the first nonempty buffer to
/// `write`.
#[unstable(feature = "iovec", issue = "0")]
fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> Result<usize> {
match bufs.iter().map(|b| b.as_slice()).find(|b| !b.is_empty()) {
Some(buf) => self.write(buf),
None => Ok(0),
}
}
/// Flush this output stream, ensuring that all intermediately buffered
/// contents reach their destination.
///
......@@ -1691,13 +1803,23 @@ impl<T: Read, U: Read> Read for Chain<T, U> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
if !self.done_first {
match self.first.read(buf)? {
0 if buf.len() != 0 => { self.done_first = true; }
0 if buf.len() != 0 => self.done_first = true,
n => return Ok(n),
}
}
self.second.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> Result<usize> {
if !self.done_first {
match self.first.read_vectored(bufs)? {
0 if bufs.iter().any(|b| !b.as_slice().is_empty()) => self.done_first = true,
n => return Ok(n),
}
}
self.second.read_vectored(bufs)
}
unsafe fn initializer(&self) -> Initializer {
let initializer = self.first.initializer();
if initializer.should_initialize() {
......
#![allow(missing_copy_implementations)]
use fmt;
use io::{self, Read, Initializer, Write, ErrorKind, BufRead};
use io::{self, Read, Initializer, Write, ErrorKind, BufRead, IoVec, IoVecMut};
use mem;
/// Copies the entire contents of a reader into a writer.
......@@ -152,6 +152,15 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
Ok(buf.len())
}
#[inline]
fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
let mut nwritten = 0;
for buf in bufs {
nwritten += self.read(buf.as_mut_slice())?;
}
Ok(nwritten)
}
#[inline]
unsafe fn initializer(&self) -> Initializer {
Initializer::nop()
......@@ -195,6 +204,13 @@ pub fn sink() -> Sink { Sink { _priv: () } }
impl Write for Sink {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { Ok(buf.len()) }
#[inline]
fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
let total_len = bufs.iter().map(|b| b.as_slice().len()).sum();
Ok(total_len)
}
#[inline]
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
......
......@@ -228,6 +228,7 @@
#![feature(arbitrary_self_types)]
#![feature(array_error_internals)]
#![feature(asm)]
#![feature(bind_by_move_pattern_guards)]
#![feature(box_syntax)]
#![feature(c_variadic)]
#![feature(cfg_target_has_atomic)]
......
use io::prelude::*;
use fmt;
use io::{self, Initializer};
use io::{self, Initializer, IoVec, IoVecMut};
use net::{ToSocketAddrs, SocketAddr, Shutdown};
use sys_common::net as net_imp;
use sys_common::{AsInner, FromInner, IntoInner};
......@@ -569,6 +569,10 @@ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
impl Read for TcpStream {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
self.0.read_vectored(bufs)
}
#[inline]
unsafe fn initializer(&self) -> Initializer {
Initializer::nop()
......@@ -577,12 +581,21 @@ unsafe fn initializer(&self) -> Initializer {
#[stable(feature = "rust1", since = "1.0.0")]
impl Write for TcpStream {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) }
fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
self.0.write_vectored(bufs)
}
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_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
self.0.read_vectored(bufs)
}
#[inline]
unsafe fn initializer(&self) -> Initializer {
Initializer::nop()
......@@ -591,6 +604,11 @@ unsafe fn initializer(&self) -> Initializer {
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Write for &'a TcpStream {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) }
fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
self.0.write_vectored(bufs)
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
......@@ -911,7 +929,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))]
mod tests {
use io::ErrorKind;
use io::{ErrorKind, IoVec, IoVecMut};
use io::prelude::*;
use net::*;
use net::test::{next_test_ip4, next_test_ip6};
......@@ -1184,6 +1202,53 @@ fn partial_read() {
})
}
#[test]
fn read_vectored() {
each_ip(&mut |addr| {
let srv = t!(TcpListener::bind(&addr));
let mut s1 = t!(TcpStream::connect(&addr));
let mut s2 = t!(srv.accept()).0;
let len = s1.write(&[10, 11, 12]).unwrap();
assert_eq!(len, 3);
let mut a = [];
let mut b = [0];
let mut c = [0; 3];
let len = t!(s2.read_vectored(
&mut [IoVecMut::new(&mut a), IoVecMut::new(&mut b), IoVecMut::new(&mut c)],
));
assert!(len > 0);
assert_eq!(b, [10]);
// some implementations don't support readv, so we may only fill the first buffer
assert!(len == 1 || c == [11, 12, 0]);
})
}
#[test]
fn write_vectored() {
each_ip(&mut |addr| {
let srv = t!(TcpListener::bind(&addr));
let mut s1 = t!(TcpStream::connect(&addr));
let mut s2 = t!(srv.accept()).0;
let a = [];
let b = [10];
let c = [11, 12];
t!(s1.write_vectored(&[IoVec::new(&a), IoVec::new(&b), IoVec::new(&c)]));
let mut buf = [0; 4];
let len = t!(s2.read(&mut buf));
// some implementations don't support writev, so we may only write the first buffer
if len == 1 {
assert_eq!(buf, [10, 0, 0, 0]);
} else {
assert_eq!(len, 3);
assert_eq!(buf, [10, 11, 12, 0]);
}
})
}
#[test]
fn double_bind() {
each_ip(&mut |addr| {
......
pub struct IoVec<'a>(&'a [u8]);
impl<'a> IoVec<'a> {
#[inline]
pub fn new(buf: &'a [u8]) -> IoVec<'a> {
IoVec(buf)
}
#[inline]
pub fn as_slice(&self) -> &'a [u8] {
self.0
}
}
pub struct IoVecMut<'a>(&'a mut [u8]);
impl<'a> IoVecMut<'a> {
#[inline]
pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> {
IoVecMut(buf)
}
#[inline]
pub fn as_slice(&self) -> &'a [u8] {
self.0
}
#[inline]
pub fn as_mut_slice(&mut self) -> &'a mut [u8] {
self.0
}
}
use io;
use libc;
use mem;
......@@ -10,6 +9,7 @@
#[path = "../unix/cmath.rs"]
pub mod cmath;
pub mod condvar;
pub mod io;
#[path = "../unix/memchr.rs"]
pub mod memchr;
pub mod mutex;
......@@ -32,24 +32,24 @@
#[allow(dead_code)]
pub fn init() {}
pub fn decode_error_kind(errno: i32) -> io::ErrorKind {
pub fn decode_error_kind(errno: i32) -> ::io::ErrorKind {
match errno {
x if x == abi::errno::ACCES as i32 => io::ErrorKind::PermissionDenied,
x if x == abi::errno::ADDRINUSE as i32 => io::ErrorKind::AddrInUse,
x if x == abi::errno::ADDRNOTAVAIL as i32 => io::ErrorKind::AddrNotAvailable,
x if x == abi::errno::AGAIN as i32 => io::ErrorKind::WouldBlock,
x if x == abi::errno::CONNABORTED as i32 => io::ErrorKind::ConnectionAborted,
x if x == abi::errno::CONNREFUSED as i32 => io::ErrorKind::ConnectionRefused,
x if x == abi::errno::CONNRESET as i32 => io::ErrorKind::ConnectionReset,
x if x == abi::errno::EXIST as i32 => io::ErrorKind::AlreadyExists,
x if x == abi::errno::INTR as i32 => io::ErrorKind::Interrupted,
x if x == abi::errno::INVAL as i32 => io::ErrorKind::InvalidInput,
x if x == abi::errno::NOENT as i32 => io::ErrorKind::NotFound,
x if x == abi::errno::NOTCONN as i32 => io::ErrorKind::NotConnected,
x if x == abi::errno::PERM as i32 => io::ErrorKind::PermissionDenied,
x if x == abi::errno::PIPE as i32 => io::ErrorKind::BrokenPipe,
x if x == abi::errno::TIMEDOUT as i32 => io::ErrorKind::TimedOut,
_ => io::ErrorKind::Other,
x if x == abi::errno::ACCES as i32 => ::io::ErrorKind::PermissionDenied,
x if x == abi::errno::ADDRINUSE as i32 => ::io::ErrorKind::AddrInUse,
x if x == abi::errno::ADDRNOTAVAIL as i32 => ::io::ErrorKind::AddrNotAvailable,
x if x == abi::errno::AGAIN as i32 => ::io::ErrorKind::WouldBlock,
x if x == abi::errno::CONNABORTED as i32 => ::io::ErrorKind::ConnectionAborted,
x if x == abi::errno::CONNREFUSED as i32 => ::io::ErrorKind::ConnectionRefused,
x if x == abi::errno::CONNRESET as i32 => ::io::ErrorKind::ConnectionReset,
x if x == abi::errno::EXIST as i32 => ::io::ErrorKind::AlreadyExists,
x if x == abi::errno::INTR as i32 => ::io::ErrorKind::Interrupted,
x if x == abi::errno::INVAL as i32 => ::io::ErrorKind::InvalidInput,
x if x == abi::errno::NOENT as i32 => ::io::ErrorKind::NotFound,
x if x == abi::errno::NOTCONN as i32 => ::io::ErrorKind::NotConnected,
x if x == abi::errno::PERM as i32 => ::io::ErrorKind::PermissionDenied,
x if x == abi::errno::PIPE as i32 => ::io::ErrorKind::BrokenPipe,
x if x == abi::errno::TIMEDOUT as i32 => ::io::ErrorKind::TimedOut,
_ => ::io::ErrorKind::Other,
}
}
......
pub struct IoVec<'a>(&'a [u8]);
impl<'a> IoVec<'a> {
#[inline]
pub fn new(buf: &'a [u8]) -> IoVec<'a> {
IoVec(buf)
}
#[inline]
pub fn as_slice(&self) -> &'a [u8] {
self.0
}
}
pub struct IoVecMut<'a>(&'a mut [u8]);
impl<'a> IoVecMut<'a> {
#[inline]
pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> {
IoVecMut(buf)
}
#[inline]
pub fn as_slice(&self) -> &'a [u8] {
self.0
}
#[inline]
pub fn as_mut_slice(&mut self) -> &'a mut [u8] {
self.0
}
}
#![allow(dead_code, missing_docs, nonstandard_style)]
use io::{self, ErrorKind};
use ::io::{ErrorKind};
pub use libc::strlen;
pub use self::rand::hashmap_random_keys;
......@@ -17,6 +17,7 @@
pub mod fast_thread_local;
pub mod fd;
pub mod fs;
pub mod io;
pub mod memchr;
pub mod mutex;
pub mod net;
......@@ -63,8 +64,8 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
}
}
pub fn cvt(result: Result<usize, syscall::Error>) -> io::Result<usize> {
result.map_err(|err| io::Error::from_raw_os_error(err.errno))
pub fn cvt(result: Result<usize, syscall::Error>) -> ::io::Result<usize> {
result.map_err(|err| ::io::Error::from_raw_os_error(err.errno))
}
#[doc(hidden)]
......@@ -82,9 +83,9 @@ fn is_minus_one(&self) -> bool {
impl_is_minus_one! { i8 i16 i32 i64 isize }
pub fn cvt_libc<T: IsMinusOne>(t: T) -> io::Result<T> {
pub fn cvt_libc<T: IsMinusOne>(t: T) -> ::io::Result<T> {
if t.is_minus_one() {
Err(io::Error::last_os_error())
Err(::io::Error::last_os_error())
} else {
Ok(t)
}
......
use cmp;
use io::{self, Error, ErrorKind, Result};
use io::{self, Error, ErrorKind, Result, IoVec, IoVecMut};
use mem;
use net::{SocketAddr, Shutdown};
use path::Path;
......@@ -34,10 +34,24 @@ pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
self.0.read(buf)
}
pub fn read_vectored(&self, buf: &mut [IoVecMut<'_>]) -> io::Result<usize> {
match buf.iter_mut().map(|b| b.as_mut_slice()).find(|b| !b.is_empty()) {
Some(buf) => self.read(buf),
None => Ok(0),
}
}
pub fn write(&self, buf: &[u8]) -> Result<usize> {
self.0.write(buf)
}
pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
match buf.iter().map(|b| b.as_slice()).find(|b| !b.is_empty()) {
Some(buf) => self.write(buf),
None => Ok(0),
}
}
pub fn take_error(&self) -> Result<Option<Error>> {
Ok(None)
}
......
pub struct IoVec<'a>(&'a [u8]);
impl<'a> IoVec<'a> {
#[inline]
pub fn new(buf: &'a [u8]) -> IoVec<'a> {
IoVec(buf)
}
#[inline]
pub fn as_slice(&self) -> &'a [u8] {
self.0
}
}
pub struct IoVecMut<'a>(&'a mut [u8]);
impl<'a> IoVecMut<'a> {
#[inline]
pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> {
IoVecMut(buf)
}
#[inline]
pub fn as_slice(&self) -> &'a [u8] {
self.0
}
#[inline]
pub fn as_mut_slice(&mut self) -> &'a mut [u8] {
self.0
}
}
......@@ -3,7 +3,6 @@
//! This module contains the facade (aka platform-specific) implementations of
//! OS level functionality for Fortanix SGX.
use io;
use os::raw::c_char;
use sync::atomic::{AtomicBool, Ordering};
......@@ -20,6 +19,7 @@
pub mod ext;
pub mod fd;
pub mod fs;
pub mod io;
pub mod memchr;
pub mod mutex;
pub mod net;
......@@ -41,12 +41,12 @@ pub fn init() {
/// This function is used to implement functionality that simply doesn't exist.
/// Programs relying on this functionality will need to deal with the error.
pub fn unsupported<T>() -> io::Result<T> {
pub fn unsupported<T>() -> ::io::Result<T> {
Err(unsupported_err())
}
pub fn unsupported_err() -> io::Error {
io::Error::new(io::ErrorKind::Other,
pub fn unsupported_err() -> ::io::Error {
::io::Error::new(::io::ErrorKind::Other,
"operation not supported on SGX yet")
}
......@@ -55,58 +55,58 @@ pub fn unsupported_err() -> io::Error {
/// returned, the program might very well be able to function normally. This is
/// what happens when `SGX_INEFFECTIVE_ERROR` is set to `true`. If it is
/// `false`, the behavior is the same as `unsupported`.
pub fn sgx_ineffective<T>(v: T) -> io::Result<T> {
pub fn sgx_ineffective<T>(v: T) -> ::io::Result<T> {
static SGX_INEFFECTIVE_ERROR: AtomicBool = AtomicBool::new(false);
if SGX_INEFFECTIVE_ERROR.load(Ordering::Relaxed) {
Err(io::Error::new(io::ErrorKind::Other,
Err(::io::Error::new(::io::ErrorKind::Other,
"operation can't be trusted to have any effect on SGX"))
} else {
Ok(v)
}
}
pub fn decode_error_kind(code: i32) -> io::ErrorKind {
pub fn decode_error_kind(code: i32) -> ::io::ErrorKind {
use fortanix_sgx_abi::Error;
// FIXME: not sure how to make sure all variants of Error are covered
if code == Error::NotFound as _ {
io::ErrorKind::NotFound
::io::ErrorKind::NotFound
} else if code == Error::PermissionDenied as _ {
io::ErrorKind::PermissionDenied
::io::ErrorKind::PermissionDenied
} else if code == Error::ConnectionRefused as _ {
io::ErrorKind::ConnectionRefused
::io::ErrorKind::ConnectionRefused
} else if code == Error::ConnectionReset as _ {
io::ErrorKind::ConnectionReset
::io::ErrorKind::ConnectionReset
} else if code == Error::ConnectionAborted as _ {
io::ErrorKind::ConnectionAborted
::io::ErrorKind::ConnectionAborted
} else if code == Error::NotConnected as _ {
io::ErrorKind::NotConnected
::io::ErrorKind::NotConnected
} else if code == Error::AddrInUse as _ {
io::ErrorKind::AddrInUse
::io::ErrorKind::AddrInUse
} else if code == Error::AddrNotAvailable as _ {
io::ErrorKind::AddrNotAvailable
::io::ErrorKind::AddrNotAvailable
} else if code == Error::BrokenPipe as _ {
io::ErrorKind::BrokenPipe
::io::ErrorKind::BrokenPipe
} else if code == Error::AlreadyExists as _ {
io::ErrorKind::AlreadyExists
::io::ErrorKind::AlreadyExists
} else if code == Error::WouldBlock as _ {
io::ErrorKind::WouldBlock
::io::ErrorKind::WouldBlock
} else if code == Error::InvalidInput as _ {
io::ErrorKind::InvalidInput
::io::ErrorKind::InvalidInput
} else if code == Error::InvalidData as _ {
io::ErrorKind::InvalidData
::io::ErrorKind::InvalidData
} else if code == Error::TimedOut as _ {
io::ErrorKind::TimedOut
::io::ErrorKind::TimedOut
} else if code == Error::WriteZero as _ {
io::ErrorKind::WriteZero
::io::ErrorKind::WriteZero
} else if code == Error::Interrupted as _ {
io::ErrorKind::Interrupted
::io::ErrorKind::Interrupted
} else if code == Error::Other as _ {
io::ErrorKind::Other
::io::ErrorKind::Other
} else if code == Error::UnexpectedEof as _ {
io::ErrorKind::UnexpectedEof
::io::ErrorKind::UnexpectedEof
} else {
io::ErrorKind::Other
::io::ErrorKind::Other
}
}
......
......@@ -103,10 +103,26 @@ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.inner.read(buf)
}
pub fn read_vectored(&self, buf: &mut [IoVecMut<'_>]) -> io::Result<usize> {
let buf = match buf.get(0) {
Some(buf) => buf.as_mut_slice(),
None => return Ok(0),
};
self.read(buf)
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.inner.inner.write(buf)
}
pub fn write_vectored(&self, buf: &[IoVec<'_>]) -> io::Result<usize> {
let buf = match buf.get(0) {
Some(buf) => buf.as_slice(),
None => return Ok(0),
};
self.read(buf)
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
addr_to_sockaddr(&self.peer_addr)
}
......
......@@ -18,7 +18,7 @@ mod libc {
use ascii;
use ffi::OsStr;
use fmt;
use io::{self, Initializer};
use io::{self, Initializer, IoVec, IoVecMut};
use mem;
use net::{self, Shutdown};
use os::unix::ffi::OsStrExt;
......@@ -551,6 +551,10 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
io::Read::read(&mut &*self, buf)
}
fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
io::Read::read_vectored(&mut &*self, bufs)
}
#[inline]
unsafe fn initializer(&self) -> Initializer {
Initializer::nop()
......@@ -563,6 +567,10 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
self.0.read_vectored(bufs)
}
#[inline]
unsafe fn initializer(&self) -> Initializer {
Initializer::nop()
......@@ -575,6 +583,10 @@ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
io::Write::write(&mut &*self, buf)
}
fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
io::Write::write_vectored(&mut &*self, bufs)
}
fn flush(&mut self) -> io::Result<()> {
io::Write::flush(&mut &*self)
}
......@@ -586,6 +598,10 @@ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
self.0.write_vectored(bufs)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
......@@ -1510,6 +1526,25 @@ fn basic() {
thread.join().unwrap();
}
#[test]
fn vectored() {
let (mut s1, mut s2) = or_panic!(UnixStream::pair());
let len = or_panic!(s1.write_vectored(
&[IoVec::new(b"hello"), IoVec::new(b" "), IoVec::new(b"world!")],
));
assert_eq!(len, 12);
let mut buf1 = [0; 6];
let mut buf2 = [0; 7];
let len = or_panic!(s2.read_vectored(
&mut [IoVecMut::new(&mut buf1), IoVecMut::new(&mut buf2)],
));
assert_eq!(len, 12);
assert_eq!(&buf1, b"hello ");
assert_eq!(&buf2, b"world!\0");
}
#[test]
fn pair() {
let msg1 = b"hello";
......
#![unstable(reason = "not public", issue = "0", feature = "fd")]
use cmp;
use io::{self, Read, Initializer};
use io::{self, Read, Initializer, IoVec, IoVecMut};
use libc::{self, c_int, c_void, ssize_t};
use mem;
use sync::atomic::{AtomicBool, Ordering};
......@@ -52,6 +52,15 @@ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
Ok(ret as usize)
}
pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
let ret = cvt(unsafe {
libc::readv(self.fd,
bufs.as_ptr() as *const libc::iovec,
cmp::min(bufs.len(), c_int::max_value() as usize) as c_int)
})?;
Ok(ret as usize)
}
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
let mut me = self;
(&mut me).read_to_end(buf)
......@@ -105,6 +114,15 @@ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
Ok(ret as usize)
}
pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
let ret = cvt(unsafe {
libc::writev(self.fd,
bufs.as_ptr() as *const libc::iovec,
cmp::min(bufs.len(), c_int::max_value() as usize) as c_int)
})?;
Ok(ret as usize)
}
pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
#[cfg(target_os = "android")]
use super::android::cvt_pwrite64;
......
use marker::PhantomData;
use libc::{iovec, c_void};
use slice;
#[repr(transparent)]
pub struct IoVec<'a> {
vec: iovec,
_p: PhantomData<&'a [u8]>,
}
impl<'a> IoVec<'a> {
#[inline]
pub fn new(buf: &'a [u8]) -> IoVec<'a> {
IoVec {
vec: iovec {
iov_base: buf.as_ptr() as *mut u8 as *mut c_void,
iov_len: buf.len()
},
_p: PhantomData,
}
}
#[inline]
pub fn as_slice(&self) -> &'a [u8] {
unsafe {
slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len)
}
}
}
pub struct IoVecMut<'a> {
vec: iovec,
_p: PhantomData<&'a mut [u8]>,
}
impl<'a> IoVecMut<'a> {
#[inline]
pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> {
IoVecMut {
vec: iovec {
iov_base: buf.as_mut_ptr() as *mut c_void,
iov_len: buf.len()
},
_p: PhantomData,
}
}
#[inline]
pub fn as_slice(&self) -> &'a [u8] {
unsafe {
slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len)
}
}
#[inline]
pub fn as_mut_slice(&mut self) -> &'a mut [u8] {
unsafe {
slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len)
}
}
}
......@@ -5,7 +5,7 @@
pub mod net {
#![allow(warnings)]
use fmt;
use io;
use io::{self, IoVec, IoVecMut};
use libc;
use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr};
use sys_common::{AsInner, FromInner, IntoInner};
......@@ -46,6 +46,10 @@ pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
unimpl!();
}
pub fn read_vectored(&self, _: &mut [IoVecMut<'_>]) -> io::Result<usize> {
unimpl!();
}
pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
unimpl!();
}
......@@ -62,6 +66,10 @@ pub fn write(&self, _: &[u8]) -> io::Result<usize> {
unimpl!();
}
pub fn write_vectored(&self, _: &[IoVec<'_>]) -> io::Result<usize> {
unimpl!();
}
pub fn set_timeout(&self, _: Option<Duration>, _: libc::c_int) -> io::Result<()> {
unimpl!();
}
......@@ -144,10 +152,18 @@ pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
unimpl!();
}
pub fn read_vectored(&self, _: &mut [IoVecMut<'_>]) -> io::Result<usize> {
unimpl!();
}
pub fn write(&self, _: &[u8]) -> io::Result<usize> {
unimpl!();
}
pub fn write_vectored(&self, _: &[IoVec<'_>]) -> io::Result<usize> {
unimpl!();
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
unimpl!();
}
......
#![allow(missing_docs, nonstandard_style)]
use io::{self, ErrorKind};
use io::ErrorKind;
use libc;
#[cfg(any(rustdoc, target_os = "linux"))] pub use os::linux as platform;
......@@ -39,6 +39,7 @@
pub mod fd;
pub mod fs;
pub mod memchr;
pub mod io;
pub mod mutex;
#[cfg(not(target_os = "l4re"))]
pub mod net;
......@@ -126,15 +127,15 @@ fn is_minus_one(&self) -> bool {
impl_is_minus_one! { i8 i16 i32 i64 isize }
pub fn cvt<T: IsMinusOne>(t: T) -> io::Result<T> {
pub fn cvt<T: IsMinusOne>(t: T) -> ::io::Result<T> {
if t.is_minus_one() {
Err(io::Error::last_os_error())
Err(::io::Error::last_os_error())
} else {
Ok(t)
}
}
pub fn cvt_r<T, F>(mut f: F) -> io::Result<T>
pub fn cvt_r<T, F>(mut f: F) -> ::io::Result<T>
where T: IsMinusOne,
F: FnMut() -> T
{
......
use ffi::CStr;
use io;
use io::{self, IoVec, IoVecMut};
use libc::{self, c_int, c_void, size_t, sockaddr, socklen_t, EAI_SYSTEM, MSG_PEEK};
use mem;
use net::{SocketAddr, Shutdown};
......@@ -241,6 +241,10 @@ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
self.recv_with_flags(buf, MSG_PEEK)
}
pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
self.0.read_vectored(bufs)
}
fn recv_from_with_flags(&self, buf: &mut [u8], flags: c_int)
-> io::Result<(usize, SocketAddr)> {
let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
......@@ -269,6 +273,10 @@ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
self.0.write_vectored(bufs)
}
pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> {
let timeout = match dur {
Some(dur) => {
......
pub struct IoVec<'a>(&'a [u8]);
impl<'a> IoVec<'a> {
#[inline]
pub fn new(buf: &'a [u8]) -> IoVec<'a> {
IoVec(buf)
}
#[inline]
pub fn as_slice(&self) -> &'a [u8] {
self.0
}
}
pub struct IoVecMut<'a>(&'a mut [u8]);
impl<'a> IoVecMut<'a> {
#[inline]
pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> {
IoVecMut(buf)
}
#[inline]
pub fn as_slice(&self) -> &'a [u8] {
self.0
}
#[inline]
pub fn as_mut_slice(&mut self) -> &'a mut [u8] {
self.0
}
}
......@@ -14,7 +14,6 @@
//! compiling for wasm. That way it's a compile time error for something that's
//! guaranteed to be a runtime error!
use io;
use os::raw::c_char;
use ptr;
use sys::os_str::Buf;
......@@ -29,6 +28,7 @@
pub mod cmath;
pub mod env;
pub mod fs;
pub mod io;
pub mod memchr;
pub mod net;
pub mod os;
......@@ -63,17 +63,17 @@
pub fn init() {
}
pub fn unsupported<T>() -> io::Result<T> {
pub fn unsupported<T>() -> ::io::Result<T> {
Err(unsupported_err())
}
pub fn unsupported_err() -> io::Error {
io::Error::new(io::ErrorKind::Other,
pub fn unsupported_err() -> ::io::Error {
::io::Error::new(::io::ErrorKind::Other,
"operation not supported on wasm yet")
}
pub fn decode_error_kind(_code: i32) -> io::ErrorKind {
io::ErrorKind::Other
pub fn decode_error_kind(_code: i32) -> ::io::ErrorKind {
::io::ErrorKind::Other
}
// This enum is used as the storage for a bunch of types which can't actually
......
use fmt;
use io;
use io::{self, IoVec, IoVecMut};
use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr};
use time::Duration;
use sys::{unsupported, Void};
......@@ -40,10 +40,18 @@ pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
match self.0 {}
}
pub fn read_vectored(&self, _: &mut [IoVecMut<'_>]) -> io::Result<usize> {
match self.0 {}
}
pub fn write(&self, _: &[u8]) -> io::Result<usize> {
match self.0 {}
}
pub fn write_vectored(&self, _: &[IoVec<'_>]) -> io::Result<usize> {
match self.0 {}
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
match self.0 {}
}
......
......@@ -57,6 +57,9 @@
pub type LPSTR = *mut CHAR;
pub type LPWSTR = *mut WCHAR;
pub type LPFILETIME = *mut FILETIME;
pub type LPWSABUF = *mut WSABUF;
pub type LPWSAOVERLAPPED = *mut c_void;
pub type LPWSAOVERLAPPED_COMPLETION_ROUTINE = *mut c_void;
pub type PCONDITION_VARIABLE = *mut CONDITION_VARIABLE;
pub type PLARGE_INTEGER = *mut c_longlong;
......@@ -324,6 +327,12 @@ pub struct WSADATA {
pub szSystemStatus: [u8; WSASYS_STATUS_LEN + 1],
}
#[repr(C)]
pub struct WSABUF {
pub len: ULONG,
pub buf: *mut CHAR,
}
#[repr(C)]
pub struct WSAPROTOCOL_INFO {
pub dwServiceFlags1: DWORD,
......@@ -988,6 +997,22 @@ pub fn WSADuplicateSocketW(s: SOCKET,
dwProcessId: DWORD,
lpProtocolInfo: LPWSAPROTOCOL_INFO)
-> c_int;
pub fn WSASend(s: SOCKET,
lpBuffers: LPWSABUF,
dwBufferCount: DWORD,
lpNumberOfBytesSent: LPDWORD,
dwFlags: DWORD,
lpOverlapped: LPWSAOVERLAPPED,
lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE)
-> c_int;
pub fn WSARecv(s: SOCKET,
lpBuffers: LPWSABUF,
dwBufferCount: DWORD,
lpNumberOfBytesRecvd: LPDWORD,
lpFlags: LPDWORD,
lpOverlapped: LPWSAOVERLAPPED,
lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE)
-> c_int;
pub fn GetCurrentProcessId() -> DWORD;
pub fn WSASocketW(af: c_int,
kind: c_int,
......
use marker::PhantomData;
use slice;
use sys::c;
#[repr(transparent)]
pub struct IoVec<'a> {
vec: c::WSABUF,
_p: PhantomData<&'a [u8]>,
}
impl<'a> IoVec<'a> {
#[inline]
pub fn new(buf: &'a [u8]) -> IoVec<'a> {
assert!(buf.len() <= c::ULONG::max_value() as usize);
IoVec {
vec: c::WSABUF {
len: buf.len() as c::ULONG,
buf: buf.as_ptr() as *mut u8 as *mut c::CHAR,
},
_p: PhantomData,
}
}
#[inline]
pub fn as_slice(&self) -> &'a [u8] {
unsafe {
slice::from_raw_parts(self.vec.buf as *mut u8, self.vec.len as usize)
}
}
}
pub struct IoVecMut<'a> {
vec: c::WSABUF,
_p: PhantomData<&'a mut [u8]>,
}
impl<'a> IoVecMut<'a> {
#[inline]
pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> {
assert!(buf.len() <= c::ULONG::max_value() as usize);
IoVecMut {
vec: c::WSABUF {
len: buf.len() as c::ULONG,
buf: buf.as_mut_ptr() as *mut c::CHAR,
},
_p: PhantomData,
}
}
#[inline]
pub fn as_slice(&self) -> &'a [u8] {
unsafe {
slice::from_raw_parts(self.vec.buf as *mut u8, self.vec.len as usize)
}
}
#[inline]
pub fn as_mut_slice(&mut self) -> &'a mut [u8] {
unsafe {
slice::from_raw_parts_mut(self.vec.buf as *mut u8, self.vec.len as usize)
}
}
}
......@@ -2,7 +2,7 @@
use ptr;
use ffi::{OsStr, OsString};
use io::{self, ErrorKind};
use io::ErrorKind;
use os::windows::ffi::{OsStrExt, OsStringExt};
use path::PathBuf;
use time::Duration;
......@@ -26,6 +26,7 @@
pub mod fast_thread_local;
pub mod fs;
pub mod handle;
pub mod io;
pub mod memchr;
pub mod mutex;
pub mod net;
......@@ -75,12 +76,12 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
}
}
pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> {
fn inner(s: &OsStr) -> io::Result<Vec<u16>> {
pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> ::io::Result<Vec<u16>> {
fn inner(s: &OsStr) -> ::io::Result<Vec<u16>> {
let mut maybe_result: Vec<u16> = s.encode_wide().collect();
if maybe_result.iter().any(|&u| u == 0) {
return Err(io::Error::new(io::ErrorKind::InvalidInput,
"strings passed to WinAPI cannot contain NULs"));
return Err(::io::Error::new(::io::ErrorKind::InvalidInput,
"strings passed to WinAPI cannot contain NULs"));
}
maybe_result.push(0);
Ok(maybe_result)
......@@ -102,7 +103,7 @@ fn inner(s: &OsStr) -> io::Result<Vec<u16>> {
// Once the syscall has completed (errors bail out early) the second closure is
// yielded the data which has been read from the syscall. The return value
// from this closure is then the return value of the function.
fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> io::Result<T>
fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> ::io::Result<T>
where F1: FnMut(*mut u16, c::DWORD) -> c::DWORD,
F2: FnOnce(&[u16]) -> T
{
......@@ -134,7 +135,7 @@ fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> io::Result<T>
c::SetLastError(0);
let k = match f1(buf.as_mut_ptr(), n as c::DWORD) {
0 if c::GetLastError() == 0 => 0,
0 => return Err(io::Error::last_os_error()),
0 => return Err(::io::Error::last_os_error()),
n => n,
} as usize;
if k == n && c::GetLastError() == c::ERROR_INSUFFICIENT_BUFFER {
......@@ -157,7 +158,7 @@ fn wide_char_to_multi_byte(code_page: u32,
flags: u32,
s: &[u16],
no_default_char: bool)
-> io::Result<Vec<i8>> {
-> ::io::Result<Vec<i8>> {
unsafe {
let mut size = c::WideCharToMultiByte(code_page,
flags,
......@@ -168,7 +169,7 @@ fn wide_char_to_multi_byte(code_page: u32,
ptr::null(),
ptr::null_mut());
if size == 0 {
return Err(io::Error::last_os_error());
return Err(::io::Error::last_os_error());
}
let mut buf = Vec::with_capacity(size as usize);
......@@ -185,10 +186,10 @@ fn wide_char_to_multi_byte(code_page: u32,
if no_default_char { &mut used_default_char }
else { ptr::null_mut() });
if size == 0 {
return Err(io::Error::last_os_error());
return Err(::io::Error::last_os_error());
}
if no_default_char && used_default_char == c::TRUE {
return Err(io::Error::new(io::ErrorKind::InvalidData,
return Err(::io::Error::new(::io::ErrorKind::InvalidData,
"string cannot be converted to requested code page"));
}
......@@ -220,9 +221,9 @@ fn is_zero(&self) -> bool {
impl_is_zero! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }
pub fn cvt<I: IsZero>(i: I) -> io::Result<I> {
pub fn cvt<I: IsZero>(i: I) -> ::io::Result<I> {
if i.is_zero() {
Err(io::Error::last_os_error())
Err(::io::Error::last_os_error())
} else {
Ok(i)
}
......
#![unstable(issue = "0", feature = "windows_net")]
use cmp;
use io::{self, Read};
use io::{self, Read, IoVec, IoVecMut};
use libc::{c_int, c_void, c_ulong, c_long};
use mem;
use net::{SocketAddr, Shutdown};
......@@ -207,6 +207,30 @@ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.recv_with_flags(buf, 0)
}
pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
// On unix when a socket is shut down all further reads return 0, so we
// do the same on windows to map a shut down socket to returning EOF.
let len = cmp::min(bufs.len(), c::DWORD::max_value() as usize) as c::DWORD;
let mut nread = 0;
let mut flags = 0;
unsafe {
let ret = c::WSARecv(
self.0,
bufs.as_mut_ptr() as *mut c::WSABUF,
len,
&mut nread,
&mut flags,
ptr::null_mut(),
ptr::null_mut(),
);
match ret {
0 => Ok(nread as usize),
_ if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0),
_ => Err(last_error()),
}
}
}
pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
self.recv_with_flags(buf, c::MSG_PEEK)
}
......@@ -243,6 +267,23 @@ pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
self.recv_from_with_flags(buf, c::MSG_PEEK)
}
pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
let len = cmp::min(bufs.len(), c::DWORD::max_value() as usize) as c::DWORD;
let mut nwritten = 0;
unsafe {
cvt(c::WSASend(
self.0,
bufs.as_ptr() as *const c::WSABUF as *mut c::WSABUF,
len,
&mut nwritten,
0,
ptr::null_mut(),
ptr::null_mut(),
))?;
}
Ok(nwritten as usize)
}
pub fn set_timeout(&self, dur: Option<Duration>,
kind: c_int) -> io::Result<()> {
let timeout = match dur {
......
use cmp;
use ffi::CString;
use fmt;
use io::{self, Error, ErrorKind};
use io::{self, Error, ErrorKind, IoVec, IoVecMut};
use libc::{c_int, c_void};
use mem;
use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr};
......@@ -255,6 +255,10 @@ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> {
self.inner.read_vectored(bufs)
}
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 {
......@@ -266,6 +270,10 @@ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
Ok(ret as usize)
}
pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result<usize> {
self.inner.write_vectored(bufs)
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
sockname(|buf, len| unsafe {
c::getpeername(*self.inner.as_inner(), buf, len)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册