1
Fork 0

auto merge of #11271 : adridu59/rust/patch-io, r=huonw

This commit is contained in:
bors 2014-01-04 06:26:52 -08:00
commit 14c24accbc
2 changed files with 84 additions and 54 deletions

View file

@ -43,12 +43,13 @@ $ ./example numbers.txt
An example program that does this task reads like this: An example program that does this task reads like this:
~~~~{.xfail-test} ~~~~
# #[allow(unused_imports)]; # #[allow(unused_imports)];
# extern mod extra;
use std::io::buffered::BufferedReader; use std::io::buffered::BufferedReader;
use std::io::fs::File; use std::io::File;
# mod BufferedReader { # mod BufferedReader {
# use std::io::fs::File; # use std::io::File;
# use std::io::mem::MemReader; # use std::io::mem::MemReader;
# use std::io::buffered::BufferedReader; # use std::io::buffered::BufferedReader;
# static s : &'static [u8] = bytes!("1 2\n\ # static s : &'static [u8] = bytes!("1 2\n\
@ -71,10 +72,9 @@ fn main() {
fn read_int_pairs() -> ~[(int,int)] { fn read_int_pairs() -> ~[(int,int)] {
let mut pairs = ~[]; let mut pairs = ~[];
let args = std::os::args();
// Path takes a generic by-value, rather than by reference // Path takes a generic by-value, rather than by reference
let path = Path::new(args.get_opt(1).expect("No input file parameter!").as_slice()); # let _g = std::io::ignore_io_error();
let path = Path::new(&"foo.txt");
let mut reader = BufferedReader::new(File::open(&path)); let mut reader = BufferedReader::new(File::open(&path));
// 1. Iterate over the lines of our file. // 1. Iterate over the lines of our file.
@ -242,13 +242,14 @@ If the example is rewritten to use failure, these error cases can be trapped.
In this rewriting, failures are trapped by placing the I/O logic in a sub-task, In this rewriting, failures are trapped by placing the I/O logic in a sub-task,
and trapping its exit status using `task::try`: and trapping its exit status using `task::try`:
~~~~{.xfail-test} ~~~~
# #[allow(unused_imports)]; # #[allow(unused_imports)];
# extern mod extra;
use std::io::buffered::BufferedReader; use std::io::buffered::BufferedReader;
use std::io::fs::File; use std::io::File;
use std::task; use std::task;
# mod BufferedReader { # mod BufferedReader {
# use std::io::fs::File; # use std::io::File;
# use std::io::mem::MemReader; # use std::io::mem::MemReader;
# use std::io::buffered::BufferedReader; # use std::io::buffered::BufferedReader;
# static s : &'static [u8] = bytes!("1 2\n\ # static s : &'static [u8] = bytes!("1 2\n\
@ -280,8 +281,8 @@ fn main() {
fn read_int_pairs() -> ~[(int,int)] { fn read_int_pairs() -> ~[(int,int)] {
let mut pairs = ~[]; let mut pairs = ~[];
let args = std::os::args(); # let _g = std::io::ignore_io_error();
let path = Path::new(args.get_opt(1).expect("No input file parameter!").as_slice()); let path = Path::new(&"foo.txt");
let mut reader = BufferedReader::new(File::open(&path)); let mut reader = BufferedReader::new(File::open(&path));
for line in reader.lines() { for line in reader.lines() {
@ -346,12 +347,13 @@ If no handler is found, `Condition::raise` will fail the task with an appropriat
Rewriting the example to use a condition in place of ignoring malformed lines makes it slightly longer, Rewriting the example to use a condition in place of ignoring malformed lines makes it slightly longer,
but similarly clear as the version that used `fail!` in the logic where the error occurs: but similarly clear as the version that used `fail!` in the logic where the error occurs:
~~~~{.xfail-test} ~~~~
# #[allow(unused_imports)]; # #[allow(unused_imports)];
# extern mod extra;
use std::io::buffered::BufferedReader; use std::io::buffered::BufferedReader;
use std::io::fs::File; use std::io::File;
# mod BufferedReader { # mod BufferedReader {
# use std::io::fs::File; # use std::io::File;
# use std::io::mem::MemReader; # use std::io::mem::MemReader;
# use std::io::buffered::BufferedReader; # use std::io::buffered::BufferedReader;
# static s : &'static [u8] = bytes!("1 2\n\ # static s : &'static [u8] = bytes!("1 2\n\
@ -378,8 +380,8 @@ fn main() {
fn read_int_pairs() -> ~[(int,int)] { fn read_int_pairs() -> ~[(int,int)] {
let mut pairs = ~[]; let mut pairs = ~[];
let args = std::os::args(); # let _g = std::io::ignore_io_error();
let path = Path::new(args.get_opt(1).expect("No input file parameter!").as_slice()); let path = Path::new(&"foo.txt");
let mut reader = BufferedReader::new(File::open(&path)); let mut reader = BufferedReader::new(File::open(&path));
for line in reader.lines() { for line in reader.lines() {
@ -415,12 +417,13 @@ To trap a condition, use `Condition::trap` in some caller of the site that calls
For example, this version of the program traps the `malformed_line` condition For example, this version of the program traps the `malformed_line` condition
and replaces bad input lines with the pair `(-1,-1)`: and replaces bad input lines with the pair `(-1,-1)`:
~~~~{.xfail-test} ~~~~
# #[allow(unused_imports)]; # #[allow(unused_imports)];
# extern mod extra;
use std::io::buffered::BufferedReader; use std::io::buffered::BufferedReader;
use std::io::fs::File; use std::io::File;
# mod BufferedReader { # mod BufferedReader {
# use std::io::fs::File; # use std::io::File;
# use std::io::mem::MemReader; # use std::io::mem::MemReader;
# use std::io::buffered::BufferedReader; # use std::io::buffered::BufferedReader;
# static s : &'static [u8] = bytes!("1 2\n\ # static s : &'static [u8] = bytes!("1 2\n\
@ -452,8 +455,8 @@ fn main() {
fn read_int_pairs() -> ~[(int,int)] { fn read_int_pairs() -> ~[(int,int)] {
let mut pairs = ~[]; let mut pairs = ~[];
let args = std::os::args(); # let _g = std::io::ignore_io_error();
let path = Path::new(args.get_opt(1).expect("No input file parameter!").as_slice()); let path = Path::new(&"foo.txt");
let mut reader = BufferedReader::new(File::open(&path)); let mut reader = BufferedReader::new(File::open(&path));
for line in reader.lines() { for line in reader.lines() {
@ -490,12 +493,13 @@ In the example program, the first form of the `malformed_line` API implicitly as
This assumption may not be correct; some callers may wish to skip malformed lines, for example. This assumption may not be correct; some callers may wish to skip malformed lines, for example.
Changing the condition's return type from `(int,int)` to `Option<(int,int)>` will suffice to support this type of recovery: Changing the condition's return type from `(int,int)` to `Option<(int,int)>` will suffice to support this type of recovery:
~~~~{.xfail-test} ~~~~
# #[allow(unused_imports)]; # #[allow(unused_imports)];
# extern mod extra;
use std::io::buffered::BufferedReader; use std::io::buffered::BufferedReader;
use std::io::fs::File; use std::io::File;
# mod BufferedReader { # mod BufferedReader {
# use std::io::fs::File; # use std::io::File;
# use std::io::mem::MemReader; # use std::io::mem::MemReader;
# use std::io::buffered::BufferedReader; # use std::io::buffered::BufferedReader;
# static s : &'static [u8] = bytes!("1 2\n\ # static s : &'static [u8] = bytes!("1 2\n\
@ -528,8 +532,8 @@ fn main() {
fn read_int_pairs() -> ~[(int,int)] { fn read_int_pairs() -> ~[(int,int)] {
let mut pairs = ~[]; let mut pairs = ~[];
let args = std::os::args(); # let _g = std::io::ignore_io_error();
let path = Path::new(args.get_opt(1).expect("No input file parameter!").as_slice()); let path = Path::new(&"foo.txt");
let mut reader = BufferedReader::new(File::open(&path)); let mut reader = BufferedReader::new(File::open(&path));
for line in reader.lines() { for line in reader.lines() {
@ -575,12 +579,13 @@ until all relevant combinations encountered in practice are encoded.
In the example, suppose a third possible recovery form arose: reusing the previous value read. In the example, suppose a third possible recovery form arose: reusing the previous value read.
This can be encoded in the handler API by introducing a helper type: `enum MalformedLineFix`. This can be encoded in the handler API by introducing a helper type: `enum MalformedLineFix`.
~~~~{.xfail-test} ~~~~
# #[allow(unused_imports)]; # #[allow(unused_imports)];
# extern mod extra;
use std::io::buffered::BufferedReader; use std::io::buffered::BufferedReader;
use std::io::fs::File; use std::io::File;
# mod BufferedReader { # mod BufferedReader {
# use std::io::fs::File; # use std::io::File;
# use std::io::mem::MemReader; # use std::io::mem::MemReader;
# use std::io::buffered::BufferedReader; # use std::io::buffered::BufferedReader;
# static s : &'static [u8] = bytes!("1 2\n\ # static s : &'static [u8] = bytes!("1 2\n\
@ -622,8 +627,8 @@ fn main() {
fn read_int_pairs() -> ~[(int,int)] { fn read_int_pairs() -> ~[(int,int)] {
let mut pairs = ~[]; let mut pairs = ~[];
let args = std::os::args(); # let _g = std::io::ignore_io_error();
let path = Path::new(args.get_opt(1).expect("No input file parameter!").as_slice()); let path = Path::new(&"foo.txt");
let mut reader = BufferedReader::new(File::open(&path)); let mut reader = BufferedReader::new(File::open(&path));
for line in reader.lines() { for line in reader.lines() {
@ -699,12 +704,13 @@ task <unnamed> failed at 'called `Option::unwrap()` on a `None` value', .../libs
To make the program robust &mdash; or at least flexible &mdash; in the face of this potential failure, To make the program robust &mdash; or at least flexible &mdash; in the face of this potential failure,
a second condition and a helper function will suffice: a second condition and a helper function will suffice:
~~~~{.xfail-test} ~~~~
# #[allow(unused_imports)]; # #[allow(unused_imports)];
# extern mod extra;
use std::io::buffered::BufferedReader; use std::io::buffered::BufferedReader;
use std::io::fs::File; use std::io::File;
# mod BufferedReader { # mod BufferedReader {
# use std::io::fs::File; # use std::io::File;
# use std::io::mem::MemReader; # use std::io::mem::MemReader;
# use std::io::buffered::BufferedReader; # use std::io::buffered::BufferedReader;
# static s : &'static [u8] = bytes!("1 2\n\ # static s : &'static [u8] = bytes!("1 2\n\
@ -760,8 +766,8 @@ fn parse_int(x: &str) -> int {
fn read_int_pairs() -> ~[(int,int)] { fn read_int_pairs() -> ~[(int,int)] {
let mut pairs = ~[]; let mut pairs = ~[];
let args = std::os::args(); # let _g = std::io::ignore_io_error();
let path = Path::new(args.get_opt(1).expect("No input file parameter!").as_slice()); let path = Path::new(&"foo.txt");
let mut reader = BufferedReader::new(File::open(&path)); let mut reader = BufferedReader::new(File::open(&path));
for line in reader.lines() { for line in reader.lines() {

View file

@ -186,23 +186,29 @@ while still providing feedback about errors. The basic strategy:
so that nullable values do not have to be 'unwrapped' before use. so that nullable values do not have to be 'unwrapped' before use.
These features combine in the API to allow for expressions like These features combine in the API to allow for expressions like
`File::new("diary.txt").write_line("met a girl")` without having to `File::create(&Path::new("diary.txt")).write(bytes!("Met a girl.\n"))`
worry about whether "diary.txt" exists or whether the write without having to worry about whether "diary.txt" exists or whether
succeeds. As written, if either `new` or `write_line` encounters the write succeeds. As written, if either `new` or `write_line`
an error the task will fail. encounters an error the task will fail.
If you wanted to handle the error though you might write If you wanted to handle the error though you might write:
let mut error = None; ```rust
do io_error::cond(|e: IoError| { use std::io::File;
error = Some(e); use std::io::{IoError, io_error};
}).in {
File::new("diary.txt").write_line("met a girl");
}
if error.is_some() { let mut error = None;
println("failed to write my diary"); io_error::cond.trap(|e: IoError| {
} error = Some(e);
}).inside(|| {
File::create(&Path::new("diary.txt")).write(bytes!("Met a girl.\n"));
});
if error.is_some() {
println("failed to write my diary");
}
# ::std::io::fs::unlink(&Path::new("diary.txt"));
```
XXX: Need better condition handling syntax XXX: Need better condition handling syntax
@ -500,10 +506,16 @@ pub trait Reader {
/// ///
/// # Example /// # Example
/// ///
/// let mut reader = BufferedReader::new(File::open(&Path::new("foo.txt"))); /// ```rust
/// for line in reader.lines() { /// use std::io;
/// println(line); /// # let _g = ::std::io::ignore_io_error();
/// } /// let mut reader = io::stdin();
///
/// let mut bytes = [0, .. 10];
/// reader.read(bytes);
///
/// if reader.eof() { println("stdin() had at most 10 bytes of data."); }
/// ```
/// ///
/// # Failure /// # Failure
/// ///
@ -1098,6 +1110,18 @@ pub trait Buffer: Reader {
/// encoded unicode codepoints. If a newline is encountered, then the /// encoded unicode codepoints. If a newline is encountered, then the
/// newline is contained in the returned string. /// newline is contained in the returned string.
/// ///
/// # Example
///
/// ```rust
/// use std::io::buffered::BufferedReader;
/// use std::io;
/// # let _g = ::std::io::ignore_io_error();
///
/// let mut reader = BufferedReader::new(io::stdin());
///
/// let input = reader.read_line().unwrap_or(~"nothing");
/// ```
///
/// # Failure /// # Failure
/// ///
/// This function will raise on the `io_error` condition (except for /// This function will raise on the `io_error` condition (except for