Skip to content

Commit 9ba6bb5

Browse files
author
Palmer Cox
committed
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
1 parent 2eebeb8 commit 9ba6bb5

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)