diff options
| author | Steven Fackler <sfackler@gmail.com> | 2019-02-08 20:42:34 +0100 |
|---|---|---|
| committer | Steven Fackler <sfackler@gmail.com> | 2019-02-13 19:40:17 -0800 |
| commit | 31bcec648aa57391115f877a2ca022d7ff6415aa (patch) | |
| tree | 2e9ba98a3146cb8eebf72d469a81615389edd4fd /src/libstd/net | |
| parent | 4772dc8087b1d0f2bab6d064fd930e596c82d439 (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.rs | 69 |
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)); |
