Skip to content

Commit

Permalink
std::io::util cleanup + fixes
Browse files Browse the repository at this point in the history
* 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]
  • Loading branch information
sfackler committed Aug 15, 2014
1 parent bf0a925 commit 89a0060
Showing 1 changed file with 38 additions and 18 deletions.
56 changes: 38 additions & 18 deletions src/libstd/io/util.rs
Expand Up @@ -48,10 +48,12 @@ impl<R: Reader> Reader for LimitReader<R> {
}

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
}
}

Expand All @@ -67,6 +69,8 @@ impl<R: Buffer> Buffer for LimitReader<R> {
}

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);
}
Expand Down Expand Up @@ -97,6 +101,7 @@ impl Buffer for ZeroReader {
static DATA: [u8, ..64] = [0, ..64];
Ok(DATA.as_slice())
}

fn consume(&mut self, _amt: uint) {}
}

Expand All @@ -117,7 +122,10 @@ impl Buffer for NullReader {
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>>
}
Expand All @@ -132,24 +140,22 @@ impl 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,
Expand Down Expand Up @@ -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 }
}
}

Expand All @@ -251,7 +256,7 @@ impl<T: Iterator<u8>> Reader for IterReader<T> {
*slot = elt;
len += 1;
}
if len == 0 {
if len == 0 && buf.len() != 0 {
Err(io::standard_error(io::EndOfFile))
} else {
Ok(len)
Expand Down Expand Up @@ -297,6 +302,14 @@ mod test {
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;
Expand Down Expand Up @@ -415,4 +428,11 @@ mod test {

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));
}
}

5 comments on commit 89a0060

@bors
Copy link
Contributor

@bors bors commented on 89a0060 Aug 16, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from alexcrichton
at sfackler@89a0060

@bors
Copy link
Contributor

@bors bors commented on 89a0060 Aug 16, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging sfackler/rust/io-util-cleanup = 89a0060 into auto

@bors
Copy link
Contributor

@bors bors commented on 89a0060 Aug 16, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sfackler/rust/io-util-cleanup = 89a0060 merged ok, testing candidate = ec1d34e

@bors
Copy link
Contributor

@bors bors commented on 89a0060 Aug 16, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fast-forwarding master to auto = ec1d34e

Please sign in to comment.