Skip to content

Commit 6c13b0f

Browse files
committed
auto merge of #8935 : blake2-ppc/rust/reader-bytes, r=brson
An iterator that simply calls `.read_bytes()` each iteration. I think choosing to own the Reader value and implementing Decorator to allow extracting it is the most generically useful. The Reader type variable can of course be some kind of reference type that implements Reader. In the generic form the `Bytes` iterator is well behaved itself and does not read ahead. It performs abysmally on top of a FileStream, and much better if a buffering reader is inserted inbetween.
2 parents 60fba4d + 913d1b4 commit 6c13b0f

File tree

1 file changed

+89
-1
lines changed

1 file changed

+89
-1
lines changed

src/libstd/rt/io/extensions.rs

+89-1
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515

1616
use uint;
1717
use int;
18+
use iterator::Iterator;
1819
use vec;
19-
use rt::io::{Reader, Writer};
20+
use rt::io::{Reader, Writer, Decorator};
2021
use rt::io::{read_error, standard_error, EndOfFile, DEFAULT_BUF_SIZE};
2122
use option::{Option, Some, None};
2223
use unstable::finally::Finally;
@@ -62,6 +63,16 @@ pub trait ReaderUtil {
6263
/// Raises the same conditions as the `read` method.
6364
fn read_to_end(&mut self) -> ~[u8];
6465

66+
/// Create an iterator that reads a single byte on
67+
/// each iteration, until EOF.
68+
///
69+
/// # Failure
70+
///
71+
/// Raises the same conditions as the `read` method, for
72+
/// each call to its `.next()` method.
73+
/// Ends the iteration if the condition is handled.
74+
fn bytes(self) -> ByteIterator<Self>;
75+
6576
}
6677

6778
pub trait ReaderByteConversions {
@@ -337,6 +348,41 @@ impl<T: Reader> ReaderUtil for T {
337348
}
338349
return buf;
339350
}
351+
352+
fn bytes(self) -> ByteIterator<T> {
353+
ByteIterator{reader: self}
354+
}
355+
}
356+
357+
/// An iterator that reads a single byte on each iteration,
358+
/// until `.read_byte()` returns `None`.
359+
///
360+
/// # Notes about the Iteration Protocol
361+
///
362+
/// The `ByteIterator` may yield `None` and thus terminate
363+
/// an iteration, but continue to yield elements if iteration
364+
/// is attempted again.
365+
///
366+
/// # Failure
367+
///
368+
/// Raises the same conditions as the `read` method, for
369+
/// each call to its `.next()` method.
370+
/// Yields `None` if the condition is handled.
371+
pub struct ByteIterator<T> {
372+
priv reader: T,
373+
}
374+
375+
impl<R> Decorator<R> for ByteIterator<R> {
376+
fn inner(self) -> R { self.reader }
377+
fn inner_ref<'a>(&'a self) -> &'a R { &self.reader }
378+
fn inner_mut_ref<'a>(&'a mut self) -> &'a mut R { &mut self.reader }
379+
}
380+
381+
impl<'self, R: Reader> Iterator<u8> for ByteIterator<R> {
382+
#[inline]
383+
fn next(&mut self) -> Option<u8> {
384+
self.reader.read_byte()
385+
}
340386
}
341387

342388
impl<T: Reader> ReaderByteConversions for T {
@@ -646,6 +692,48 @@ mod test {
646692
}
647693
}
648694

695+
#[test]
696+
fn bytes_0_bytes() {
697+
let mut reader = MockReader::new();
698+
let count = Cell::new(0);
699+
reader.read = |buf| {
700+
do count.with_mut_ref |count| {
701+
if *count == 0 {
702+
*count = 1;
703+
Some(0)
704+
} else {
705+
buf[0] = 10;
706+
Some(1)
707+
}
708+
}
709+
};
710+
let byte = reader.bytes().next();
711+
assert!(byte == Some(10));
712+
}
713+
714+
#[test]
715+
fn bytes_eof() {
716+
let mut reader = MockReader::new();
717+
reader.read = |_| None;
718+
let byte = reader.bytes().next();
719+
assert!(byte == None);
720+
}
721+
722+
#[test]
723+
fn bytes_error() {
724+
let mut reader = MockReader::new();
725+
reader.read = |_| {
726+
read_error::cond.raise(placeholder_error());
727+
None
728+
};
729+
let mut it = reader.bytes();
730+
do read_error::cond.trap(|_| ()).inside {
731+
let byte = it.next();
732+
assert!(byte == None);
733+
}
734+
}
735+
736+
649737
#[test]
650738
fn read_bytes() {
651739
let mut reader = MemReader::new(~[10, 11, 12, 13]);

0 commit comments

Comments
 (0)