From 55603830715a1e4c99683660b141b6a4c3491d0c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 20 Mar 2014 18:52:00 -0700 Subject: [PATCH 1/2] std: Add an I/O reader method to fill a buffer I've found a common use case being to fill a slice (not an owned vector) completely with bytes. It's posible for short reads to happen, and if you're trying to get an exact number of bytes then this helper will be useful. --- src/libstd/io/buffered.rs | 6 +++--- src/libstd/io/mem.rs | 18 ++++++++++++++++-- src/libstd/io/mod.rs | 21 +++++++++++++++++++-- 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index ab9a8377136..5f3b88d5205 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -87,7 +87,7 @@ impl BufferedReader { } impl Buffer for BufferedReader { - fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]> { + fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> { if self.pos == self.cap { self.cap = try!(self.inner.read(self.buf)); self.pos = 0; @@ -104,7 +104,7 @@ impl Buffer for BufferedReader { impl Reader for BufferedReader { fn read(&mut self, buf: &mut [u8]) -> IoResult { let nread = { - let available = try!(self.fill()); + let available = try!(self.fill_buf()); let nread = cmp::min(available.len(), buf.len()); slice::bytes::copy_memory(buf, available.slice_to(nread)); nread @@ -336,7 +336,7 @@ impl BufferedStream { } impl Buffer for BufferedStream { - fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]> { self.inner.fill() } + fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> { self.inner.fill_buf() } fn consume(&mut self, amt: uint) { self.inner.consume(amt) } } diff --git a/src/libstd/io/mem.rs b/src/libstd/io/mem.rs index d0c4ef308b3..7ae717cfccf 100644 --- a/src/libstd/io/mem.rs +++ b/src/libstd/io/mem.rs @@ -190,7 +190,7 @@ impl Seek for MemReader { } impl Buffer for MemReader { - fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]> { + fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> { if self.pos < self.buf.len() { Ok(self.buf.slice_from(self.pos)) } else { @@ -322,7 +322,7 @@ impl<'a> Seek for BufReader<'a> { } impl<'a> Buffer for BufReader<'a> { - fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]> { + fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> { if self.pos < self.buf.len() { Ok(self.buf.slice_from(self.pos)) } else { @@ -555,4 +555,18 @@ mod test { let mut r = BufWriter::new(buf); assert!(r.seek(-1, SeekSet).is_err()); } + + #[test] + fn io_fill() { + let mut r = MemReader::new(~[1, 2, 3, 4, 5, 6, 7, 8]); + let mut buf = [0, ..3]; + assert_eq!(r.fill(buf), Ok(())); + assert_eq!(buf.as_slice(), &[1, 2, 3]); + assert_eq!(r.fill(buf.mut_slice_to(0)), Ok(())); + assert_eq!(buf.as_slice(), &[1, 2, 3]); + assert_eq!(r.fill(buf), Ok(())); + assert_eq!(buf.as_slice(), &[4, 5, 6]); + assert!(r.fill(buf).is_err()); + assert_eq!(buf.as_slice(), &[7, 8, 6]); + } } diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 88ffc363e88..6bd8f119ba2 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -360,6 +360,23 @@ pub trait Reader { } } + /// Fills the provided slice with bytes from this reader + /// + /// This will continue to call `read` until the slice has been completely + /// filled with bytes. + /// + /// # Error + /// + /// If an error occurs at any point, that error is returned, and no further + /// bytes are read. + fn fill(&mut self, buf: &mut [u8]) -> IoResult<()> { + let mut read = 0; + while read < buf.len() { + read += try!(self.read(buf.mut_slice_from(read))); + } + Ok(()) + } + /// Reads exactly `len` bytes and appends them to a vector. /// /// May push fewer than the requested number of bytes on error @@ -1045,7 +1062,7 @@ pub trait Buffer: Reader { /// This function will return an I/O error if the underlying reader was /// read, but returned an error. Note that it is not an error to return a /// 0-length buffer. - fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]>; + fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]>; /// Tells this buffer that `amt` bytes have been consumed from the buffer, /// so they should no longer be returned in calls to `fill` or `read`. @@ -1116,7 +1133,7 @@ pub trait Buffer: Reader { let mut used; loop { { - let available = match self.fill() { + let available = match self.fill_buf() { Ok(n) => n, Err(ref e) if res.len() > 0 && e.kind == EndOfFile => { used = 0; From 02dab5a3e79a48c77d28c9aa6dcfea173584933b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 20 Mar 2014 18:53:30 -0700 Subject: [PATCH 2/2] rand: Use fill() instead of read() It's possible for a reader to have a short read, and there's no reason the task should fail in this scenario. By using fill(), this has a stronger guarantee that the buffer will get filled with data. --- src/librand/reader.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/librand/reader.rs b/src/librand/reader.rs index 744930e028c..9e7e38d2723 100644 --- a/src/librand/reader.rs +++ b/src/librand/reader.rs @@ -60,10 +60,8 @@ impl Rng for ReaderRng { } fn fill_bytes(&mut self, v: &mut [u8]) { if v.len() == 0 { return } - match self.reader.read(v) { - Ok(n) if n == v.len() => return, - Ok(n) => fail!("ReaderRng.fill_bytes could not fill buffer: \ - read {} out of {} bytes.", n, v.len()), + match self.reader.fill(v) { + Ok(()) => {} Err(e) => fail!("ReaderRng.fill_bytes error: {}", e) } }