about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPalmer Cox <p@lmercox.com>2014-02-19 21:53:46 -0500
committerPalmer Cox <p@lmercox.com>2014-03-12 22:42:50 -0400
commit9ba6bb5a71adeb861f8bf21c2b1f2fde3132480d (patch)
tree8b334634887fcd0a6ba5a2ed926aec010386fc05
parent2eebeb81372e320510a1c1e2eef96eb5146a1e1f (diff)
Update io iterators to produce IoResults
Most IO related functions return an IoResult so that the caller can handle failure
in whatever way is appropriate. However, the `lines`, `bytes`, and `chars` iterators all
supress errors. This means that code that needs to handle errors can't use any of these
iterators. All three of these iterators were updated to produce IoResults.

Fixes #12368
-rw-r--r--src/compiletest/errors.rs2
-rw-r--r--src/compiletest/header.rs1
-rw-r--r--src/libstd/io/buffered.rs10
-rw-r--r--src/libstd/io/extensions.rs29
-rw-r--r--src/libstd/io/mod.rs60
-rw-r--r--src/test/bench/shootout-k-nucleotide-pipes.rs2
-rw-r--r--src/test/bench/sudoku.rs2
7 files changed, 57 insertions, 49 deletions
diff --git a/src/compiletest/errors.rs b/src/compiletest/errors.rs
index 3a6b1666c1e..4fee64e6304 100644
--- a/src/compiletest/errors.rs
+++ b/src/compiletest/errors.rs
@@ -19,7 +19,7 @@ pub fn load_errors(testfile: &Path) -> ~[ExpectedError] {
     let mut rdr = BufferedReader::new(File::open(testfile).unwrap());
     let mut line_num = 1u;
     for ln in rdr.lines() {
-        error_patterns.push_all_move(parse_expected(line_num, ln));
+        error_patterns.push_all_move(parse_expected(line_num, ln.unwrap()));
         line_num += 1u;
     }
     return error_patterns;
diff --git a/src/compiletest/header.rs b/src/compiletest/header.rs
index 7f8be5ff090..81b76f6b09a 100644
--- a/src/compiletest/header.rs
+++ b/src/compiletest/header.rs
@@ -140,6 +140,7 @@ fn iter_header(testfile: &Path, it: |&str| -> bool) -> bool {
         // Assume that any directives will be found before the first
         // module or function. This doesn't seem to be an optimization
         // with a warm page cache. Maybe with a cold one.
+        let ln = ln.unwrap();
         if ln.starts_with("fn") || ln.starts_with("mod") {
             return true;
         } else { if !(it(ln.trim())) { return false; } }
diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index fa122fa8c11..3ae44e4a1b5 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -537,9 +537,9 @@ mod test {
         let in_buf = MemReader::new(bytes!("a\nb\nc").to_owned());
         let mut reader = BufferedReader::with_capacity(2, in_buf);
         let mut it = reader.lines();
-        assert_eq!(it.next(), Some(~"a\n"));
-        assert_eq!(it.next(), Some(~"b\n"));
-        assert_eq!(it.next(), Some(~"c"));
+        assert_eq!(it.next(), Some(Ok(~"a\n")));
+        assert_eq!(it.next(), Some(Ok(~"b\n")));
+        assert_eq!(it.next(), Some(Ok(~"c")));
         assert_eq!(it.next(), None);
     }
 
@@ -569,8 +569,8 @@ mod test {
         let buf = [195u8, 159u8, 'a' as u8];
         let mut reader = BufferedReader::with_capacity(1, BufReader::new(buf));
         let mut it = reader.chars();
-        assert_eq!(it.next(), Some('ß'));
-        assert_eq!(it.next(), Some('a'));
+        assert_eq!(it.next(), Some(Ok('ß')));
+        assert_eq!(it.next(), Some(Ok('a')));
         assert_eq!(it.next(), None);
     }
 
diff --git a/src/libstd/io/extensions.rs b/src/libstd/io/extensions.rs
index 0424b7783ce..f7cab755714 100644
--- a/src/libstd/io/extensions.rs
+++ b/src/libstd/io/extensions.rs
@@ -17,13 +17,15 @@
 
 use container::Container;
 use iter::Iterator;
-use option::Option;
-use io::Reader;
+use option::{Option, Some, None};
+use result::{Ok, Err};
+use io;
+use io::{IoError, IoResult, Reader};
 use vec::{OwnedVector, ImmutableVector};
 use ptr::RawPtr;
 
 /// An iterator that reads a single byte on each iteration,
-/// until `.read_byte()` returns `None`.
+/// until `.read_byte()` returns `EndOfFile`.
 ///
 /// # Notes about the Iteration Protocol
 ///
@@ -31,11 +33,10 @@ use ptr::RawPtr;
 /// an iteration, but continue to yield elements if iteration
 /// is attempted again.
 ///
-/// # Failure
+/// # Error
 ///
-/// Raises the same conditions as the `read` method, for
-/// each call to its `.next()` method.
-/// Yields `None` if the condition is handled.
+/// Any error other than `EndOfFile` that is produced by the underlying Reader
+/// is returned by the iterator and should be handled by the caller.
 pub struct Bytes<'r, T> {
     priv reader: &'r mut T,
 }
@@ -46,10 +47,14 @@ impl<'r, R: Reader> Bytes<'r, R> {
     }
 }
 
