diff options
| author | bors <bors@rust-lang.org> | 2019-12-19 11:33:00 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2019-12-19 11:33:00 +0000 |
| commit | 0de96d37fbcc54978458c18f5067cd9817669bc8 (patch) | |
| tree | 9fb998a8d7f0d19bc4ad5a7e37ee1fa694e27de6 /src/libstd | |
| parent | c605199e89572e586a5f37bc698c48b6a10896fb (diff) | |
| parent | 06985c68592112ef256eb08140f38a30b602d35c (diff) | |
| download | rust-0de96d37fbcc54978458c18f5067cd9817669bc8.tar.gz rust-0de96d37fbcc54978458c18f5067cd9817669bc8.zip | |
Auto merge of #67419 - Centril:rollup-v7b0ypv, r=Centril
Rollup of 8 pull requests Successful merges: - #67189 (Unify binop wording) - #67270 (std: Implement `LineWriter::write_vectored`) - #67286 (Fix the configure.py TOML field for a couple LLVM options) - #67321 (make htons const fn) - #67382 (Remove some unnecessary `ATTR_*` constants.) - #67389 (Remove `SO_NOSIGPIPE` dummy variable on platforms that don't use it.) - #67394 (Remove outdated references to @T from comments) - #67406 (Suggest associated type when the specified one cannot be found) Failed merges: r? @ghost
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/io/buffered.rs | 172 | ||||
| -rw-r--r-- | src/libstd/net/addr.rs | 14 | ||||
| -rw-r--r-- | src/libstd/net/mod.rs | 19 | ||||
| -rw-r--r-- | src/libstd/sys/unix/net.rs | 17 | ||||
| -rw-r--r-- | src/libstd/sys/vxworks/net.rs | 1 |
5 files changed, 188 insertions, 35 deletions
diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 8e81b292f6f..df259dc2f56 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -989,6 +989,68 @@ impl<W: Write> Write for LineWriter<W> { } } + // Vectored writes are very similar to the writes above, but adjusted for + // the list of buffers that we have to write. + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { + if self.need_flush { + self.flush()?; + } + + // Find the last newline, and failing that write the whole buffer + let last_newline = bufs + .iter() + .enumerate() + .rev() + .filter_map(|(i, buf)| { + let pos = memchr::memrchr(b'\n', buf)?; + Some((i, pos)) + }) + .next(); + let (i, j) = match last_newline { + Some(pair) => pair, + None => return self.inner.write_vectored(bufs), + }; + let (prefix, suffix) = bufs.split_at(i); + let (buf, suffix) = suffix.split_at(1); + let buf = &buf[0]; + + // Write everything up to the last newline, flushing afterwards. Note + // that only if we finished our entire `write_vectored` do we try the + // subsequent + // `write` + let mut n = 0; + let prefix_amt = prefix.iter().map(|i| i.len()).sum(); + if prefix_amt > 0 { + n += self.inner.write_vectored(prefix)?; + self.need_flush = true; + } + if n == prefix_amt { + match self.inner.write(&buf[..=j]) { + Ok(m) => n += m, + Err(e) if n == 0 => return Err(e), + Err(_) => return Ok(n), + } + self.need_flush = true; + } + if self.flush().is_err() || n != j + 1 + prefix_amt { + return Ok(n); + } + + // ... and now write out everything remaining + match self.inner.write(&buf[j + 1..]) { + Ok(i) => n += i, + Err(_) => return Ok(n), + } + + if suffix.iter().map(|s| s.len()).sum::<usize>() == 0 { + return Ok(n) + } + match self.inner.write_vectored(suffix) { + Ok(i) => Ok(n + i), + Err(_) => Ok(n), + } + } + fn flush(&mut self) -> io::Result<()> { self.inner.flush()?; self.need_flush = false; @@ -1015,7 +1077,7 @@ where #[cfg(test)] mod tests { use crate::io::prelude::*; - use crate::io::{self, BufReader, BufWriter, LineWriter, SeekFrom}; + use crate::io::{self, BufReader, BufWriter, LineWriter, SeekFrom, IoSlice}; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::thread; @@ -1483,4 +1545,112 @@ mod tests { assert_eq!(l.write(b"a").unwrap_err().kind(), io::ErrorKind::Other) } + + #[test] + fn line_vectored() { + let mut a = LineWriter::new(Vec::new()); + assert_eq!( + a.write_vectored(&[ + IoSlice::new(&[]), + IoSlice::new(b"\n"), + IoSlice::new(&[]), + IoSlice::new(b"a"), + ]) + .unwrap(), + 2, + ); + assert_eq!(a.get_ref(), b"\n"); + + assert_eq!( + a.write_vectored(&[ + IoSlice::new(&[]), + IoSlice::new(b"b"), + IoSlice::new(&[]), + IoSlice::new(b"a"), + IoSlice::new(&[]), + IoSlice::new(b"c"), + ]) + .unwrap(), + 3, + ); + assert_eq!(a.get_ref(), b"\n"); + a.flush().unwrap(); + assert_eq!(a.get_ref(), b"\nabac"); + assert_eq!(a.write_vectored(&[]).unwrap(), 0); + assert_eq!( + a.write_vectored(&[ + IoSlice::new(&[]), + IoSlice::new(&[]), + IoSlice::new(&[]), + IoSlice::new(&[]), + ]) + .unwrap(), + 0, + ); + assert_eq!(a.write_vectored(&[IoSlice::new(b"a\nb"),]).unwrap(), 3); + assert_eq!(a.get_ref(), b"\nabaca\n"); + } + + #[test] + fn line_vectored_partial_and_errors() { + enum Call { + Write { inputs: Vec<&'static [u8]>, output: io::Result<usize> }, + Flush { output: io::Result<()> }, + } + struct Writer { + calls: Vec<Call>, + } + + impl Write for Writer { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.write_vectored(&[IoSlice::new(buf)]) + } + + fn write_vectored(&mut self, buf: &[IoSlice<'_>]) -> io::Result<usize> { + match self.calls.pop().unwrap() { + Call::Write { inputs, output } => { + assert_eq!(inputs, buf.iter().map(|b| &**b).collect::<Vec<_>>()); + output + } + _ => panic!("unexpected call to write"), + } + } + + fn flush(&mut self) -> io::Result<()> { + match self.calls.pop().unwrap() { + Call::Flush { output } => output, + _ => panic!("unexpected call to flush"), + } + } + } + + impl Drop for Writer { + fn drop(&mut self) { + if !thread::panicking() { + assert_eq!(self.calls.len(), 0); + } + } + } + + // partial writes keep going + let mut a = LineWriter::new(Writer { calls: Vec::new() }); + a.write_vectored(&[IoSlice::new(&[]), IoSlice::new(b"abc")]).unwrap(); + a.get_mut().calls.push(Call::Flush { output: Ok(()) }); + a.get_mut().calls.push(Call::Write { inputs: vec![b"bcx\n"], output: Ok(4) }); + a.get_mut().calls.push(Call::Write { inputs: vec![b"abcx\n"], output: Ok(1) }); + a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\n")]).unwrap(); + a.get_mut().calls.push(Call::Flush { output: Ok(()) }); + a.flush().unwrap(); + + // erroneous writes stop and don't write more + a.get_mut().calls.push(Call::Write { inputs: vec![b"x\n"], output: Err(err()) }); + assert_eq!(a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\na")]).unwrap(), 2); + a.get_mut().calls.push(Call::Flush { output: Ok(()) }); + a.get_mut().calls.push(Call::Write { inputs: vec![b"x\n"], output: Ok(2) }); + a.flush().unwrap(); + + fn err() -> io::Error { + io::Error::new(io::ErrorKind::Other, "x") + } + } } diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index d5f4ece726b..a9d88370c61 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -4,7 +4,7 @@ use crate::hash; use crate::io; use crate::iter; use crate::mem; -use crate::net::{hton, ntoh, IpAddr, Ipv4Addr, Ipv6Addr}; +use crate::net::{htons, ntohs, IpAddr, Ipv4Addr, Ipv6Addr}; use crate::option; use crate::slice; use crate::sys::net::netc as c; @@ -276,7 +276,7 @@ impl SocketAddrV4 { SocketAddrV4 { inner: c::sockaddr_in { sin_family: c::AF_INET as c::sa_family_t, - sin_port: hton(port), + sin_port: htons(port), sin_addr: *ip.as_inner(), ..unsafe { mem::zeroed() } }, @@ -326,7 +326,7 @@ impl SocketAddrV4 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn port(&self) -> u16 { - ntoh(self.inner.sin_port) + ntohs(self.inner.sin_port) } /// Changes the port number associated with this socket address. @@ -342,7 +342,7 @@ impl SocketAddrV4 { /// ``` #[stable(feature = "sockaddr_setters", since = "1.9.0")] pub fn set_port(&mut self, new_port: u16) { - self.inner.sin_port = hton(new_port); + self.inner.sin_port = htons(new_port); } } @@ -368,7 +368,7 @@ impl SocketAddrV6 { SocketAddrV6 { inner: c::sockaddr_in6 { sin6_family: c::AF_INET6 as c::sa_family_t, - sin6_port: hton(port), + sin6_port: htons(port), sin6_addr: *ip.as_inner(), sin6_flowinfo: flowinfo, sin6_scope_id: scope_id, @@ -420,7 +420,7 @@ impl SocketAddrV6 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn port(&self) -> u16 { - ntoh(self.inner.sin6_port) + ntohs(self.inner.sin6_port) } /// Changes the port number associated with this socket address. @@ -436,7 +436,7 @@ impl SocketAddrV6 { /// ``` #[stable(feature = "sockaddr_setters", since = "1.9.0")] pub fn set_port(&mut self, new_port: u16) { - self.inner.sin6_port = hton(new_port); + self.inner.sin6_port = htons(new_port); } /// Returns the flow information associated with this address. diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index b68146939fd..8652ed8b046 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -85,21 +85,10 @@ pub enum Shutdown { Both, } -#[doc(hidden)] -trait NetInt { - fn from_be(i: Self) -> Self; - fn to_be(&self) -> Self; -} -macro_rules! doit { - ($($t:ident)*) => ($(impl NetInt for $t { - fn from_be(i: Self) -> Self { <$t>::from_be(i) } - fn to_be(&self) -> Self { <$t>::to_be(*self) } - })*) -} -doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } - -fn hton<I: NetInt>(i: I) -> I { i.to_be() } -fn ntoh<I: NetInt>(i: I) -> I { I::from_be(i) } +#[inline] +const fn htons(i: u16) -> u16 { i.to_be() } +#[inline] +const fn ntohs(i: u16) -> u16 { u16::from_be(i) } fn each_addr<A: ToSocketAddrs, F, T>(addr: A, mut f: F) -> io::Result<T> where F: FnMut(io::Result<&SocketAddr>) -> io::Result<T> diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index 946b2b9d8de..5d101ed1f2e 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -28,14 +28,6 @@ use libc::SOCK_CLOEXEC; #[cfg(not(target_os = "linux"))] const SOCK_CLOEXEC: c_int = 0; -// Another conditional constant for name resolution: Macos et iOS use -// SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket. -// Other platforms do otherwise. -#[cfg(target_vendor = "apple")] -use libc::SO_NOSIGPIPE; -#[cfg(not(target_vendor = "apple"))] -const SO_NOSIGPIPE: c_int = 0; - pub struct Socket(FileDesc); pub fn init() {} @@ -89,9 +81,12 @@ impl Socket { let fd = FileDesc::new(fd); fd.set_cloexec()?; let socket = Socket(fd); - if cfg!(target_vendor = "apple") { - setsockopt(&socket, libc::SOL_SOCKET, SO_NOSIGPIPE, 1)?; - } + + // macOS and iOS use `SO_NOSIGPIPE` as a `setsockopt` + // flag to disable `SIGPIPE` emission on socket. + #[cfg(target_vendor = "apple")] + setsockopt(&socket, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1)?; + Ok(socket) } } diff --git a/src/libstd/sys/vxworks/net.rs b/src/libstd/sys/vxworks/net.rs index 85f5fcff2c2..54466ff2c2e 100644 --- a/src/libstd/sys/vxworks/net.rs +++ b/src/libstd/sys/vxworks/net.rs @@ -19,7 +19,6 @@ pub extern crate libc as netc; pub type wrlen_t = size_t; const SOCK_CLOEXEC: c_int = 0; -const SO_NOSIGPIPE: c_int = 0; pub struct Socket(FileDesc); |
