Skip to content

rt::io: Add Bytes iterator for Reader #8935

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 89 additions & 1 deletion src/libstd/rt/io/extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@

use uint;
use int;
use iterator::Iterator;
use vec;
use rt::io::{Reader, Writer};
use rt::io::{Reader, Writer, Decorator};
use rt::io::{read_error, standard_error, EndOfFile, DEFAULT_BUF_SIZE};
use option::{Option, Some, None};
use unstable::finally::Finally;
Expand Down Expand Up @@ -62,6 +63,16 @@ pub trait ReaderUtil {
/// Raises the same conditions as the `read` method.
fn read_to_end(&mut self) -> ~[u8];

/// Create an iterator that reads a single byte on
/// each iteration, until EOF.
///
/// # Failure
///
/// Raises the same conditions as the `read` method, for
/// each call to its `.next()` method.
/// Ends the iteration if the condition is handled.
fn bytes(self) -> ByteIterator<Self>;

}

pub trait ReaderByteConversions {
Expand Down Expand Up @@ -337,6 +348,41 @@ impl<T: Reader> ReaderUtil for T {
}
return buf;
}

fn bytes(self) -> ByteIterator<T> {
ByteIterator{reader: self}
}
}

/// An iterator that reads a single byte on each iteration,
/// until `.read_byte()` returns `None`.
///
/// # Notes about the Iteration Protocol
///
/// The `ByteIterator` may yield `None` and thus terminate
/// an iteration, but continue to yield elements if iteration
/// is attempted again.
///
/// # Failure
///
/// Raises the same conditions as the `read` method, for
/// each call to its `.next()` method.
/// Yields `None` if the condition is handled.
pub struct ByteIterator<T> {
priv reader: T,
}

impl<R> Decorator<R> for ByteIterator<R> {
fn inner(self) -> R { self.reader }
fn inner_ref<'a>(&'a self) -> &'a R { &self.reader }
fn inner_mut_ref<'a>(&'a mut self) -> &'a mut R { &mut self.reader }
}

impl<'self, R: Reader> Iterator<u8> for ByteIterator<R> {
#[inline]
fn next(&mut self) -> Option<u8> {
self.reader.read_byte()
}
}

impl<T: Reader> ReaderByteConversions for T {
Expand Down Expand Up @@ -646,6 +692,48 @@ mod test {
}
}

#[test]
fn bytes_0_bytes() {
let mut reader = MockReader::new();
let count = Cell::new(0);
reader.read = |buf| {
do count.with_mut_ref |count| {
if *count == 0 {
*count = 1;
Some(0)
} else {
buf[0] = 10;
Some(1)
}
}
};
let byte = reader.bytes().next();
assert!(byte == Some(10));
}

#[test]
fn bytes_eof() {
let mut reader = MockReader::new();
reader.read = |_| None;
let byte = reader.bytes().next();
assert!(byte == None);
}

#[test]
fn bytes_error() {
let mut reader = MockReader::new();
reader.read = |_| {
read_error::cond.raise(placeholder_error());
None
};
let mut it = reader.bytes();
do read_error::cond.trap(|_| ()).inside {
let byte = it.next();
assert!(byte == None);
}
}


#[test]
fn read_bytes() {
let mut reader = MemReader::new(~[10, 11, 12, 13]);
Expand Down