about summary refs log tree commit diff
diff options
context:
space:
mode:
authorblake2-ppc <blake2-ppc>2013-09-02 01:30:21 +0200
committerblake2-ppc <blake2-ppc>2013-09-02 03:12:32 +0200
commit61026ae621ffbc6d7538cfb0add49b8fc5638e86 (patch)
tree667b44fd4a0c33e9042f18f670d9c09d8c682448
parent1f4aba8cbf7caa3a82b52b6f171221ed6067eed5 (diff)
downloadrust-61026ae621ffbc6d7538cfb0add49b8fc5638e86.tar.gz
rust-61026ae621ffbc6d7538cfb0add49b8fc5638e86.zip
rt::io: Add Bytes iterator for Reader
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.
-rw-r--r--src/libstd/rt/io/extensions.rs84
1 files changed, 83 insertions, 1 deletions
diff --git a/src/libstd/rt/io/extensions.rs b/src/libstd/rt/io/extensions.rs
index e82662c6b0d..0b93a2ad2ca 100644
--- a/src/libstd/rt/io/extensions.rs
+++ b/src/libstd/rt/io/extensions.rs
@@ -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;
@@ -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) -> Bytes<Self>;
+
 }
 
 pub trait ReaderByteConversions {
@@ -337,6 +348,35 @@ impl<T: Reader> ReaderUtil for T {
         }
         return buf;
     }
+
+    fn bytes(self) -> Bytes<T> {
+        Bytes{reader: self}
+    }
+}
+
+/// 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.
+pub struct Bytes<T> {
+    priv reader: T,
+}
+
+impl<R> Decorator<R> for Bytes<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 Bytes<R> {
+    #[inline]
+    fn next(&mut self) -> Option<u8> {
+        self.reader.read_byte()
+    }
 }
 
 impl<T: Reader> ReaderByteConversions for T {
@@ -647,6 +687,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]);
         let bytes = reader.read_bytes(4);