auto merge of #16513 : sfackler/rust/io-util-cleanup, r=alexcrichton

* Fix `LimitReader`'s `Buffer::consume` impl to avoid limit underflow
* Make `MultiWriter` fail fast instead of always running through each
    `Writer`. This may or may not be what we want, but it at least
    doesn't throw any errors encountered in later `Writer`s into oblivion.
* Prevent `IterReader`'s `Reader::read` impl from returning EOF if given
    an empty buffer.

[breaking-change]
This commit is contained in:
bors 2014-08-16 05:36:14 +00:00
commit ec1d34eb27

View File

@ -48,10 +48,12 @@ fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> {
}
let len = cmp::min(self.limit, buf.len());
self.inner.read(buf.mut_slice_to(len)).map(|len| {
self.limit -= len;
len
})
let res = self.inner.read(buf.mut_slice_to(len));
match res {
Ok(len) => self.limit -= len,
_ => {}
}
res
}
}
@ -67,6 +69,8 @@ fn fill_buf<'a>(&'a mut self) -> io::IoResult<&'a [u8]> {
}
fn consume(&mut self, amt: uint) {
// Don't let callers reset the limit by passing an overlarge value
let amt = cmp::min(amt, self.limit);
self.limit -= amt;
self.inner.consume(amt);
}
@ -97,6 +101,7 @@ fn fill_buf<'a>(&'a mut self) -> io::IoResult<&'a [u8]> {
static DATA: [u8, ..64] = [0, ..64];
Ok(DATA.as_slice())
}
fn consume(&mut self, _amt: uint) {}
}
@ -117,7 +122,10 @@ fn fill_buf<'a>(&'a mut self) -> io::IoResult<&'a [u8]> {
fn consume(&mut self, _amt: uint) {}
}
/// A `Writer` which multiplexes writes to a set of `Writers`.
/// A `Writer` which multiplexes writes to a set of `Writer`s.
///
/// The `Writer`s are delegated to in order. If any `Writer` returns an error,
/// that error is returned immediately and remaining `Writer`s are not called.
pub struct MultiWriter {
writers: Vec<Box<Writer>>
}
@ -132,24 +140,22 @@ pub fn new(writers: Vec<Box<Writer>>) -> MultiWriter {
impl Writer for MultiWriter {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::IoResult<()> {
let mut ret = Ok(());
for writer in self.writers.mut_iter() {
ret = ret.and(writer.write(buf));
try!(writer.write(buf));
}
return ret;
Ok(())
}
#[inline]
fn flush(&mut self) -> io::IoResult<()> {
let mut ret = Ok(());
for writer in self.writers.mut_iter() {
ret = ret.and(writer.flush());
try!(writer.flush());
}
return ret;
Ok(())
}
}
/// A `Reader` which chains input from multiple `Readers`, reading each to
/// A `Reader` which chains input from multiple `Reader`s, reading each to
/// completion before moving onto the next.
pub struct ChainedReader<I, R> {
readers: I,
@ -229,17 +235,16 @@ pub fn copy<R: Reader, W: Writer>(r: &mut R, w: &mut W) -> io::IoResult<()> {
}
}
/// A `Reader` which converts an `Iterator<u8>` into a `Reader`.
/// An adaptor converting an `Iterator<u8>` to a `Reader`.
pub struct IterReader<T> {
iter: T,
}
impl<T: Iterator<u8>> IterReader<T> {
/// Create a new `IterReader` which will read from the specified `Iterator`.
/// Creates a new `IterReader` which will read from the specified
/// `Iterator`.
pub fn new(iter: T) -> IterReader<T> {
IterReader {
iter: iter,
}
IterReader { iter: iter }
}
}
@ -251,7 +256,7 @@ fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> {
*slot = elt;
len += 1;
}
if len == 0 {
if len == 0 && buf.len() != 0 {
Err(io::standard_error(io::EndOfFile))
} else {
Ok(len)
@ -297,6 +302,14 @@ fn test_limit_reader_limit() {
assert_eq!(0, r.limit());
}
#[test]
fn test_limit_reader_overlong_consume() {
let mut r = MemReader::new(vec![0, 1, 2, 3, 4, 5]);
let mut r = LimitReader::new(r.by_ref(), 1);
r.consume(2);
assert_eq!(vec![], r.read_to_end().unwrap());
}
#[test]
fn test_null_writer() {
let mut s = NullWriter;
@ -415,4 +428,11 @@ fn test_iter_reader() {
assert_eq!(r.read(buf).unwrap_err().kind, io::EndOfFile);
}
#[test]
fn iter_reader_zero_length() {
let mut r = IterReader::new(range(0u8, 8));
let mut buf = [];
assert_eq!(Ok(0), r.read(buf));
}
}