From a47d04a9096e72dc21a2e8c70076056b4f7705ec Mon Sep 17 00:00:00 2001 From: David Turner Date: Sat, 14 Mar 2015 11:32:38 -0400 Subject: [PATCH] Add read_all to std:io::Read to parallel write_all in std::io::Write. In the event of EOF, read_all returns a result with the new error ShortRead(number of bytes successfully read). Fixes #23174 --- src/libstd/io/error.rs | 8 ++++++++ src/libstd/io/mod.rs | 41 +++++++++++++++++++++++++++++++++++++++++ src/libstd/io/stdio.rs | 3 +++ 3 files changed, 52 insertions(+) diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index f445ace081e4f..0f1ea7f73b2d0 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -107,6 +107,14 @@ pub enum ErrorKind { /// written. #[stable(feature = "rust1", since = "1.0.0")] WriteZero, + /// An error returned when an operation could not be completed because a + /// call to `read` returned `Ok(0)`. + /// + /// This typically means that an operation could only succeed if it read a + /// particular number of bytes but only a smaller number of bytes could be + /// read. + #[stable(feature = "rust1", since = "1.0.0")] + ShortRead(usize), /// This operation was interrupted. /// /// Interrupted operations can typically be retried. diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 8691c84a4622f..44d8e15144f00 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -187,6 +187,32 @@ pub trait Read { #[stable(feature = "rust1", since = "1.0.0")] fn read(&mut self, buf: &mut [u8]) -> Result; + /// Read as many bytes as buf can hold, stopping at EOF or on error + /// + /// This method will continuously call `read` while there is more data to + /// read. This method will not return until the entire buffer has been + /// successfully read or an error occurs. The first error generated from + /// this method will be returned. + /// + /// # Errors + /// + /// This function will return the first error that `read` returns. + #[stable(feature = "rust1", since = "1.0.0")] + fn read_all(&mut self, mut buf: &mut [u8]) -> Result<()> { + let mut total = 0; + while total < buf.len() { + match self.read(&mut buf[total..]) { + Ok(0) => return Err(Error::new(ErrorKind::ShortRead(total), + "failed to read whole buffer", + None)), + Ok(n) => total += n, + Err(ref e) if e.kind() == ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + Ok(()) + } + /// 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 @@ -989,6 +1015,21 @@ mod tests { assert_eq!(s.next(), None); } + #[test] + fn read_all() { + let mut c = Cursor::new(b"hello"); + let mut v = [0 as u8; 5]; + assert_eq!(c.read_all(&mut v), Ok()); + assert_eq!(v, b"hello"); + + let mut c = Cursor::new(b"short"); + let mut v = [115 as u8; 6]; + assert_eq!(c.read_all(&mut v), Error::new(ErrorKind::ShortRead(5), + "failed to read whole buffer", + None)); + assert_eq!(v, b"shorts"); + } + #[test] fn read_to_end() { let mut c = Cursor::new(&b""[..]); diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 53f67766ea676..a4a39a2719dc9 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -164,6 +164,9 @@ impl Read for Stdin { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.lock().read(buf) } + fn read_all(&mut self, buf: &mut [u8]) -> io::Result<()> { + self.lock().read_all(buf) + } fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { self.lock().read_to_end(buf) }