Skip to content

Commit 6cbba7c

Browse files
committedMar 13, 2014
auto merge of #12414 : DaGenix/rust/failing-iterator-wrappers, r=alexcrichton
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
2 parents 792da84 + 9ba6bb5 commit 6cbba7c

File tree

7 files changed

+57
-49
lines changed

7 files changed

+57
-49
lines changed
 

‎src/compiletest/errors.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub fn load_errors(testfile: &Path) -> ~[ExpectedError] {
1919
let mut rdr = BufferedReader::new(File::open(testfile).unwrap());
2020
let mut line_num = 1u;
2121
for ln in rdr.lines() {
22-
error_patterns.push_all_move(parse_expected(line_num, ln));
22+
error_patterns.push_all_move(parse_expected(line_num, ln.unwrap()));
2323
line_num += 1u;
2424
}
2525
return error_patterns;

‎src/compiletest/header.rs

+1
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ fn iter_header(testfile: &Path, it: |&str| -> bool) -> bool {
140140
// Assume that any directives will be found before the first
141141
// module or function. This doesn't seem to be an optimization
142142
// with a warm page cache. Maybe with a cold one.
143+
let ln = ln.unwrap();
143144
if ln.starts_with("fn") || ln.starts_with("mod") {
144145
return true;
145146
} else { if !(it(ln.trim())) { return false; } }

‎src/libstd/io/buffered.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -537,9 +537,9 @@ mod test {
537537
let in_buf = MemReader::new(bytes!("a\nb\nc").to_owned());
538538
let mut reader = BufferedReader::with_capacity(2, in_buf);
539539
let mut it = reader.lines();
540-
assert_eq!(it.next(), Some(~"a\n"));
541-
assert_eq!(it.next(), Some(~"b\n"));
542-
assert_eq!(it.next(), Some(~"c"));
540+
assert_eq!(it.next(), Some(Ok(~"a\n")));
541+
assert_eq!(it.next(), Some(Ok(~"b\n")));
542+
assert_eq!(it.next(), Some(Ok(~"c")));
543543
assert_eq!(it.next(), None);
544544
}
545545

@@ -569,8 +569,8 @@ mod test {
569569
let buf = [195u8, 159u8, 'a' as u8];
570570
let mut reader = BufferedReader::with_capacity(1, BufReader::new(buf));
571571
let mut it = reader.chars();
572-
assert_eq!(it.next(), Some('ß'));
573-
assert_eq!(it.next(), Some('a'));
572+
assert_eq!(it.next(), Some(Ok('ß')));
573+
assert_eq!(it.next(), Some(Ok('a')));
574574
assert_eq!(it.next(), None);
575575
}
576576

‎src/libstd/io/extensions.rs

+17-12
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,26 @@
1717

1818
use container::Container;
1919
use iter::Iterator;
20-
use option::Option;
21-
use io::Reader;
20+
use option::{Option, Some, None};
21+
use result::{Ok, Err};
22+
use io;
23+
use io::{IoError, IoResult, Reader};
2224
use vec::{OwnedVector, ImmutableVector};
2325
use ptr::RawPtr;
2426

2527
/// An iterator that reads a single byte on each iteration,
26-
/// until `.read_byte()` returns `None`.
28+
/// until `.read_byte()` returns `EndOfFile`.
2729
///
2830
/// # Notes about the Iteration Protocol
2931
///
3032
/// The `Bytes` may yield `None` and thus terminate
3133
/// an iteration, but continue to yield elements if iteration
3234
/// is attempted again.
3335
///
34-
/// # Failure
36+
/// # Error
3537
///
36-
/// Raises the same conditions as the `read` method, for
37-
/// each call to its `.next()` method.
38-
/// Yields `None` if the condition is handled.
38+
/// Any error other than `EndOfFile` that is produced by the underlying Reader
39+
/// is returned by the iterator and should be handled by the caller.
3940
pub struct Bytes<'r, T> {
4041
priv reader: &'r mut T,
4142
}
@@ -46,10 +47,14 @@ impl<'r, R: Reader> Bytes<'r, R> {
4647
}
4748
}
4849