-impl<'r, R: Reader> Iterator<u8> for Bytes<'r, R> {
+impl<'r, R: Reader> Iterator<IoResult<u8>> for Bytes<'r, R> {
     #[inline]
-    fn next(&mut self) -> Option<u8> {
-        self.reader.read_byte().ok()
+    fn next(&mut self) -> Option<IoResult<u8>> {
+        match self.reader.read_byte() {
+            Ok(x) => Some(Ok(x)),
+            Err(IoError { kind: io::EndOfFile, .. }) => None,
+            Err(e) => Some(Err(e))
+        }
     }
 }
 
@@ -257,7 +262,7 @@ mod test {
             count: 0,
         };
         let byte = reader.bytes().next();
-        assert!(byte == Some(10));
+        assert!(byte == Some(Ok(10)));
     }
 
     #[test]
@@ -272,7 +277,7 @@ mod test {
         let mut reader = ErroringReader;
         let mut it = reader.bytes();
         let byte = it.next();
-        assert!(byte.is_none());
+        assert!(byte.unwrap().is_err());
     }
 
     #[test]
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index 1c10c7b61c3..26dcd0c077c 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -31,7 +31,7 @@ Some examples of obvious things you might want to do
     use std::io;
 
     for line in io::stdin().lines() {
-        print!("{}", line);
+        print!("{}", line.unwrap());
     }
     ```
 
@@ -57,26 +57,26 @@ Some examples of obvious things you might want to do
 
 * Iterate over the lines of a file
 
-    ```rust
+    ```rust,no_run
     use std::io::BufferedReader;
     use std::io::File;
 
     let path = Path::new("message.txt");
     let mut file = BufferedReader::new(File::open(&path));
     for line in file.lines() {
-        print!("{}", line);
+        print!("{}", line.unwrap());
     }
     ```
 
 * Pull the lines of a file into a vector of strings
 
-    ```rust
+    ```rust,no_run
     use std::io::BufferedReader;
     use std::io::File;
 
     let path = Path::new("message.txt");
     let mut file = BufferedReader::new(File::open(&path));
-    let lines: ~[~str] = file.lines().collect();
+    let lines: ~[~str] = file.lines().map(|x| x.unwrap()).collect();
     ```
 
 * Make a simple TCP client connection and request
@@ -466,10 +466,8 @@ pub trait Reader {
     ///
     /// # Error
     ///
-    /// The iterator protocol causes all specifics about errors encountered to
-    /// be swallowed. All errors will be signified by returning `None` from the
-    /// iterator. If this is undesirable, it is recommended to use the
-    /// `read_byte` method.
+    /// Any error other than `EndOfFile` that is produced by the underlying Reader
+    /// is returned by the iterator and should be handled by the caller.
     fn bytes<'r>(&'r mut self) -> extensions::Bytes<'r, Self> {
         extensions::Bytes::new(self)
     }
@@ -986,7 +984,7 @@ pub trait Stream: Reader + Writer { }
 impl<T: Reader + Writer> Stream for T {}
 
 /// An iterator that reads a line on each iteration,
-/// until `.read_line()` returns `None`.
+/// until `.read_line()` encounters `EndOfFile`.
 ///
 /// # Notes about the Iteration Protocol
 ///
@@ -996,21 +994,24 @@ impl<T: Reader + Writer> Stream for T {}
 ///
 /// # Error
 ///
-/// This iterator will swallow all I/O errors, transforming `Err` values to
-/// `None`. If errors need to be handled, it is recommended to use the
-/// `read_line` method directly.
+/// Any error other than `EndOfFile` that is produced by the underlying Reader
+/// is returned by the iterator and should be handled by the caller.
 pub struct Lines<'r, T> {
     priv buffer: &'r mut T,
 }
 
-impl<'r, T: Buffer> Iterator<~str> for Lines<'r, T> {
-    fn next(&mut self) -> Option<~str> {
-        self.buffer.read_line().ok()
+impl<'r, T: Buffer> Iterator<IoResult<~str>> for Lines<'r, T> {
+    fn next(&mut self) -> Option<IoResult<~str>> {
+        match self.buffer.read_line() {
+            Ok(x) => Some(Ok(x)),
+            Err(IoError { kind: EndOfFile, ..}) => None,
+            Err(y) => Some(Err(y))
+        }
     }
 }
 
 /// An iterator that reads a utf8-encoded character on each iteration,
-/// until `.read_char()` returns `None`.
+/// until `.read_char()` encounters `EndOfFile`.
 ///
 /// # Notes about the Iteration Protocol
 ///
@@ -1020,16 +1021,19 @@ impl<'r, T: Buffer> Iterator<~str> for Lines<'r, T> {
 ///
 /// # Error
 ///
-/// This iterator will swallow all I/O errors, transforming `Err` values to
-/// `None`. If errors need to be handled, it is recommended to use the
-/// `read_char` method directly.
+/// Any error other than `EndOfFile` that is produced by the underlying Reader
+/// is returned by the iterator and should be handled by the caller.
 pub struct Chars<'r, T> {
     priv buffer: &'r mut T
 }
 
-impl<'r, T: Buffer> Iterator<char> for Chars<'r, T> {
-    fn next(&mut self) -> Option<char> {
-        self.buffer.read_char().ok()
+impl<'r, T: Buffer> Iterator<IoResult<char>> for Chars<'r, T> {
+    fn next(&mut self) -> Option<IoResult<char>> {
+        match self.buffer.read_char() {
+            Ok(x) => Some(Ok(x)),
+            Err(IoError { kind: EndOfFile, ..}) => None,
+            Err(y) => Some(Err(y))
+        }
     }
 }
 
@@ -1095,9 +1099,8 @@ pub trait Buffer: Reader {
     ///
     /// # Error
     ///
-    /// This iterator will transform all error values to `None`, discarding the
-    /// cause of the error. If this is undesirable, it is recommended to call
-    /// `read_line` directly.
+    /// Any error other than `EndOfFile` that is produced by the underlying Reader
+    /// is returned by the iterator and should be handled by the caller.
     fn lines<'r>(&'r mut self) -> Lines<'r, Self> {
         Lines { buffer: self }
     }
@@ -1183,9 +1186,8 @@ pub trait Buffer: Reader {
     ///
     /// # Error
     ///
-    /// This iterator will transform all error values to `None`, discarding the
-    /// cause of the error. If this is undesirable, it is recommended to call
-    /// `read_char` directly.
+    /// Any error other than `EndOfFile` that is produced by the underlying Reader
+    /// is returned by the iterator and should be handled by the caller.
     fn chars<'r>(&'r mut self) -> Chars<'r, Self> {
         Chars { buffer: self }
     }
diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs
index 7188e119a8d..d8bd0e6250f 100644
--- a/src/test/bench/shootout-k-nucleotide-pipes.rs
+++ b/src/test/bench/shootout-k-nucleotide-pipes.rs
@@ -182,7 +182,7 @@ fn main() {
    let mut proc_mode = false;
 
    for line in rdr.lines() {
-       let line = line.trim().to_owned();
+       let line = line.unwrap().trim().to_owned();
 
        if line.len() == 0u { continue; }
 
diff --git a/src/test/bench/sudoku.rs b/src/test/bench/sudoku.rs
index b77180e8e4c..d2ce61ee755 100644
--- a/src/test/bench/sudoku.rs
+++ b/src/test/bench/sudoku.rs
@@ -72,7 +72,7 @@ impl Sudoku {
 
         let mut g = vec::from_fn(10u, { |_i| ~[0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8] });
         for line in reader.lines() {
-            let comps: ~[&str] = line.trim().split(',').collect();
+            let comps: ~[&str] = line.unwrap().trim().split(',').collect();
 
             if comps.len() == 3u {
                 let row     = from_str::<uint>(comps[0]).unwrap() as u8;