about summary refs log tree commit diff
path: root/src/libstd/net
diff options
context:
space:
mode:
authorSteven Fackler <sfackler@gmail.com>2019-02-08 20:42:34 +0100
committerSteven Fackler <sfackler@gmail.com>2019-02-13 19:40:17 -0800
commit31bcec648aa57391115f877a2ca022d7ff6415aa (patch)
tree2e9ba98a3146cb8eebf72d469a81615389edd4fd /src/libstd/net
parent4772dc8087b1d0f2bab6d064fd930e596c82d439 (diff)
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.
Diffstat (limited to 'src/libstd/net')
-rw-r--r--src/libstd/net/tcp.rs69
1 files changed, 67 insertions, 2 deletions
diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs
index c4b0cd0f17c..d8a9d80cdbf 100644
--- a/src/libstd/net/tcp.rs
+++ b/src/libstd/net/tcp.rs
@@ -1,7 +1,7 @@
 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 @@ impl TcpStream {
 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 @@ impl Read for TcpStream {
 #[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 @@ impl<'a> Read for &'a TcpStream {
 #[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 @@ impl fmt::Debug for TcpListener {
 
 #[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};
@@ -1185,6 +1203,53 @@ mod tests {
     }
 
     #[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| {
             let _listener = t!(TcpListener::bind(&addr));