49-
impl<'r, R: Reader> Iterator<u8> for Bytes<'r, R> {
50+
impl<'r, R: Reader> Iterator<IoResult<u8>> for Bytes<'r, R> {
5051
#[inline]
51-
fn next(&mut self) -> Option<u8> {
52-
self.reader.read_byte().ok()
52+
fn next(&mut self) -> Option<IoResult<u8>> {
53+
match self.reader.read_byte() {
54+
Ok(x) => Some(Ok(x)),
55+
Err(IoError { kind: io::EndOfFile, .. }) => None,
56+
Err(e) => Some(Err(e))
57+
}
5358
}
5459
}
5560

@@ -257,7 +262,7 @@ mod test {
257262
count: 0,
258263
};
259264
let byte = reader.bytes().next();
260-
assert!(byte == Some(10));
265+
assert!(byte == Some(Ok(10)));
261266
}
262267

263268
#[test]
@@ -272,7 +277,7 @@ mod test {
272277
let mut reader = ErroringReader;
273278
let mut it = reader.bytes();
274279
let byte = it.next();
275-
assert!(byte.is_none());
280+
assert!(byte.unwrap().is_err());
276281
}
277282

278283
#[test]

‎src/libstd/io/mod.rs

+31-29
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Some examples of obvious things you might want to do
3131
use std::io;
3232
3333
for line in io::stdin().lines() {
34-
print!("{}", line);
34+
print!("{}", line.unwrap());
3535
}
3636
```
3737
@@ -57,26 +57,26 @@ Some examples of obvious things you might want to do
5757
5858
* Iterate over the lines of a file
5959
60-
```rust
60+
```rust,no_run
6161
use std::io::BufferedReader;
6262
use std::io::File;
6363
6464
let path = Path::new("message.txt");
6565
let mut file = BufferedReader::new(File::open(&path));
6666
for line in file.lines() {
67-
print!("{}", line);
67+
print!("{}", line.unwrap());
6868
}
6969
```
7070
7171
* Pull the lines of a file into a vector of strings
7272
73-
```rust
73+
```rust,no_run
7474
use std::io::BufferedReader;
7575
use std::io::File;
7676
7777
let path = Path::new("message.txt");
7878
let mut file = BufferedReader::new(File::open(&path));
79-
let lines: ~[~str] = file.lines().collect();
79+
let lines: ~[~str] = file.lines().map(|x| x.unwrap()).collect();
8080
```
8181
8282
* Make a simple TCP client connection and request
@@ -466,10 +466,8 @@ pub trait Reader {
466466
///
467467
/// # Error
468468
///
469-
/// The iterator protocol causes all specifics about errors encountered to
470-
/// be swallowed. All errors will be signified by returning `None` from the
471-
/// iterator. If this is undesirable, it is recommended to use the
472-
/// `read_byte` method.
469+
/// Any error other than `EndOfFile` that is produced by the underlying Reader
470+
/// is returned by the iterator and should be handled by the caller.
473471
fn bytes<'r>(&'r mut self) -> extensions::Bytes<'r, Self> {
474472
extensions::Bytes::new(self)
475473
}
@@ -986,7 +984,7 @@ pub trait Stream: Reader + Writer { }
986984
impl<T: Reader + Writer> Stream for T {}
987985

988986
/// An iterator that reads a line on each iteration,
989-
/// until `.read_line()` returns `None`.
987+
/// until `.read_line()` encounters `EndOfFile`.
990988
///
991989
/// # Notes about the Iteration Protocol
992990
///
@@ -996,21 +994,24 @@ impl<T: Reader + Writer> Stream for T {}
996994
///
997995
/// # Error
998996
///
999-
/// This iterator will swallow all I/O errors, transforming `Err` values to
1000-
/// `None`. If errors need to be handled, it is recommended to use the
1001-
/// `read_line` method directly.
997+
/// Any error other than `EndOfFile` that is produced by the underlying Reader
998+
/// is returned by the iterator and should be handled by the caller.
1002999
pub struct Lines<'r, T> {
10031000
priv buffer: &'r mut T,
10041001
}
10051002

1006-
impl<'r, T: Buffer> Iterator<~str> for Lines<'r, T> {
1007-
fn next(&mut self) -> Option<~str> {
1008-
self.buffer.read_line().ok()
1003+
impl<'r, T: Buffer> Iterator<IoResult<~str>> for Lines<'r, T> {
1004+
fn next(&mut self) -> Option<IoResult<~str>> {
1005+
match self.buffer.read_line() {
1006+
Ok(x) => Some(Ok(x)),
1007+
Err(IoError { kind: EndOfFile, ..}) => None,
1008+
Err(y) => Some(Err(y))
1009+
}
10091010
}
10101011
}
10111012

10121013
/// An iterator that reads a utf8-encoded character on each iteration,
1013-
/// until `.read_char()` returns `None`.
1014+
/// until `.read_char()` encounters `EndOfFile`.
10141015
///
10151016
/// # Notes about the Iteration Protocol
10161017
///
@@ -1020,16 +1021,19 @@ impl<'r, T: Buffer> Iterator<~str> for Lines<'r, T> {
10201021
///
10211022
/// # Error
10221023
///
1023-
/// This iterator will swallow all I/O errors, transforming `Err` values to
1024-
/// `None`. If errors need to be handled, it is recommended to use the
1025-
/// `read_char` method directly.
1024+
/// Any error other than `EndOfFile` that is produced by the underlying Reader
1025+
/// is returned by the iterator and should be handled by the caller.
10261026
pub struct Chars<'r, T> {
10271027
priv buffer: &'r mut T
10281028
}
10291029

1030-
impl<'r, T: Buffer> Iterator<char> for Chars<'r, T> {
1031-
fn next(&mut self) -> Option<char> {
1032-
self.buffer.read_char().ok()
1030+
impl<'r, T: Buffer> Iterator<IoResult<char>> for Chars<'r, T> {
1031+
fn next(&mut self) -> Option<IoResult<char>> {
1032+
match self.buffer.read_char() {
1033+
Ok(x) => Some(Ok(x)),
1034+
Err(IoError { kind: EndOfFile, ..}) => None,
1035+
Err(y) => Some(Err(y))
1036+
}
10331037
}
10341038
}
10351039

@@ -1095,9 +1099,8 @@ pub trait Buffer: Reader {
10951099
///
10961100
/// # Error
10971101
///
1098-
/// This iterator will transform all error values to `None`, discarding the
1099-
/// cause of the error. If this is undesirable, it is recommended to call
1100-
/// `read_line` directly.
1102+
/// Any error other than `EndOfFile` that is produced by the underlying Reader
1103+
/// is returned by the iterator and should be handled by the caller.
11011104
fn lines<'r>(&'r mut self) -> Lines<'r, Self> {
11021105
Lines { buffer: self }
11031106
}
@@ -1183,9 +1186,8 @@ pub trait Buffer: Reader {
11831186
///
11841187
/// # Error
11851188
///
1186-
/// This iterator will transform all error values to `None`, discarding the
1187-
/// cause of the error. If this is undesirable, it is recommended to call
1188-
/// `read_char` directly.
1189+
/// Any error other than `EndOfFile` that is produced by the underlying Reader
1190+
/// is returned by the iterator and should be handled by the caller.
11891191
fn chars<'r>(&'r mut self) -> Chars<'r, Self> {
11901192
Chars { buffer: self }
11911193
}

‎src/test/bench/shootout-k-nucleotide-pipes.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ fn main() {
182182
let mut proc_mode = false;
183183
184184
for line in rdr.lines() {
185-
let line = line.trim().to_owned();
185+
let line = line.unwrap().trim().to_owned();
186186
187187
if line.len() == 0u { continue; }
188188

‎src/test/bench/sudoku.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ impl Sudoku {
7272
7373
let mut g = vec::from_fn(10u, { |_i| ~[0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8] });
7474
for line in reader.lines() {
75-
let comps: ~[&str] = line.trim().split(',').collect();
75+
let comps: ~[&str] = line.unwrap().trim().split(',').collect();
7676
7777
if comps.len() == 3u {
7878
let row = from_str::<uint>(comps[0]).unwrap() as u8;

0 commit comments

Comments
 (0)
Please sign in to comment.