diff options
| author | bors <bors@rust-lang.org> | 2014-02-03 10:41:34 -0800 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2014-02-03 10:41:34 -0800 |
| commit | cb40eba4b1ce12914612914b94bdccd251a9f554 (patch) | |
| tree | 5cb922f942920dc7d6b0f3606e9cd914360b2707 /src/libstd | |
| parent | be4fc638092bf896c5c6c0672136b83b71e491ee (diff) | |
| parent | c765a8e7ad314651b92ff860cda0159c79dbec6e (diff) | |
| download | rust-cb40eba4b1ce12914612914b94bdccd251a9f554.tar.gz rust-cb40eba4b1ce12914612914b94bdccd251a9f554.zip | |
auto merge of #11946 : alexcrichton/rust/no-io-error, r=brson
Turns out this was a little more far-reaching than I thought it was. The first commit is the crux of this stack of commits. The `io::io_error` condition is completely removed and the `read` and `write` methods are altered to return `IoResult<T>`. This turned out to be an incredibly far-reaching change! Overall, I'm very happy with how this turned out (in addition with the `unused_must_use` lint). I had to almost rewrite the pretty printer in `libsyntax` as well as the the formatting in `librustdoc` (as one would expect). These two modules do *tons* of I/O, and I believe that it's definitely improved. This pull request also introduces the `if_ok!()` macro for returning-early from something that returns a result. I made quite liberal use of this in mostly the pretty printer and html renderer, and I found its usage generally quite pleasant and convenient to have. I didn't really feel like adding any other macro while I was using it, and I figured that pretty printing could be nicer, but it's nowhere near horrid today. This may be a controversial issue closing, but I'm going to say it. Closes #6163
Diffstat (limited to 'src/libstd')
39 files changed, 1814 insertions, 2138 deletions
diff --git a/src/libstd/comm/mod.rs b/src/libstd/comm/mod.rs index 7b1a6055542..bccebeaa79f 100644 --- a/src/libstd/comm/mod.rs +++ b/src/libstd/comm/mod.rs @@ -1252,7 +1252,7 @@ mod test { spawn(proc() { let _p = port; }); - task::try(proc() { + let _ = task::try(proc() { chan.send(1); }); } diff --git a/src/libstd/fmt/mod.rs b/src/libstd/fmt/mod.rs index a17a030f4f7..06737e22007 100644 --- a/src/libstd/fmt/mod.rs +++ b/src/libstd/fmt/mod.rs @@ -163,9 +163,10 @@ method of the signature: ```rust # use std; +# mod fmt { pub type Result = (); } # struct T; # trait SomeName<T> { -fn fmt(value: &T, f: &mut std::fmt::Formatter); +fn fmt(value: &T, f: &mut std::fmt::Formatter) -> fmt::Result; # } ``` @@ -174,7 +175,14 @@ emit output into the `f.buf` stream. It is up to each format trait implementation to correctly adhere to the requested formatting parameters. The values of these parameters will be listed in the fields of the `Formatter` struct. In order to help with this, the `Formatter` struct also provides some -helper methods. An example of implementing the formatting traits would look +helper methods. + +Additionally, the return value of this function is `fmt::Result` which is a +typedef to `Result<(), IoError>` (also known as `IoError<()>`). Formatting +implementations should ensure that they return errors from `write!` correctly +(propagating errors upward). + +An example of implementing the formatting traits would look like: ```rust @@ -187,7 +195,7 @@ struct Vector2D { } impl fmt::Show for Vector2D { - fn fmt(obj: &Vector2D, f: &mut fmt::Formatter) { + fn fmt(obj: &Vector2D, f: &mut fmt::Formatter) -> fmt::Result { // The `f.buf` value is of the type `&mut io::Writer`, which is what th // write! macro is expecting. Note that this formatting ignores the // various flags provided to format strings. @@ -198,7 +206,7 @@ impl fmt::Show for Vector2D { // Different traits allow different forms of output of a type. The meaning of // this format is to print the magnitude of a vector. impl fmt::Binary for Vector2D { - fn fmt(obj: &Vector2D, f: &mut fmt::Formatter) { + fn fmt(obj: &Vector2D, f: &mut fmt::Formatter) -> fmt::Result { let magnitude = (obj.x * obj.x + obj.y * obj.y) as f64; let magnitude = magnitude.sqrt(); @@ -207,7 +215,7 @@ impl fmt::Binary for Vector2D { // for details, and the function `pad` can be used to pad strings. let decimals = f.precision.unwrap_or(3); let string = f64::to_str_exact(magnitude, decimals); - f.pad_integral(string.as_bytes(), "", true); + f.pad_integral(string.as_bytes(), "", true) } } @@ -242,6 +250,7 @@ strings and instead directly write the output. Under the hood, this function is actually invoking the `write` function defined in this module. Example usage is: ```rust +# #[allow(unused_must_use)]; use std::io; let mut w = io::MemWriter::new(); @@ -468,16 +477,20 @@ will look like `"\\{"`. */ -#[cfg(not(stage0))] -use prelude::*; - use cast; use char::Char; +use container::Container; use io::MemWriter; use io; -use str; +use iter::{Iterator, range}; +use num::Signed; +use option::{Option,Some,None}; use repr; +use result::{Ok, Err}; +use str::StrSlice; +use str; use util; +use vec::ImmutableVector; use vec; // NOTE this is just because the `prelude::*` import above includes @@ -485,22 +498,11 @@ use vec; #[cfg(stage0)] pub use Default = fmt::Show; // export required for `format!()` etc. -#[cfg(stage0)] -use container::Container; -#[cfg(stage0)] -use iter::{Iterator, range}; -#[cfg(stage0)] -use option::{Option,Some,None}; -#[cfg(stage0)] -use vec::ImmutableVector; -#[cfg(stage0)] -use str::StrSlice; -#[cfg(stage0)] -use num::Signed; - pub mod parse; pub mod rt; +pub type Result = io::IoResult<()>; + /// A struct to represent both where to emit formatting strings to and how they /// should be formatted. A mutable version of this is passed to all formatting /// traits. @@ -527,7 +529,7 @@ pub struct Formatter<'a> { /// compile time it is ensured that the function and the value have the correct /// types, and then this struct is used to canonicalize arguments to one type. pub struct Argument<'a> { - priv formatter: extern "Rust" fn(&util::Void, &mut Formatter), + priv formatter: extern "Rust" fn(&util::Void, &mut Formatter) -> Result, priv value: &'a util::Void, } @@ -561,50 +563,50 @@ pub struct Arguments<'a> { /// to this trait. There is not an explicit way of selecting this trait to be /// used for formatting, it is only if no other format is specified. #[allow(missing_doc)] -pub trait Show { fn fmt(&Self, &mut Formatter); } +pub trait Show { fn fmt(&Self, &mut Formatter) -> Result; } /// Format trait for the `b` character #[allow(missing_doc)] -pub trait Bool { fn fmt(&Self, &mut Formatter); } +pub trait Bool { fn fmt(&Self, &mut Formatter) -> Result; } /// Format trait for the `c` character #[allow(missing_doc)] -pub trait Char { fn fmt(&Self, &mut Formatter); } +pub trait Char { fn fmt(&Self, &mut Formatter) -> Result; } /// Format trait for the `i` and `d` characters #[allow(missing_doc)] -pub trait Signed { fn fmt(&Self, &mut Formatter); } +pub trait Signed { fn fmt(&Self, &mut Formatter) -> Result; } /// Format trait for the `u` character #[allow(missing_doc)] -pub trait Unsigned { fn fmt(&Self, &mut Formatter); } +pub trait Unsigned { fn fmt(&Self, &mut Formatter) -> Result; } /// Format trait for the `o` character #[allow(missing_doc)] -pub trait Octal { fn fmt(&Self, &mut Formatter); } +pub trait Octal { fn fmt(&Self, &mut Formatter) -> Result; } /// Format trait for the `b` character #[allow(missing_doc)] -pub trait Binary { fn fmt(&Self, &mut Formatter); } +pub trait Binary { fn fmt(&Self, &mut Formatter) -> Result; } /// Format trait for the `x` character #[allow(missing_doc)] -pub trait LowerHex { fn fmt(&Self, &mut Formatter); } +pub trait LowerHex { fn fmt(&Self, &mut Formatter) -> Result; } /// Format trait for the `X` character #[allow(missing_doc)] -pub trait UpperHex { fn fmt(&Self, &mut Formatter); } +pub trait UpperHex { fn fmt(&Self, &mut Formatter) -> Result; } /// Format trait for the `s` character #[allow(missing_doc)] -pub trait String { fn fmt(&Self, &mut Formatter); } +pub trait String { fn fmt(&Self, &mut Formatter) -> Result; } /// Format trait for the `?` character #[allow(missing_doc)] -pub trait Poly { fn fmt(&Self, &mut Formatter); } +pub trait Poly { fn fmt(&Self, &mut Formatter) -> Result; } /// Format trait for the `p` character #[allow(missing_doc)] -pub trait Pointer { fn fmt(&Self, &mut Formatter); } +pub trait Pointer { fn fmt(&Self, &mut Formatter) -> Result; } /// Format trait for the `f` character #[allow(missing_doc)] -pub trait Float { fn fmt(&Self, &mut Formatter); } +pub trait Float { fn fmt(&Self, &mut Formatter) -> Result; } /// Format trait for the `e` character #[allow(missing_doc)] -pub trait LowerExp { fn fmt(&Self, &mut Formatter); } +pub trait LowerExp { fn fmt(&Self, &mut Formatter) -> Result; } /// Format trait for the `E` character #[allow(missing_doc)] -pub trait UpperExp { fn fmt(&Self, &mut Formatter); } +pub trait UpperExp { fn fmt(&Self, &mut Formatter) -> Result; } // FIXME #11938 - UFCS would make us able call the above methods // directly Show::show(x, fmt). @@ -617,7 +619,7 @@ macro_rules! uniform_fn_call_workaround { ($( $name: ident, $trait_: ident; )*) => { $( #[doc(hidden)] - pub fn $name<T: $trait_>(x: &T, fmt: &mut Formatter) { + pub fn $name<T: $trait_>(x: &T, fmt: &mut Formatter) -> Result { $trait_::fmt(x, fmt) } )* @@ -653,21 +655,22 @@ uniform_fn_call_workaround! { /// # Example /// /// ```rust +/// # #[allow(unused_must_use)]; /// use std::fmt; /// use std::io; /// /// let w = &mut io::stdout() as &mut io::Writer; -/// format_args!(|args| { fmt::write(w, args) }, "Hello, {}!", "world"); +/// format_args!(|args| { fmt::write(w, args); }, "Hello, {}!", "world"); /// ``` -pub fn write(output: &mut io::Writer, args: &Arguments) { +pub fn write(output: &mut io::Writer, args: &Arguments) -> Result { unsafe { write_unsafe(output, args.fmt, args.args) } } /// The `writeln` function takes the same arguments as `write`, except that it /// will also write a newline (`\n`) character at the end of the format string. -pub fn writeln(output: &mut io::Writer, args: &Arguments) { - unsafe { write_unsafe(output, args.fmt, args.args) } - output.write(['\n' as u8]); +pub fn writeln(output: &mut io::Writer, args: &Arguments) -> Result { + let first = unsafe { write_unsafe(output, args.fmt, args.args) }; + first.and_then(|()| output.write(['\n' as u8])) } /// The `write_unsafe` function takes an output stream, a precompiled format @@ -692,7 +695,7 @@ pub fn writeln(output: &mut io::Writer, args: &Arguments) { /// format string. pub unsafe fn write_unsafe(output: &mut io::Writer, fmt: &[rt::Piece], - args: &[Argument]) { + args: &[Argument]) -> Result { let mut formatter = Formatter { flags: 0, width: None, @@ -704,8 +707,9 @@ pub unsafe fn write_unsafe(output: &mut io::Writer, curarg: args.iter(), }; for piece in fmt.iter() { - formatter.run(piece, None); + if_ok!(formatter.run(piece, None)); } + Ok(()) } /// The format function takes a precompiled format string and a list of @@ -752,7 +756,7 @@ pub fn format(args: &Arguments) -> ~str { /// format string. pub unsafe fn format_unsafe(fmt: &[rt::Piece], args: &[Argument]) -> ~str { let mut output = MemWriter::new(); - write_unsafe(&mut output as &mut io::Writer, fmt, args); + write_unsafe(&mut output as &mut io::Writer, fmt, args).unwrap(); return str::from_utf8_owned(output.unwrap()).unwrap(); } @@ -762,10 +766,10 @@ impl<'a> Formatter<'a> { // at runtime. This consumes all of the compile-time statics generated by // the format! syntax extension. - fn run(&mut self, piece: &rt::Piece, cur: Option<&str>) { + fn run(&mut self, piece: &rt::Piece, cur: Option<&str>) -> Result { match *piece { - rt::String(s) => { self.buf.write(s.as_bytes()); } - rt::CurrentArgument(()) => { self.buf.write(cur.unwrap().as_bytes()); } + rt::String(s) => self.buf.write(s.as_bytes()), + rt::CurrentArgument(()) => self.buf.write(cur.unwrap().as_bytes()), rt::Argument(ref arg) => { // Fill in the format parameters into the formatter self.fill = arg.format.fill; @@ -782,8 +786,8 @@ impl<'a> Formatter<'a> { // Then actually do some printing match arg.method { - None => { (value.formatter)(value.value, self); } - Some(ref method) => { self.execute(*method, value); } + None => (value.formatter)(value.value, self), + Some(ref method) => self.execute(*method, value) } } } @@ -804,7 +808,7 @@ impl<'a> Formatter<'a> { } } - fn execute(&mut self, method: &rt::Method, arg: Argument) { + fn execute(&mut self, method: &rt::Method, arg: Argument) -> Result { match *method { // Pluralization is selection upon a numeric value specified as the // parameter. @@ -847,7 +851,7 @@ impl<'a> Formatter<'a> { } } - self.runplural(value, *default); + self.runplural(value, *default) } // Select is just a matching against the string specified. @@ -860,24 +864,26 @@ impl<'a> Formatter<'a> { for s in selectors.iter() { if s.selector == value { for piece in s.result.iter() { - self.run(piece, Some(value)); + if_ok!(self.run(piece, Some(value))); } - return; + return Ok(()); } } for piece in default.iter() { - self.run(piece, Some(value)); + if_ok!(self.run(piece, Some(value))); } + Ok(()) } } } - fn runplural(&mut self, value: uint, pieces: &[rt::Piece]) { + fn runplural(&mut self, value: uint, pieces: &[rt::Piece]) -> Result { ::uint::to_str_bytes(value, 10, |buf| { let valuestr = str::from_utf8(buf).unwrap(); for piece in pieces.iter() { - self.run(piece, Some(valuestr)); + if_ok!(self.run(piece, Some(valuestr))); } + Ok(()) }) } @@ -899,7 +905,7 @@ impl<'a> Formatter<'a> { /// This function will correctly account for the flags provided as well as /// the minimum width. It will not take precision into account. pub fn pad_integral(&mut self, s: &[u8], alternate_prefix: &str, - positive: bool) { + positive: bool) -> Result { use fmt::parse::{FlagAlternate, FlagSignPlus, FlagSignAwareZeroPad}; let mut actual_len = s.len(); @@ -916,32 +922,32 @@ impl<'a> Formatter<'a> { let sign = |this: &mut Formatter| { if !signprinted { if this.flags & 1 << (FlagSignPlus as uint) != 0 && positive { - this.buf.write(['+' as u8]); + if_ok!(this.buf.write(['+' as u8])); } else if !positive { - this.buf.write(['-' as u8]); + if_ok!(this.buf.write(['-' as u8])); } if this.flags & 1 << (FlagAlternate as uint) != 0 { - this.buf.write(alternate_prefix.as_bytes()); + if_ok!(this.buf.write(alternate_prefix.as_bytes())); } signprinted = true; } + Ok(()) }; let emit = |this: &mut Formatter| { - sign(this); - this.buf.write(s); + sign(this).and_then(|()| this.buf.write(s)) }; match self.width { - None => { emit(self) } - Some(min) if actual_len >= min => { emit(self) } + None => emit(self), + Some(min) if actual_len >= min => emit(self), Some(min) => { if self.flags & 1 << (FlagSignAwareZeroPad as uint) != 0 { self.fill = '0'; - sign(self); + if_ok!(sign(self)); } self.with_padding(min - actual_len, parse::AlignRight, |me| { - emit(me); + emit(me) }) } } @@ -958,11 +964,10 @@ impl<'a> Formatter<'a> { /// is longer than this length /// /// Notably this function ignored the `flag` parameters - pub fn pad(&mut self, s: &str) { + pub fn pad(&mut self, s: &str) -> Result { // Make sure there's a fast path up front if self.width.is_none() && self.precision.is_none() { - self.buf.write(s.as_bytes()); - return + return self.buf.write(s.as_bytes()); } // The `precision` field can be interpreted as a `max-width` for the // string being formatted @@ -974,8 +979,7 @@ impl<'a> Formatter<'a> { let char_len = s.char_len(); if char_len >= max { let nchars = ::cmp::min(max, char_len); - self.buf.write(s.slice_chars(0, nchars).as_bytes()); - return + return self.buf.write(s.slice_chars(0, nchars).as_bytes()); } } None => {} @@ -985,7 +989,7 @@ impl<'a> Formatter<'a> { match self.width { // If we're under the maximum length, and there's no minimum length // requirements, then we can just emit the string - None => { self.buf.write(s.as_bytes()) } + None => self.buf.write(s.as_bytes()), // If we're under the maximum width, check if we're over the minimum // width, if so it's as easy as just emitting the string. @@ -997,7 +1001,7 @@ impl<'a> Formatter<'a> { // up the minimum width with the specified string + some alignment. Some(width) => { self.with_padding(width - s.len(), parse::AlignLeft, |me| { - me.buf.write(s.as_bytes()); + me.buf.write(s.as_bytes()) }) } } @@ -1006,29 +1010,30 @@ impl<'a> Formatter<'a> { fn with_padding(&mut self, padding: uint, default: parse::Alignment, - f: |&mut Formatter|) { + f: |&mut Formatter| -> Result) -> Result { let align = match self.align { parse::AlignUnknown => default, parse::AlignLeft | parse::AlignRight => self.align }; if align == parse::AlignLeft { - f(self); + if_ok!(f(self)); } let mut fill = [0u8, ..4]; let len = self.fill.encode_utf8(fill); for _ in range(0, padding) { - self.buf.write(fill.slice_to(len)); + if_ok!(self.buf.write(fill.slice_to(len))); } if align == parse::AlignRight { - f(self); + if_ok!(f(self)); } + Ok(()) } } /// This is a function which calls are emitted to by the compiler itself to /// create the Argument structures that are passed into the `format` function. #[doc(hidden)] #[inline] -pub fn argument<'a, T>(f: extern "Rust" fn(&T, &mut Formatter), +pub fn argument<'a, T>(f: extern "Rust" fn(&T, &mut Formatter) -> Result, t: &'a T) -> Argument<'a> { unsafe { Argument { @@ -1055,41 +1060,41 @@ pub fn argumentuint<'a>(s: &'a uint) -> Argument<'a> { // Implementations of the core formatting traits impl Bool for bool { - fn fmt(b: &bool, f: &mut Formatter) { - String::fmt(&(if *b {"true"} else {"false"}), f); + fn fmt(b: &bool, f: &mut Formatter) -> Result { + String::fmt(&(if *b {"true"} else {"false"}), f) } } impl<'a, T: str::Str> String for T { - fn fmt(s: &T, f: &mut Formatter) { - f.pad(s.as_slice()); + fn fmt(s: &T, f: &mut Formatter) -> Result { + f.pad(s.as_slice()) } } impl Char for char { - fn fmt(c: &char, f: &mut Formatter) { + fn fmt(c: &char, f: &mut Formatter) -> Result { let mut utf8 = [0u8, ..4]; let amt = c.encode_utf8(utf8); let s: &str = unsafe { cast::transmute(utf8.slice_to(amt)) }; - String::fmt(&s, f); + String::fmt(&s, f) } } macro_rules! int_base(($ty:ident, $into:ident, $base:expr, $name:ident, $prefix:expr) => { impl $name for $ty { - fn fmt(c: &$ty, f: &mut Formatter) { + fn fmt(c: &$ty, f: &mut Formatter) -> Result { ::$into::to_str_bytes(*c as $into, $base, |buf| { - f.pad_integral(buf, $prefix, true); + f.pad_integral(buf, $prefix, true) }) } } }) macro_rules! upper_hex(($ty:ident, $into:ident) => { impl UpperHex for $ty { - fn fmt(c: &$ty, f: &mut Formatter) { + fn fmt(c: &$ty, f: &mut Formatter) -> Result { ::$into::to_str_bytes(*c as $into, 16, |buf| { - upperhex(buf, f); + upperhex(buf, f) }) } } @@ -1097,7 +1102,7 @@ macro_rules! upper_hex(($ty:ident, $into:ident) => { // Not sure why, but this causes an "unresolved enum variant, struct or const" // when inlined into the above macro... #[doc(hidden)] -pub fn upperhex(buf: &[u8], f: &mut Formatter) { +pub fn upperhex(buf: &[u8], f: &mut Formatter) -> Result { let mut local = [0u8, ..16]; for i in ::iter::range(0, buf.len()) { local[i] = match buf[i] as char { @@ -1105,16 +1110,16 @@ pub fn upperhex(buf: &[u8], f: &mut Formatter) { c => c as u8, } } - f.pad_integral(local.slice_to(buf.len()), "0x", true); + f.pad_integral(local.slice_to(buf.len()), "0x", true) } macro_rules! integer(($signed:ident, $unsigned:ident) => { // Signed is special because it actuall emits the negative sign, // nothing else should do that, however. impl Signed for $signed { - fn fmt(c: &$signed, f: &mut Formatter) { + fn fmt(c: &$signed, f: &mut Formatter) -> Result { ::$unsigned::to_str_bytes(c.abs() as $unsigned, 10, |buf| { - f.pad_integral(buf, "", *c >= 0); + f.pad_integral(buf, "", *c >= 0) }) } } @@ -1138,35 +1143,35 @@ integer!(i64, u64) macro_rules! floating(($ty:ident) => { impl Float for $ty { - fn fmt(f: &$ty, fmt: &mut Formatter) { + fn fmt(f: &$ty, fmt: &mut Formatter) -> Result { // FIXME: this shouldn't perform an allocation let s = match fmt.precision { Some(i) => ::$ty::to_str_exact(f.abs(), i), None => ::$ty::to_str_digits(f.abs(), 6) }; - fmt.pad_integral(s.as_bytes(), "", *f >= 0.0); + fmt.pad_integral(s.as_bytes(), "", *f >= 0.0) } } impl LowerExp for $ty { - fn fmt(f: &$ty, fmt: &mut Formatter) { + fn fmt(f: &$ty, fmt: &mut Formatter) -> Result { // FIXME: this shouldn't perform an allocation let s = match fmt.precision { Some(i) => ::$ty::to_str_exp_exact(f.abs(), i, false), None => ::$ty::to_str_exp_digits(f.abs(), 6, false) }; - fmt.pad_integral(s.as_bytes(), "", *f >= 0.0); + fmt.pad_integral(s.as_bytes(), "", *f >= 0.0) } } impl UpperExp for $ty { - fn fmt(f: &$ty, fmt: &mut Formatter) { + fn fmt(f: &$ty, fmt: &mut Formatter) -> Result { // FIXME: this shouldn't perform an allocation let s = match fmt.precision { Some(i) => ::$ty::to_str_exp_exact(f.abs(), i, true), None => ::$ty::to_str_exp_digits(f.abs(), 6, true) }; - fmt.pad_integral(s.as_bytes(), "", *f >= 0.0); + fmt.pad_integral(s.as_bytes(), "", *f >= 0.0) } } }) @@ -1174,39 +1179,41 @@ floating!(f32) floating!(f64) impl<T> Poly for T { - fn fmt(t: &T, f: &mut Formatter) { + fn fmt(t: &T, f: &mut Formatter) -> Result { match (f.width, f.precision) { (None, None) => { - repr::write_repr(f.buf, t); + repr::write_repr(f.buf, t) } // If we have a specified width for formatting, then we have to make // this allocation of a new string _ => { let s = repr::repr_to_str(t); - f.pad(s); + f.pad(s) } } } } impl<T> Pointer for *T { - fn fmt(t: &*T, f: &mut Formatter) { + fn fmt(t: &*T, f: &mut Formatter) -> Result { f.flags |= 1 << (parse::FlagAlternate as uint); ::uint::to_str_bytes(*t as uint, 16, |buf| { - f.pad_integral(buf, "0x", true); + f.pad_integral(buf, "0x", true) }) } } impl<T> Pointer for *mut T { - fn fmt(t: &*mut T, f: &mut Formatter) { Pointer::fmt(&(*t as *T), f) } + fn fmt(t: &*mut T, f: &mut Formatter) -> Result { + Pointer::fmt(&(*t as *T), f) + } } // Implementation of Show for various core types macro_rules! delegate(($ty:ty to $other:ident) => { impl<'a> Show for $ty { - fn fmt(me: &$ty, f: &mut Formatter) { + fn fmt(me: &$ty, f: &mut Formatter) -> Result { $other::fmt(me, f) } } @@ -1229,10 +1236,10 @@ delegate!(f32 to Float) delegate!(f64 to Float) impl<T> Show for *T { - fn fmt(me: &*T, f: &mut Formatter) { Pointer::fmt(me, f) } + fn fmt(me: &*T, f: &mut Formatter) -> Result { Pointer::fmt(me, f) } } impl<T> Show for *mut T { - fn fmt(me: &*mut T, f: &mut Formatter) { Pointer::fmt(me, f) } + fn fmt(me: &*mut T, f: &mut Formatter) -> Result { Pointer::fmt(me, f) } } // If you expected tests to be here, look instead at the run-pass/ifmt.rs test, diff --git a/src/libstd/hash.rs b/src/libstd/hash.rs index 1444f9b4129..4163d1e0c96 100644 --- a/src/libstd/hash.rs +++ b/src/libstd/hash.rs @@ -27,13 +27,14 @@ #[allow(missing_doc)]; use container::Container; +use io::{Writer, IoResult}; use iter::Iterator; +use num::ToStrRadix; use option::{Some, None}; -use io::Writer; +use result::Ok; use str::OwnedStr; use to_bytes::IterBytes; use vec::ImmutableVector; -use num::ToStrRadix; // Alias `SipState` to `State`. pub use State = hash::SipState; @@ -164,7 +165,7 @@ macro_rules! compress ( impl Writer for SipState { // Methods for io::writer #[inline] - fn write(&mut self, msg: &[u8]) { + fn write(&mut self, msg: &[u8]) -> IoResult<()> { let length = msg.len(); self.length += length; @@ -180,7 +181,7 @@ impl Writer for SipState { t += 1; } self.ntail += length; - return; + return Ok(()) } let mut t = 0; @@ -222,17 +223,14 @@ impl Writer for SipState { t += 1 } self.ntail = left; - } - - fn flush(&mut self) { - // No-op + Ok(()) } } impl Streaming for SipState { #[inline] fn input(&mut self, buf: &[u8]) { - self.write(buf); + self.write(buf).unwrap(); } #[inline] diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 64e42c5480f..256f9d325f3 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -11,10 +11,11 @@ //! Buffering wrappers for I/O traits use container::Container; -use io::{Reader, Writer, Stream, Buffer, DEFAULT_BUF_SIZE}; +use io::{Reader, Writer, Stream, Buffer, DEFAULT_BUF_SIZE, IoResult}; use iter::ExactSize; use num; -use option::{Option, Some, None}; +use option::{Some, None}; +use result::{Ok, Err}; use vec::{OwnedVector, ImmutableVector, MutableVector}; use vec; @@ -30,14 +31,13 @@ use vec; /// ```rust /// use std::io::{BufferedReader, File}; /// -/// # let _g = ::std::io::ignore_io_error(); /// let file = File::open(&Path::new("message.txt")); /// let mut reader = BufferedReader::new(file); /// /// let mut buf = [0, ..100]; /// match reader.read(buf) { -/// Some(nread) => println!("Read {} bytes", nread), -/// None => println!("At the end of the file!") +/// Ok(nread) => println!("Read {} bytes", nread), +/// Err(e) => println!("error reading: {}", e) /// } /// ``` pub struct BufferedReader<R> { @@ -86,17 +86,12 @@ impl<R: Reader> BufferedReader<R> { } impl<R: Reader> Buffer for BufferedReader<R> { - fn fill<'a>(&'a mut self) -> &'a [u8] { + fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]> { if self.pos == self.cap { - match self.inner.read(self.buf) { - Some(cap) => { - self.pos = 0; - self.cap = cap; - } - None => { self.eof = true; } - } + self.cap = if_ok!(self.inner.read(self.buf)); + self.pos = 0; } - return self.buf.slice(self.pos, self.cap); + Ok(self.buf.slice(self.pos, self.cap)) } fn consume(&mut self, amt: uint) { @@ -106,18 +101,15 @@ impl<R: Reader> Buffer for BufferedReader<R> { } impl<R: Reader> Reader for BufferedReader<R> { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { let nread = { - let available = self.fill(); + let available = if_ok!(self.fill()); let nread = num::min(available.len(), buf.len()); vec::bytes::copy_memory(buf, available.slice_to(nread)); nread }; self.pos += nread; - if nread == 0 && buf.len() != 0 && self.eof { - return None; - } - Some(nread) + Ok(nread) } } @@ -128,9 +120,9 @@ impl<R: Reader> Reader for BufferedReader<R> { /// # Example /// /// ```rust +/// # #[allow(unused_must_use)]; /// use std::io::{BufferedWriter, File}; /// -/// # let _g = ::std::io::ignore_io_error(); /// let file = File::open(&Path::new("message.txt")); /// let mut writer = BufferedWriter::new(file); /// @@ -161,10 +153,13 @@ impl<W: Writer> BufferedWriter<W> { BufferedWriter::with_capacity(DEFAULT_BUF_SIZE, inner) } - fn flush_buf(&mut self) { + fn flush_buf(&mut self) -> IoResult<()> { if self.pos != 0 { - self.inner.write(self.buf.slice_to(self.pos)); + let ret = self.inner.write(self.buf.slice_to(self.pos)); self.pos = 0; + ret + } else { + Ok(()) } } @@ -178,29 +173,30 @@ impl<W: Writer> BufferedWriter<W> { /// /// The buffer is flushed before returning the writer. pub fn unwrap(mut self) -> W { - self.flush_buf(); + // FIXME: is failing the right thing to do if flushing fails? + self.flush_buf().unwrap(); self.inner } } impl<W: Writer> Writer for BufferedWriter<W> { - fn write(&mut self, buf: &[u8]) { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { if self.pos + buf.len() > self.buf.len() { - self.flush_buf(); + if_ok!(self.flush_buf()); } if buf.len() > self.buf.len() { - self.inner.write(buf); + self.inner.write(buf) } else { let dst = self.buf.mut_slice_from(self.pos); vec::bytes::copy_memory(dst, buf); self.pos += buf.len(); + Ok(()) } } - fn flush(&mut self) { - self.flush_buf(); - self.inner.flush(); + fn flush(&mut self) -> IoResult<()> { + self.flush_buf().and_then(|()| self.inner.flush()) } } @@ -234,18 +230,19 @@ impl<W: Writer> LineBufferedWriter<W> { } impl<W: Writer> Writer for LineBufferedWriter<W> { - fn write(&mut self, buf: &[u8]) { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { match buf.iter().rposition(|&b| b == '\n' as u8) { Some(i) => { - self.inner.write(buf.slice_to(i + 1)); - self.inner.flush(); - self.inner.write(buf.slice_from(i + 1)); + if_ok!(self.inner.write(buf.slice_to(i + 1))); + if_ok!(self.inner.flush()); + if_ok!(self.inner.write(buf.slice_from(i + 1))); + Ok(()) } None => self.inner.write(buf), } } - fn flush(&mut self) { self.inner.flush() } + fn flush(&mut self) -> IoResult<()> { self.inner.flush() } } struct InternalBufferedWriter<W>(BufferedWriter<W>); @@ -258,7 +255,9 @@ impl<W> InternalBufferedWriter<W> { } impl<W: Reader> Reader for InternalBufferedWriter<W> { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.get_mut_ref().inner.read(buf) } + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { + self.get_mut_ref().inner.read(buf) + } } /// Wraps a Stream and buffers input and output to and from it @@ -268,9 +267,9 @@ impl<W: Reader> Reader for InternalBufferedWriter<W> { /// # Example /// /// ```rust +/// # #[allow(unused_must_use)]; /// use std::io::{BufferedStream, File}; /// -/// # let _g = ::std::io::ignore_io_error(); /// let file = File::open(&Path::new("message.txt")); /// let mut stream = BufferedStream::new(file); /// @@ -279,8 +278,8 @@ impl<W: Reader> Reader for InternalBufferedWriter<W> { /// /// let mut buf = [0, ..100]; /// match stream.read(buf) { -/// Some(nread) => println!("Read {} bytes", nread), -/// None => println!("At the end of the stream!") +/// Ok(nread) => println!("Read {} bytes", nread), +/// Err(e) => println!("error reading: {}", e) /// } /// ``` pub struct BufferedStream<S> { @@ -326,17 +325,23 @@ impl<S: Stream> BufferedStream<S> { } impl<S: Stream> Buffer for BufferedStream<S> { - fn fill<'a>(&'a mut self) -> &'a [u8] { self.inner.fill() } + fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]> { self.inner.fill() } fn consume(&mut self, amt: uint) { self.inner.consume(amt) } } impl<S: Stream> Reader for BufferedStream<S> { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.inner.read(buf) } + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { + self.inner.read(buf) + } } impl<S: Stream> Writer for BufferedStream<S> { - fn write(&mut self, buf: &[u8]) { self.inner.inner.get_mut_ref().write(buf) } - fn flush(&mut self) { self.inner.inner.get_mut_ref().flush() } + fn write(&mut self, buf: &[u8]) -> IoResult<()> { + self.inner.inner.get_mut_ref().write(buf) + } + fn flush(&mut self) -> IoResult<()> { + self.inner.inner.get_mut_ref().flush() + } } #[cfg(test)] @@ -354,13 +359,13 @@ mod test { pub struct NullStream; impl Reader for NullStream { - fn read(&mut self, _: &mut [u8]) -> Option<uint> { - None + fn read(&mut self, _: &mut [u8]) -> io::IoResult<uint> { + Err(io::standard_error(io::EndOfFile)) } } impl Writer for NullStream { - fn write(&mut self, _: &[u8]) { } + fn write(&mut self, _: &[u8]) -> io::IoResult<()> { Ok(()) } } /// A dummy reader intended at testing short-reads propagation. @@ -369,8 +374,11 @@ mod test { } impl Reader for ShortReader { - fn read(&mut self, _: &mut [u8]) -> Option<uint> { - self.lengths.shift() + fn read(&mut self, _: &mut [u8]) -> io::IoResult<uint> { + match self.lengths.shift() { + Some(i) => Ok(i), + None => Err(io::standard_error(io::EndOfFile)) + } } } @@ -381,24 +389,24 @@ mod test { let mut buf = [0, 0, 0]; let nread = reader.read(buf); - assert_eq!(Some(2), nread); + assert_eq!(Ok(2), nread); assert_eq!([0, 1, 0], buf); let mut buf = [0]; let nread = reader.read(buf); - assert_eq!(Some(1), nread); + assert_eq!(Ok(1), nread); assert_eq!([2], buf); let mut buf = [0, 0, 0]; let nread = reader.read(buf); - assert_eq!(Some(1), nread); + assert_eq!(Ok(1), nread); assert_eq!([3, 0, 0], buf); let nread = reader.read(buf); - assert_eq!(Some(1), nread); + assert_eq!(Ok(1), nread); assert_eq!([4, 0, 0], buf); - assert_eq!(None, reader.read(buf)); + assert!(reader.read(buf).is_err()); } #[test] @@ -406,35 +414,35 @@ mod test { let inner = MemWriter::new(); let mut writer = BufferedWriter::with_capacity(2, inner); - writer.write([0, 1]); + writer.write([0, 1]).unwrap(); assert_eq!([], writer.get_ref().get_ref()); - writer.write([2]); + writer.write([2]).unwrap(); assert_eq!([0, 1], writer.get_ref().get_ref()); - writer.write([3]); + writer.write([3]).unwrap(); assert_eq!([0, 1], writer.get_ref().get_ref()); - writer.flush(); + writer.flush().unwrap(); assert_eq!([0, 1, 2, 3], writer.get_ref().get_ref()); - writer.write([4]); - writer.write([5]); + writer.write([4]).unwrap(); + writer.write([5]).unwrap(); assert_eq!([0, 1, 2, 3], writer.get_ref().get_ref()); - writer.write([6]); + writer.write([6]).unwrap(); assert_eq!([0, 1, 2, 3, 4, 5], writer.get_ref().get_ref()); - writer.write([7, 8]); + writer.write([7, 8]).unwrap(); assert_eq!([0, 1, 2, 3, 4, 5, 6], writer.get_ref().get_ref()); - writer.write([9, 10, 11]); + writer.write([9, 10, 11]).unwrap(); assert_eq!([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], writer.get_ref().get_ref()); - writer.flush(); + writer.flush().unwrap(); assert_eq!([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], writer.get_ref().get_ref()); } @@ -442,7 +450,7 @@ mod test { #[test] fn test_buffered_writer_inner_flushes() { let mut w = BufferedWriter::with_capacity(3, MemWriter::new()); - w.write([0, 1]); + w.write([0, 1]).unwrap(); assert_eq!([], w.get_ref().get_ref()); let w = w.unwrap(); assert_eq!([0, 1], w.get_ref()); @@ -455,47 +463,49 @@ mod test { struct S; impl io::Writer for S { - fn write(&mut self, _: &[u8]) {} + fn write(&mut self, _: &[u8]) -> io::IoResult<()> { Ok(()) } } impl io::Reader for S { - fn read(&mut self, _: &mut [u8]) -> Option<uint> { None } + fn read(&mut self, _: &mut [u8]) -> io::IoResult<uint> { + Err(io::standard_error(io::EndOfFile)) + } } let mut stream = BufferedStream::new(S); let mut buf = []; - stream.read(buf); - stream.write(buf); - stream.flush(); + assert!(stream.read(buf).is_err()); + stream.write(buf).unwrap(); + stream.flush().unwrap(); } #[test] fn test_read_until() { let inner = MemReader::new(~[0, 1, 2, 1, 0]); let mut reader = BufferedReader::with_capacity(2, inner); - assert_eq!(reader.read_until(0), Some(~[0])); - assert_eq!(reader.read_until(2), Some(~[1, 2])); - assert_eq!(reader.read_until(1), Some(~[1])); - assert_eq!(reader.read_until(8), Some(~[0])); - assert_eq!(reader.read_until(9), None); + assert_eq!(reader.read_until(0), Ok(~[0])); + assert_eq!(reader.read_until(2), Ok(~[1, 2])); + assert_eq!(reader.read_until(1), Ok(~[1])); + assert_eq!(reader.read_until(8), Ok(~[0])); + assert!(reader.read_until(9).is_err()); } #[test] fn test_line_buffer() { let mut writer = LineBufferedWriter::new(MemWriter::new()); - writer.write([0]); + writer.write([0]).unwrap(); assert_eq!(writer.get_ref().get_ref(), []); - writer.write([1]); + writer.write([1]).unwrap(); assert_eq!(writer.get_ref().get_ref(), []); - writer.flush(); + writer.flush().unwrap(); assert_eq!(writer.get_ref().get_ref(), [0, 1]); - writer.write([0, '\n' as u8, 1, '\n' as u8, 2]); + writer.write([0, '\n' as u8, 1, '\n' as u8, 2]).unwrap(); assert_eq!(writer.get_ref().get_ref(), [0, 1, 0, '\n' as u8, 1, '\n' as u8]); - writer.flush(); + writer.flush().unwrap(); assert_eq!(writer.get_ref().get_ref(), [0, 1, 0, '\n' as u8, 1, '\n' as u8, 2]); - writer.write([3, '\n' as u8]); + writer.write([3, '\n' as u8]).unwrap(); assert_eq!(writer.get_ref().get_ref(), [0, 1, 0, '\n' as u8, 1, '\n' as u8, 2, 3, '\n' as u8]); } @@ -504,10 +514,10 @@ mod test { fn test_read_line() { let in_buf = MemReader::new(bytes!("a\nb\nc").to_owned()); let mut reader = BufferedReader::with_capacity(2, in_buf); - assert_eq!(reader.read_line(), Some(~"a\n")); - assert_eq!(reader.read_line(), Some(~"b\n")); - assert_eq!(reader.read_line(), Some(~"c")); - assert_eq!(reader.read_line(), None); + assert_eq!(reader.read_line(), Ok(~"a\n")); + assert_eq!(reader.read_line(), Ok(~"b\n")); + assert_eq!(reader.read_line(), Ok(~"c")); + assert!(reader.read_line().is_err()); } #[test] @@ -526,20 +536,20 @@ mod test { let inner = ShortReader{lengths: ~[0, 1, 2, 0, 1, 0]}; let mut reader = BufferedReader::new(inner); let mut buf = [0, 0]; - assert_eq!(reader.read(buf), Some(0)); - assert_eq!(reader.read(buf), Some(1)); - assert_eq!(reader.read(buf), Some(2)); - assert_eq!(reader.read(buf), Some(0)); - assert_eq!(reader.read(buf), Some(1)); - assert_eq!(reader.read(buf), Some(0)); - assert_eq!(reader.read(buf), None); + assert_eq!(reader.read(buf), Ok(0)); + assert_eq!(reader.read(buf), Ok(1)); + assert_eq!(reader.read(buf), Ok(2)); + assert_eq!(reader.read(buf), Ok(0)); + assert_eq!(reader.read(buf), Ok(1)); + assert_eq!(reader.read(buf), Ok(0)); + assert!(reader.read(buf).is_err()); } #[test] fn read_char_buffered() { let buf = [195u8, 159u8]; let mut reader = BufferedReader::with_capacity(1, BufReader::new(buf)); - assert_eq!(reader.read_char(), Some('ß')); + assert_eq!(reader.read_char(), Ok('ß')); } #[bench] diff --git a/src/libstd/io/comm_adapters.rs b/src/libstd/io/comm_adapters.rs index 1eaa752d2a3..6ed588ac69f 100644 --- a/src/libstd/io/comm_adapters.rs +++ b/src/libstd/io/comm_adapters.rs @@ -14,7 +14,7 @@ use comm::{Port, Chan}; use cmp; use io; use option::{None, Option, Some}; -use super::{Reader, Writer}; +use super::{Reader, Writer, IoResult}; use vec::{bytes, CloneableVector, MutableVector, ImmutableVector}; /// Allows reading from a port. @@ -49,7 +49,7 @@ impl PortReader { } impl Reader for PortReader { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { let mut num_read = 0; loop { match self.buf { @@ -71,10 +71,9 @@ impl Reader for PortReader { self.closed = self.buf.is_none(); } if self.closed && num_read == 0 { - io::io_error::cond.raise(io::standard_error(io::EndOfFile)); - None + Err(io::standard_error(io::EndOfFile)) } else { - Some(num_read) + Ok(num_read) } } } @@ -98,13 +97,15 @@ impl ChanWriter { } impl Writer for ChanWriter { - fn write(&mut self, buf: &[u8]) { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { if !self.chan.try_send(buf.to_owned()) { - io::io_error::cond.raise(io::IoError { + Err(io::IoError { kind: io::BrokenPipe, desc: "Pipe closed", detail: None - }); + }) + } else { + Ok(()) } } } @@ -132,36 +133,28 @@ mod test { let mut buf = ~[0u8, ..3]; - assert_eq!(Some(0), reader.read([])); + assert_eq!(Ok(0), reader.read([])); - assert_eq!(Some(3), reader.read(buf)); + assert_eq!(Ok(3), reader.read(buf)); assert_eq!(~[1,2,3], buf); - assert_eq!(Some(3), reader.read(buf)); + assert_eq!(Ok(3), reader.read(buf)); assert_eq!(~[4,5,6], buf); - assert_eq!(Some(2), reader.read(buf)); + assert_eq!(Ok(2), reader.read(buf)); assert_eq!(~[7,8,6], buf); - let mut err = None; - let result = io::io_error::cond.trap(|io::standard_error(k, _, _)| { - err = Some(k) - }).inside(|| { - reader.read(buf) - }); - assert_eq!(Some(io::EndOfFile), err); - assert_eq!(None, result); + match reader.read(buf) { + Ok(..) => fail!(), + Err(e) => assert_eq!(e.kind, io::EndOfFile), + } assert_eq!(~[7,8,6], buf); // Ensure it continues to fail in the same way. - err = None; - let result = io::io_error::cond.trap(|io::standard_error(k, _, _)| { - err = Some(k) - }).inside(|| { - reader.read(buf) - }); - assert_eq!(Some(io::EndOfFile), err); - assert_eq!(None, result); + match reader.read(buf) { + Ok(..) => fail!(), + Err(e) => assert_eq!(e.kind, io::EndOfFile), + } assert_eq!(~[7,8,6], buf); } @@ -169,18 +162,15 @@ mod test { fn test_chan_writer() { let (port, chan) = Chan::new(); let mut writer = ChanWriter::new(chan); - writer.write_be_u32(42); + writer.write_be_u32(42).unwrap(); let wanted = ~[0u8, 0u8, 0u8, 42u8]; let got = task::try(proc() { port.recv() }).unwrap(); assert_eq!(wanted, got); - let mut err = None; - io::io_error::cond.trap(|io::IoError { kind, .. } | { - err = Some(kind) - }).inside(|| { - writer.write_u8(1) - }); - assert_eq!(Some(io::BrokenPipe), err); + match writer.write_u8(1) { + Ok(..) => fail!(), + Err(e) => assert_eq!(e.kind, io::BrokenPipe), + } } } diff --git a/src/libstd/io/extensions.rs b/src/libstd/io/extensions.rs index 548dc3efe92..49d51cbb26f 100644 --- a/src/libstd/io/extensions.rs +++ b/src/libstd/io/extensions.rs @@ -46,7 +46,7 @@ impl<'r, R: Reader> Bytes<'r, R> { impl<'r, R: Reader> Iterator<u8> for Bytes<'r, R> { #[inline] fn next(&mut self) -> Option<u8> { - self.reader.read_byte() + self.reader.read_byte().ok() } } @@ -125,23 +125,22 @@ pub fn u64_from_be_bytes(data: &[u8], #[cfg(test)] mod test { - use unstable::finally::Finally; use prelude::*; + use io; use io::{MemReader, MemWriter}; - use io::{io_error, placeholder_error}; struct InitialZeroByteReader { count: int, } impl Reader for InitialZeroByteReader { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> { if self.count == 0 { self.count = 1; - Some(0) + Ok(0) } else { buf[0] = 10; - Some(1) + Ok(1) } } } @@ -149,17 +148,16 @@ mod test { struct EofReader; impl Reader for EofReader { - fn read(&mut self, _: &mut [u8]) -> Option<uint> { - None + fn read(&mut self, _: &mut [u8]) -> io::IoResult<uint> { + Err(io::standard_error(io::EndOfFile)) } } struct ErroringReader; impl Reader for ErroringReader { - fn read(&mut self, _: &mut [u8]) -> Option<uint> { - io_error::cond.raise(placeholder_error()); - None + fn read(&mut self, _: &mut [u8]) -> io::IoResult<uint> { + Err(io::standard_error(io::InvalidInput)) } } @@ -168,16 +166,16 @@ mod test { } impl Reader for PartialReader { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> { if self.count == 0 { self.count = 1; buf[0] = 10; buf[1] = 11; - Some(2) + Ok(2) } else { buf[0] = 12; buf[1] = 13; - Some(2) + Ok(2) } } } @@ -187,14 +185,13 @@ mod test { } impl Reader for ErroringLaterReader { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> { if self.count == 0 { self.count = 1; buf[0] = 10; - Some(1) + Ok(1) } else { - io_error::cond.raise(placeholder_error()); - None + Err(io::standard_error(io::InvalidInput)) } } } @@ -204,19 +201,19 @@ mod test { } impl Reader for ThreeChunkReader { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> { if self.count == 0 { self.count = 1; buf[0] = 10; buf[1] = 11; - Some(2) + Ok(2) } else if self.count == 1 { self.count = 2; buf[0] = 12; buf[1] = 13; - Some(2) + Ok(2) } else { - None + Err(io::standard_error(io::EndOfFile)) } } } @@ -225,7 +222,7 @@ mod test { fn read_byte() { let mut reader = MemReader::new(~[10]); let byte = reader.read_byte(); - assert!(byte == Some(10)); + assert!(byte == Ok(10)); } #[test] @@ -234,24 +231,21 @@ mod test { count: 0, }; let byte = reader.read_byte(); - assert!(byte == Some(10)); + assert!(byte == Ok(10)); } #[test] fn read_byte_eof() { let mut reader = EofReader; let byte = reader.read_byte(); - assert!(byte == None); + assert!(byte.is_err()); } #[test] fn read_byte_error() { let mut reader = ErroringReader; - io_error::cond.trap(|_| { - }).inside(|| { - let byte = reader.read_byte(); - assert!(byte == None); - }); + let byte = reader.read_byte(); + assert!(byte.is_err()); } #[test] @@ -267,23 +261,21 @@ mod test { fn bytes_eof() { let mut reader = EofReader; let byte = reader.bytes().next(); - assert!(byte == None); + assert!(byte.is_none()); } #[test] fn bytes_error() { let mut reader = ErroringReader; let mut it = reader.bytes(); - io_error::cond.trap(|_| ()).inside(|| { - let byte = it.next(); - assert!(byte == None); - }) + let byte = it.next(); + assert!(byte.is_none()); } #[test] fn read_bytes() { let mut reader = MemReader::new(~[10, 11, 12, 13]); - let bytes = reader.read_bytes(4); + let bytes = reader.read_bytes(4).unwrap(); assert!(bytes == ~[10, 11, 12, 13]); } @@ -292,24 +284,21 @@ mod test { let mut reader = PartialReader { count: 0, }; - let bytes = reader.read_bytes(4); + let bytes = reader.read_bytes(4).unwrap(); assert!(bytes == ~[10, 11, 12, 13]); } #[test] fn read_bytes_eof() { let mut reader = MemReader::new(~[10, 11]); - io_error::cond.trap(|_| { - }).inside(|| { - assert!(reader.read_bytes(4) == ~[10, 11]); - }) + assert!(reader.read_bytes(4).is_err()); } #[test] fn push_bytes() { let mut reader = MemReader::new(~[10, 11, 12, 13]); let mut buf = ~[8, 9]; - reader.push_bytes(&mut buf, 4); + reader.push_bytes(&mut buf, 4).unwrap(); assert!(buf == ~[8, 9, 10, 11, 12, 13]); } @@ -319,7 +308,7 @@ mod test { count: 0, }; let mut buf = ~[8, 9]; - reader.push_bytes(&mut buf, 4); + reader.push_bytes(&mut buf, 4).unwrap(); assert!(buf == ~[8, 9, 10, 11, 12, 13]); } @@ -327,11 +316,8 @@ mod test { fn push_bytes_eof() { let mut reader = MemReader::new(~[10, 11]); let mut buf = ~[8, 9]; - io_error::cond.trap(|_| { - }).inside(|| { - reader.push_bytes(&mut buf, 4); - assert!(buf == ~[8, 9, 10, 11]); - }) + assert!(reader.push_bytes(&mut buf, 4).is_err()); + assert!(buf == ~[8, 9, 10, 11]); } #[test] @@ -340,38 +326,16 @@ mod test { count: 0, }; let mut buf = ~[8, 9]; - io_error::cond.trap(|_| { } ).inside(|| { - reader.push_bytes(&mut buf, 4); - }); + assert!(reader.push_bytes(&mut buf, 4).is_err()); assert!(buf == ~[8, 9, 10]); } #[test] - #[should_fail] - #[ignore] // borrow issues with RefCell - fn push_bytes_fail_reset_len() { - // push_bytes unsafely sets the vector length. This is testing that - // upon failure the length is reset correctly. - let _reader = ErroringLaterReader { - count: 0, - }; - // FIXME (#7049): Figure out some other way to do this. - //let buf = RefCell::new(~[8, 9]); - (|| { - //reader.push_bytes(buf.borrow_mut().get(), 4); - }).finally(|| { - // NB: Using rtassert here to trigger abort on failure since this is a should_fail test - // FIXME: #7049 This fails because buf is still borrowed - //rtassert!(buf.borrow().get() == ~[8, 9, 10]); - }) - } - - #[test] fn read_to_end() { let mut reader = ThreeChunkReader { count: 0, }; - let buf = reader.read_to_end(); + let buf = reader.read_to_end().unwrap(); assert!(buf == ~[10, 11, 12, 13]); } @@ -381,7 +345,7 @@ mod test { let mut reader = ThreeChunkReader { count: 0, }; - let buf = reader.read_to_end(); + let buf = reader.read_to_end().unwrap(); assert!(buf == ~[10, 11]); } @@ -391,12 +355,12 @@ mod test { let mut writer = MemWriter::new(); for i in uints.iter() { - writer.write_le_u64(*i); + writer.write_le_u64(*i).unwrap(); } let mut reader = MemReader::new(writer.unwrap()); for i in uints.iter() { - assert!(reader.read_le_u64() == *i); + assert!(reader.read_le_u64().unwrap() == *i); } } @@ -407,12 +371,12 @@ mod test { let mut writer = MemWriter::new(); for i in uints.iter() { - writer.write_be_u64(*i); + writer.write_be_u64(*i).unwrap(); } let mut reader = MemReader::new(writer.unwrap()); for i in uints.iter() { - assert!(reader.read_be_u64() == *i); + assert!(reader.read_be_u64().unwrap() == *i); } } @@ -422,14 +386,14 @@ mod test { let mut writer = MemWriter::new(); for i in ints.iter() { - writer.write_be_i32(*i); + writer.write_be_i32(*i).unwrap(); } let mut reader = MemReader::new(writer.unwrap()); for i in ints.iter() { // this tests that the sign extension is working // (comparing the values as i32 would not test this) - assert!(reader.read_be_int_n(4) == *i as i64); + assert!(reader.read_be_int_n(4).unwrap() == *i as i64); } } @@ -439,10 +403,10 @@ mod test { let buf = ~[0x41, 0x02, 0x00, 0x00]; let mut writer = MemWriter::new(); - writer.write(buf); + writer.write(buf).unwrap(); let mut reader = MemReader::new(writer.unwrap()); - let f = reader.read_be_f32(); + let f = reader.read_be_f32().unwrap(); assert!(f == 8.1250); } @@ -451,12 +415,12 @@ mod test { let f:f32 = 8.1250; let mut writer = MemWriter::new(); - writer.write_be_f32(f); - writer.write_le_f32(f); + writer.write_be_f32(f).unwrap(); + writer.write_le_f32(f).unwrap(); let mut reader = MemReader::new(writer.unwrap()); - assert!(reader.read_be_f32() == 8.1250); - assert!(reader.read_le_f32() == 8.1250); + assert!(reader.read_be_f32().unwrap() == 8.1250); + assert!(reader.read_le_f32().unwrap() == 8.1250); } #[test] diff --git a/src/libstd/io/fs.rs b/src/libstd/io/fs.rs index 8904101dd05..ef1b1a56ec0 100644 --- a/src/libstd/io/fs.rs +++ b/src/libstd/io/fs.rs @@ -14,11 +14,11 @@ This module provides a set of functions and traits for working with regular files & directories on a filesystem. At the top-level of the module are a set of freestanding functions, associated -with various filesystem operations. They all operate on a `Path` object. +with various filesystem operations. They all operate on `Path` objects. All operations in this module, including those as part of `File` et al -block the task during execution. Most will raise `std::io::io_error` -conditions in the event of failure. +block the task during execution. In the event of failure, all functions/methods +will return an `IoResult` type with an `Err` value. Also included in this module is an implementation block on the `Path` object defined in `std::path::Path`. The impl adds useful methods about inspecting the @@ -27,21 +27,25 @@ particular bits of it, etc. # Example - use std::io::{File, fs}; +```rust +# #[allow(unused_must_use)]; +use std::io::{File, fs}; - let path = Path::new("foo.txt"); +let path = Path::new("foo.txt"); - // create the file, whether it exists or not - let mut file = File::create(&path); - file.write(bytes!("foobar")); +// create the file, whether it exists or not +let mut file = File::create(&path); +file.write(bytes!("foobar")); +# drop(file); - // open the file in read-only mode - let mut file = File::open(&path); - file.read_to_end(); +// open the file in read-only mode +let mut file = File::open(&path); +file.read_to_end(); - println!("{}", path.stat().size); - fs::symlink(&path, &Path::new("bar.txt")); - fs::unlink(&path); +println!("{}", path.stat().unwrap().size); +# drop(file); +fs::unlink(&path); +``` */ @@ -50,7 +54,7 @@ use clone::Clone; use iter::Iterator; use super::{Reader, Writer, Seek}; use super::{SeekStyle, Read, Write, Open, IoError, Truncate, - FileMode, FileAccess, FileStat, io_error, FilePermission}; + FileMode, FileAccess, FileStat, IoResult, FilePermission}; use rt::rtio::{RtioFileStream, IoFactory, LocalIo}; use io; use option::{Some, None, Option}; @@ -64,11 +68,12 @@ use vec::{OwnedVector, ImmutableVector}; /// Can be constructed via `File::open()`, `File::create()`, and /// `File::open_mode()`. /// -/// # Errors +/// # Error /// -/// This type will raise an io_error condition if operations are attempted against -/// it for which its underlying file descriptor was not configured at creation -/// time, via the `FileAccess` parameter to `File::open_mode()`. +/// This type will return errors as an `IoResult<T>` if operations are +/// attempted against it for which its underlying file descriptor was not +/// configured at creation time, via the `FileAccess` parameter to +/// `File::open_mode()`. pub struct File { priv fd: ~RtioFileStream, priv path: Path, @@ -81,22 +86,19 @@ impl File { /// /// # Example /// - /// use std::io::{File, io_error, Open, ReadWrite}; + /// ```rust,should_fail + /// use std::io::{File, Open, ReadWrite}; /// - /// let p = Path::new("/some/file/path.txt"); + /// let p = Path::new("/some/file/path.txt"); /// - /// io_error::cond.trap(|_| { - /// // hoo-boy... - /// }).inside(|| { - /// let file = match File::open_mode(&p, Open, ReadWrite) { - /// Some(s) => s, - /// None => fail!("whoops! I'm sure this raised, anyways..") - /// }; - /// // do some stuff with that file + /// let file = match File::open_mode(&p, Open, ReadWrite) { + /// Ok(f) => f, + /// Err(e) => fail!("file error: {}", e), + /// }; + /// // do some stuff with that file /// - /// // the file will be closed at the end of this block - /// }) - /// // .. + /// // the file will be closed at the end of this block + /// ``` /// /// `FileMode` and `FileAccess` provide information about the permissions /// context in which a given stream is created. More information about them @@ -106,12 +108,12 @@ impl File { /// /// Note that, with this function, a `File` is returned regardless of the /// access-limitations indicated by `FileAccess` (e.g. calling `write` on a - /// `File` opened as `Read` will raise an `io_error` condition at runtime). + /// `File` opened as `Read` will return an error at runtime). /// - /// # Errors + /// # Error /// - /// This function will raise an `io_error` condition under a number of - /// different circumstances, to include but not limited to: + /// This function will return an error under a number of different + /// circumstances, to include but not limited to: /// /// * Opening a file that does not exist with `Read` access. /// * Attempting to open a file with a `FileAccess` that the user lacks @@ -119,7 +121,7 @@ impl File { /// * Filesystem-level errors (full disk, etc) pub fn open_mode(path: &Path, mode: FileMode, - access: FileAccess) -> Option<File> { + access: FileAccess) -> IoResult<File> { LocalIo::maybe_raise(|io| { io.fs_open(&path.to_c_str(), mode, access).map(|fd| { File { @@ -139,10 +141,12 @@ impl File { /// /// # Example /// - /// use std::io::File; + /// ```rust + /// use std::io::File; /// - /// let contents = File::open(&Path::new("foo.txt")).read_to_end(); - pub fn open(path: &Path) -> Option<File> { + /// let contents = File::open(&Path::new("foo.txt")).read_to_end(); + /// ``` + pub fn open(path: &Path) -> IoResult<File> { File::open_mode(path, Open, Read) } @@ -154,11 +158,16 @@ impl File { /// /// # Example /// - /// use std::io::File; + /// ```rust + /// # #[allow(unused_must_use)]; + /// use std::io::File; /// - /// let mut f = File::create(&Path::new("foo.txt")); - /// f.write(bytes!("This is a sample file")); - pub fn create(path: &Path) -> Option<File> { + /// let mut f = File::create(&Path::new("foo.txt")); + /// f.write(bytes!("This is a sample file")); + /// # drop(f); + /// # ::std::io::fs::unlink(&Path::new("foo.txt")); + /// ``` + pub fn create(path: &Path) -> IoResult<File> { File::open_mode(path, Truncate, Write) } @@ -170,24 +179,16 @@ impl File { /// Synchronizes all modifications to this file to its permanent storage /// device. This will flush any internal buffers necessary to perform this /// operation. - /// - /// # Errors - /// - /// This function will raise on the `io_error` condition on failure. - pub fn fsync(&mut self) { - let _ = self.fd.fsync().map_err(|e| io_error::cond.raise(e)); + pub fn fsync(&mut self) -> IoResult<()> { + self.fd.fsync() } /// This function is similar to `fsync`, except that it may not synchronize /// file metadata to the filesystem. This is intended for use case which /// must synchronize content, but don't need the metadata on disk. The goal /// of this method is to reduce disk operations. - /// - /// # Errors - /// - /// This function will raise on the `io_error` condition on failure. - pub fn datasync(&mut self) { - let _ = self.fd.datasync().map_err(|e| io_error::cond.raise(e)); + pub fn datasync(&mut self) -> IoResult<()> { + self.fd.datasync() } /// Either truncates or extends the underlying file, updating the size of @@ -198,12 +199,8 @@ impl File { /// be shrunk. If it is greater than the current file's size, then the file /// will be extended to `size` and have all of the intermediate data filled /// in with 0s. - /// - /// # Errors - /// - /// On error, this function will raise on the `io_error` condition. - pub fn truncate(&mut self, size: i64) { - let _ = self.fd.truncate(size).map_err(|e| io_error::cond.raise(e)); + pub fn truncate(&mut self, size: i64) -> IoResult<()> { + self.fd.truncate(size) } /// Tests whether this stream has reached EOF. @@ -219,24 +216,25 @@ impl File { /// /// # Example /// -/// use std::io::fs; +/// ```rust +/// # #[allow(unused_must_use)]; +/// use std::io::fs; /// -/// let p = Path::new("/some/file/path.txt"); -/// fs::unlink(&p); -/// // if we made it here without failing, then the -/// // unlink operation was successful +/// let p = Path::new("/some/file/path.txt"); +/// fs::unlink(&p); +/// ``` /// /// Note that, just because an unlink call was successful, it is not /// guaranteed that a file is immediately deleted (e.g. depending on /// platform, other open file descriptors may prevent immediate removal) /// -/// # Errors +/// # Error /// -/// This function will raise an `io_error` condition if the path points to a -/// directory, the user lacks permissions to remove the file, or if some -/// other filesystem-level error occurs. -pub fn unlink(path: &Path) { - LocalIo::maybe_raise(|io| io.fs_unlink(&path.to_c_str())); +/// This function will return an error if the path points to a directory, the +/// user lacks permissions to remove the file, or if some other filesystem-level +/// error occurs. +pub fn unlink(path: &Path) -> IoResult<()> { + LocalIo::maybe_raise(|io| io.fs_unlink(&path.to_c_str())) } /// Given a path, query the file system to get information about a file, @@ -249,48 +247,25 @@ pub fn unlink(path: &Path) { /// /// # Example /// -/// use std::io; -/// use std::io::fs; +/// ```rust +/// use std::io::fs; /// -/// let p = Path::new("/some/file/path.txt"); -/// match io::result(|| fs::stat(&p)) { -/// Ok(stat) => { /* ... */ } -/// Err(e) => { /* handle error */ } -/// } +/// let p = Path::new("/some/file/path.txt"); +/// match fs::stat(&p) { +/// Ok(stat) => { /* ... */ } +/// Err(e) => { /* handle error */ } +/// } +/// ``` /// -/// # Errors +/// # Error /// -/// This call will raise an `io_error` condition if the user lacks the -/// requisite permissions to perform a `stat` call on the given path or if -/// there is no entry in the filesystem at the provided path. -pub fn stat(path: &Path) -> FileStat { +/// This call will return an error if the user lacks the requisite permissions +/// to perform a `stat` call on the given path or if there is no entry in the +/// filesystem at the provided path. +pub fn stat(path: &Path) -> IoResult<FileStat> { LocalIo::maybe_raise(|io| { io.fs_stat(&path.to_c_str()) - }).unwrap_or_else(dummystat) -} - -fn dummystat() -> FileStat { - FileStat { - path: Path::new(""), - size: 0, - kind: io::TypeFile, - perm: 0, - created: 0, - modified: 0, - accessed: 0, - unstable: io::UnstableFileStat { - device: 0, - inode: 0, - rdev: 0, - nlink: 0, - uid: 0, - gid: 0, - blksize: 0, - blocks: 0, - flags: 0, - gen: 0, - } - } + }) } /// Perform the same operation as the `stat` function, except that this @@ -298,31 +273,33 @@ fn dummystat() -> FileStat { /// information about the symlink file instead of the file that it points /// to. /// -/// # Errors +/// # Error /// /// See `stat` -pub fn lstat(path: &Path) -> FileStat { +pub fn lstat(path: &Path) -> IoResult<FileStat> { LocalIo::maybe_raise(|io| { io.fs_lstat(&path.to_c_str()) - }).unwrap_or_else(dummystat) + }) } /// Rename a file or directory to a new name. /// /// # Example /// -/// use std::io::fs; +/// ```rust +/// # #[allow(unused_must_use)]; +/// use std::io::fs; /// -/// fs::rename(&Path::new("foo"), &Path::new("bar")); -/// // Oh boy, nothing was raised! +/// fs::rename(&Path::new("foo"), &Path::new("bar")); +/// ``` /// -/// # Errors +/// # Error /// -/// Will raise an `io_error` condition if the provided `path` doesn't exist, -/// the process lacks permissions to view the contents, or if some other -/// intermittent I/O error occurs. -pub fn rename(from: &Path, to: &Path) { - LocalIo::maybe_raise(|io| io.fs_rename(&from.to_c_str(), &to.to_c_str())); +/// Will return an error if the provided `path` doesn't exist, the process lacks +/// permissions to view the contents, or if some other intermittent I/O error +/// occurs. +pub fn rename(from: &Path, to: &Path) -> IoResult<()> { + LocalIo::maybe_raise(|io| io.fs_rename(&from.to_c_str(), &to.to_c_str())) } /// Copies the contents of one file to another. This function will also @@ -333,15 +310,17 @@ pub fn rename(from: &Path, to: &Path) { /// /// # Example /// -/// use std::io::fs; +/// ```rust +/// # #[allow(unused_must_use)]; +/// use std::io::fs; /// -/// fs::copy(&Path::new("foo.txt"), &Path::new("bar.txt")); -/// // Oh boy, nothing was raised! +/// fs::copy(&Path::new("foo.txt"), &Path::new("bar.txt")); +/// ``` /// -/// # Errors +/// # Error /// -/// Will raise an `io_error` condition is the following situations, but is -/// not limited to just these cases: +/// Will return an error in the following situations, but is not limited to +/// just these cases: /// /// * The `from` path is not a file /// * The `from` file does not exist @@ -351,27 +330,29 @@ pub fn rename(from: &Path, to: &Path) { /// Note that this copy is not atomic in that once the destination is /// ensured to not exist, there is nothing preventing the destination from /// being created and then destroyed by this operation. -pub fn copy(from: &Path, to: &Path) { +pub fn copy(from: &Path, to: &Path) -> IoResult<()> { if !from.is_file() { - return io_error::cond.raise(IoError { + return Err(IoError { kind: io::MismatchedFileTypeForOperation, desc: "the source path is not an existing file", detail: None, - }); + }) } - let mut reader = match File::open(from) { Some(f) => f, None => return }; - let mut writer = match File::create(to) { Some(f) => f, None => return }; + let mut reader = if_ok!(File::open(from)); + let mut writer = if_ok!(File::create(to)); let mut buf = [0, ..io::DEFAULT_BUF_SIZE]; loop { - match reader.read(buf) { - Some(amt) => writer.write(buf.slice_to(amt)), - None => break - } + let amt = match reader.read(buf) { + Ok(n) => n, + Err(ref e) if e.kind == io::EndOfFile => { break } + Err(e) => return Err(e) + }; + if_ok!(writer.write(buf.slice_to(amt))); } - chmod(to, from.stat().perm) + chmod(to, if_ok!(from.stat()).perm) } /// Changes the permission mode bits found on a file or a directory. This @@ -379,61 +360,51 @@ pub fn copy(from: &Path, to: &Path) { /// /// # Example /// -/// use std::io; -/// use std::io::fs; +/// ```rust +/// # #[allow(unused_must_use)]; +/// use std::io; +/// use std::io::fs; /// -/// fs::chmod(&Path::new("file.txt"), io::UserFile); -/// fs::chmod(&Path::new("file.txt"), io::UserRead | io::UserWrite); -/// fs::chmod(&Path::new("dir"), io::UserDir); -/// fs::chmod(&Path::new("file.exe"), io::UserExec); +/// fs::chmod(&Path::new("file.txt"), io::UserFile); +/// fs::chmod(&Path::new("file.txt"), io::UserRead | io::UserWrite); +/// fs::chmod(&Path::new("dir"), io::UserDir); +/// fs::chmod(&Path::new("file.exe"), io::UserExec); +/// ``` /// -/// # Errors +/// # Error /// -/// If this function encounters an I/O error, it will raise on the `io_error` -/// condition. Some possible error situations are not having the permission to +/// If this function encounters an I/O error, it will return an `Err` value. +/// Some possible error situations are not having the permission to /// change the attributes of a file or the file not existing. -pub fn chmod(path: &Path, mode: io::FilePermission) { - LocalIo::maybe_raise(|io| io.fs_chmod(&path.to_c_str(), mode)); +pub fn chmod(path: &Path, mode: io::FilePermission) -> IoResult<()> { + LocalIo::maybe_raise(|io| io.fs_chmod(&path.to_c_str(), mode)) } /// Change the user and group owners of a file at the specified path. -/// -/// # Errors -/// -/// This function will raise on the `io_error` condition on failure. -pub fn chown(path: &Path, uid: int, gid: int) { - LocalIo::maybe_raise(|io| io.fs_chown(&path.to_c_str(), uid, gid)); +pub fn chown(path: &Path, uid: int, gid: int) -> IoResult<()> { + LocalIo::maybe_raise(|io| io.fs_chown(&path.to_c_str(), uid, gid)) } /// Creates a new hard link on the filesystem. The `dst` path will be a /// link pointing to the `src` path. Note that systems often require these /// two paths to both be located on the same filesystem. -/// -/// # Errors -/// -/// This function will raise on the `io_error` condition on failure. -pub fn link(src: &Path, dst: &Path) { - LocalIo::maybe_raise(|io| io.fs_link(&src.to_c_str(), &dst.to_c_str())); +pub fn link(src: &Path, dst: &Path) -> IoResult<()> { + LocalIo::maybe_raise(|io| io.fs_link(&src.to_c_str(), &dst.to_c_str())) } /// Creates a new symbolic link on the filesystem. The `dst` path will be a /// symlink pointing to the `src` path. -/// -/// # Errors -/// -/// This function will raise on the `io_error` condition on failure. -pub fn symlink(src: &Path, dst: &Path) { - LocalIo::maybe_raise(|io| io.fs_symlink(&src.to_c_str(), &dst.to_c_str())); +pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> { + LocalIo::maybe_raise(|io| io.fs_symlink(&src.to_c_str(), &dst.to_c_str())) } /// Reads a symlink, returning the file that the symlink points to. /// -/// # Errors +/// # Error /// -/// This function will raise on the `io_error` condition on failure. Failure -/// conditions include reading a file that does not exist or reading a file -/// which is not a symlink. -pub fn readlink(path: &Path) -> Option<Path> { +/// This function will return an error on failure. Failure conditions include +/// reading a file that does not exist or reading a file which is not a symlink. +pub fn readlink(path: &Path) -> IoResult<Path> { LocalIo::maybe_raise(|io| io.fs_readlink(&path.to_c_str())) } @@ -441,75 +412,85 @@ pub fn readlink(path: &Path) -> Option<Path> { /// /// # Example /// -/// use std::libc::S_IRWXU; -/// use std::io::fs; +/// ```rust +/// # #[allow(unused_must_use)]; +/// use std::io; +/// use std::io::fs; /// -/// let p = Path::new("/some/dir"); -/// fs::mkdir(&p, S_IRWXU as int); -/// // If we got here, our directory exists! Hooray! +/// let p = Path::new("/some/dir"); +/// fs::mkdir(&p, io::UserRWX); +/// ``` /// -/// # Errors +/// # Error /// -/// This call will raise an `io_error` condition if the user lacks permissions -/// to make a new directory at the provided path, or if the directory already -/// exists. -pub fn mkdir(path: &Path, mode: FilePermission) { - LocalIo::maybe_raise(|io| io.fs_mkdir(&path.to_c_str(), mode)); +/// This call will return an error if the user lacks permissions to make a new +/// directory at the provided path, or if the directory already exists. +pub fn mkdir(path: &Path, mode: FilePermission) -> IoResult<()> { + LocalIo::maybe_raise(|io| io.fs_mkdir(&path.to_c_str(), mode)) } /// Remove an existing, empty directory /// /// # Example /// -/// use std::io::fs; +/// ```rust +/// # #[allow(unused_must_use)]; +/// use std::io::fs; /// -/// let p = Path::new("/some/dir"); -/// fs::rmdir(&p); -/// // good riddance, you mean ol' directory +/// let p = Path::new("/some/dir"); +/// fs::rmdir(&p); +/// ``` /// -/// # Errors +/// # Error /// -/// This call will raise an `io_error` condition if the user lacks permissions -/// to remove the directory at the provided path, or if the directory isn't -/// empty. -pub fn rmdir(path: &Path) { - LocalIo::maybe_raise(|io| io.fs_rmdir(&path.to_c_str())); +/// This call will return an error if the user lacks permissions to remove the +/// directory at the provided path, or if the directory isn't empty. +pub fn rmdir(path: &Path) -> IoResult<()> { + LocalIo::maybe_raise(|io| io.fs_rmdir(&path.to_c_str())) } /// Retrieve a vector containing all entries within a provided directory /// /// # Example /// -/// use std::io::fs; -/// -/// // one possible implementation of fs::walk_dir only visiting files -/// fn visit_dirs(dir: &Path, cb: |&Path|) { -/// if dir.is_dir() { -/// let contents = fs::readdir(dir).unwrap(); -/// for entry in contents.iter() { -/// if entry.is_dir() { visit_dirs(entry, cb); } -/// else { cb(entry); } +/// ```rust +/// use std::io; +/// use std::io::fs; +/// +/// // one possible implementation of fs::walk_dir only visiting files +/// fn visit_dirs(dir: &Path, cb: |&Path|) -> io::IoResult<()> { +/// if dir.is_dir() { +/// let contents = if_ok!(fs::readdir(dir)); +/// for entry in contents.iter() { +/// if entry.is_dir() { +/// if_ok!(visit_dirs(entry, |p| cb(p))); +/// } else { +/// cb(entry); /// } /// } -/// else { fail!("nope"); } +/// Ok(()) +/// } else { +/// Err(io::standard_error(io::InvalidInput)) /// } +/// } +/// ``` /// -/// # Errors +/// # Error /// -/// Will raise an `io_error` condition if the provided `from` doesn't exist, -/// the process lacks permissions to view the contents or if the `path` points -/// at a non-directory file -pub fn readdir(path: &Path) -> ~[Path] { +/// Will return an error if the provided `from` doesn't exist, the process lacks +/// permissions to view the contents or if the `path` points at a non-directory +/// file +pub fn readdir(path: &Path) -> IoResult<~[Path]> { LocalIo::maybe_raise(|io| { io.fs_readdir(&path.to_c_str(), 0) - }).unwrap_or_else(|| ~[]) + }) } /// Returns an iterator which will recursively walk the directory structure /// rooted at `path`. The path given will not be iterated over, and this will /// perform iteration in a top-down order. -pub fn walk_dir(path: &Path) -> Directories { - Directories { stack: readdir(path) } +pub fn walk_dir(path: &Path) -> IoResult<Directories> { + Ok(Directories { stack: if_ok!(readdir(path)) }) } /// An iterator which walks over a directory @@ -522,7 +503,10 @@ impl Iterator<Path> for Directories { match self.stack.shift() { Some(path) => { if path.is_dir() { - self.stack.push_all_move(readdir(&path)); + match readdir(&path) { + Ok(dirs) => { self.stack.push_all_move(dirs); } + Err(..) => {} + } } Some(path) } @@ -534,19 +518,18 @@ impl Iterator<Path> for Directories { /// Recursively create a directory and all of its parent components if they /// are missing. /// -/// # Errors +/// # Error /// -/// This function will raise on the `io_error` condition if an error -/// happens, see `fs::mkdir` for more information about error conditions -/// and performance. -pub fn mkdir_recursive(path: &Path, mode: FilePermission) { +/// This function will return an `Err` value if an error happens, see +/// `fs::mkdir` for more information about error conditions and performance. +pub fn mkdir_recursive(path: &Path, mode: FilePermission) -> IoResult<()> { // tjc: if directory exists but with different permissions, // should we return false? if path.is_dir() { - return + return Ok(()) } if path.filename().is_some() { - mkdir_recursive(&path.dir_path(), mode); + if_ok!(mkdir_recursive(&path.dir_path(), mode)); } mkdir(path, mode) } @@ -554,92 +537,64 @@ pub fn mkdir_recursive(path: &Path, mode: FilePermission) { /// Removes a directory at this path, after removing all its contents. Use /// carefully! /// -/// # Errors +/// # Error /// -/// This function will raise on the `io_error` condition if an error -/// happens. See `file::unlink` and `fs::readdir` for possible error -/// conditions. -pub fn rmdir_recursive(path: &Path) { - let children = readdir(path); +/// This function will return an `Err` value if an error happens. See +/// `file::unlink` and `fs::readdir` for possible error conditions. +pub fn rmdir_recursive(path: &Path) -> IoResult<()> { + let children = if_ok!(readdir(path)); for child in children.iter() { if child.is_dir() { - rmdir_recursive(child); + if_ok!(rmdir_recursive(child)); } else { - unlink(child); + if_ok!(unlink(child)); } } // Directory should now be empty - rmdir(path); + rmdir(path) } /// Changes the timestamps for a file's last modification and access time. /// The file at the path specified will have its last access time set to /// `atime` and its modification time set to `mtime`. The times specified should /// be in milliseconds. -/// -/// # Errors -/// -/// This function will raise on the `io_error` condition if an error -/// happens. // FIXME(#10301) these arguments should not be u64 -pub fn change_file_times(path: &Path, atime: u64, mtime: u64) { - LocalIo::maybe_raise(|io| io.fs_utime(&path.to_c_str(), atime, mtime)); +pub fn change_file_times(path: &Path, atime: u64, mtime: u64) -> IoResult<()> { + LocalIo::maybe_raise(|io| io.fs_utime(&path.to_c_str(), atime, mtime)) } impl Reader for File { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { match self.fd.read(buf) { Ok(read) => { self.last_nread = read; match read { - 0 => None, - _ => Some(read as uint) + 0 => Err(io::standard_error(io::EndOfFile)), + _ => Ok(read as uint) } }, - Err(ioerr) => { - // EOF is indicated by returning None - if ioerr.kind != io::EndOfFile { - io_error::cond.raise(ioerr); - } - return None; - } + Err(e) => Err(e), } } } impl Writer for File { - fn write(&mut self, buf: &[u8]) { - match self.fd.write(buf) { - Ok(()) => (), - Err(ioerr) => { - io_error::cond.raise(ioerr); - } - } - } + fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.fd.write(buf) } } impl Seek for File { - fn tell(&self) -> u64 { - let res = self.fd.tell(); - match res { - Ok(cursor) => cursor, - Err(ioerr) => { - io_error::cond.raise(ioerr); - return -1; - } - } + fn tell(&self) -> IoResult<u64> { + self.fd.tell() } - fn seek(&mut self, pos: i64, style: SeekStyle) { + fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { match self.fd.seek(pos, style) { Ok(_) => { // successful seek resets EOF indicator self.last_nread = -1; - () - }, - Err(ioerr) => { - io_error::cond.raise(ioerr); + Ok(()) } + Err(e) => Err(e), } } } @@ -650,17 +605,17 @@ impl path::Path { /// Consult the `file::stat` documentation for more info. /// /// This call preserves identical runtime/error semantics with `file::stat`. - pub fn stat(&self) -> FileStat { stat(self) } + pub fn stat(&self) -> IoResult<FileStat> { stat(self) } /// Boolean value indicator whether the underlying file exists on the local /// filesystem. This will return true if the path points to either a /// directory or a file. /// - /// # Errors + /// # Error /// /// Will not raise a condition pub fn exists(&self) -> bool { - io::result(|| self.stat()).is_ok() + self.stat().is_ok() } /// Whether the underlying implementation (be it a file path, or something @@ -668,11 +623,11 @@ impl path::Path { /// to non-existent locations or directories or other non-regular files /// (named pipes, etc). /// - /// # Errors + /// # Error /// /// Will not raise a condition pub fn is_file(&self) -> bool { - match io::result(|| self.stat()) { + match self.stat() { Ok(s) => s.kind == io::TypeFile, Err(..) => false } @@ -683,11 +638,11 @@ impl path::Path { /// Will return false for paths to non-existent locations or if the item is /// not a directory (eg files, named pipes, links, etc) /// - /// # Errors + /// # Error /// /// Will not raise a condition pub fn is_dir(&self) -> bool { - match io::result(|| self.stat()) { + match self.stat() { Ok(s) => s.kind == io::TypeDirectory, Err(..) => false } @@ -698,8 +653,7 @@ impl path::Path { #[allow(unused_imports)] mod test { use prelude::*; - use io::{SeekSet, SeekCur, SeekEnd, io_error, Read, Open, - ReadWrite}; + use io::{SeekSet, SeekCur, SeekEnd, Read, Open, ReadWrite}; use io; use str; use io::fs::{File, rmdir, mkdir, readdir, rmdir_recursive, @@ -729,7 +683,7 @@ mod test { // Gee, seeing how we're testing the fs module I sure hope that we // at least implement this correctly! let TempDir(ref p) = *self; - io::fs::rmdir_recursive(p); + io::fs::rmdir_recursive(p).unwrap(); } } @@ -737,7 +691,7 @@ mod test { use os; use rand; let ret = os::tmpdir().join(format!("rust-{}", rand::random::<u32>())); - io::fs::mkdir(&ret, io::UserRWX); + io::fs::mkdir(&ret, io::UserRWX).unwrap(); TempDir(ret) } @@ -747,7 +701,7 @@ mod test { let filename = &tmpdir.join("file_rt_io_file_test.txt"); { let mut write_stream = File::open_mode(filename, Open, ReadWrite); - write_stream.write(message.as_bytes()); + write_stream.write(message.as_bytes()).unwrap(); } { let mut read_stream = File::open_mode(filename, Open, Read); @@ -758,30 +712,20 @@ mod test { }; assert_eq!(read_str, message.to_owned()); } - unlink(filename); + unlink(filename).unwrap(); }) iotest!(fn invalid_path_raises() { let tmpdir = tmpdir(); let filename = &tmpdir.join("file_that_does_not_exist.txt"); - let mut called = false; - io_error::cond.trap(|_| { - called = true; - }).inside(|| { - let result = File::open_mode(filename, Open, Read); - assert!(result.is_none()); - }); - assert!(called); + let result = File::open_mode(filename, Open, Read); + assert!(result.is_err()); }) iotest!(fn file_test_iounlinking_invalid_path_should_raise_condition() { let tmpdir = tmpdir(); let filename = &tmpdir.join("file_another_file_that_does_not_exist.txt"); - let mut called = false; - io_error::cond.trap(|_| { - called = true; - }).inside(|| unlink(filename)); - assert!(called); + assert!(unlink(filename).is_err()); }) iotest!(fn file_test_io_non_positional_read() { @@ -791,20 +735,20 @@ mod test { let filename = &tmpdir.join("file_rt_io_file_test_positional.txt"); { let mut rw_stream = File::open_mode(filename, Open, ReadWrite); - rw_stream.write(message.as_bytes()); + rw_stream.write(message.as_bytes()).unwrap(); } { let mut read_stream = File::open_mode(filename, Open, Read); { let read_buf = read_mem.mut_slice(0, 4); - read_stream.read(read_buf); + read_stream.read(read_buf).unwrap(); } { let read_buf = read_mem.mut_slice(4, 8); - read_stream.read(read_buf); + read_stream.read(read_buf).unwrap(); } } - unlink(filename); + unlink(filename).unwrap(); let read_str = str::from_utf8(read_mem).unwrap(); assert_eq!(read_str, message); }) @@ -819,16 +763,16 @@ mod test { let filename = &tmpdir.join("file_rt_io_file_test_seeking.txt"); { let mut rw_stream = File::open_mode(filename, Open, ReadWrite); - rw_stream.write(message.as_bytes()); + rw_stream.write(message.as_bytes()).unwrap(); } { let mut read_stream = File::open_mode(filename, Open, Read); - read_stream.seek(set_cursor as i64, SeekSet); - tell_pos_pre_read = read_stream.tell(); - read_stream.read(read_mem); - tell_pos_post_read = read_stream.tell(); + read_stream.seek(set_cursor as i64, SeekSet).unwrap(); + tell_pos_pre_read = read_stream.tell().unwrap(); + read_stream.read(read_mem).unwrap(); + tell_pos_post_read = read_stream.tell().unwrap(); } - unlink(filename); + unlink(filename).unwrap(); let read_str = str::from_utf8(read_mem).unwrap(); assert_eq!(read_str, message.slice(4, 8)); assert_eq!(tell_pos_pre_read, set_cursor); @@ -845,15 +789,15 @@ mod test { let filename = &tmpdir.join("file_rt_io_file_test_seek_and_write.txt"); { let mut rw_stream = File::open_mode(filename, Open, ReadWrite); - rw_stream.write(initial_msg.as_bytes()); - rw_stream.seek(seek_idx as i64, SeekSet); - rw_stream.write(overwrite_msg.as_bytes()); + rw_stream.write(initial_msg.as_bytes()).unwrap(); + rw_stream.seek(seek_idx as i64, SeekSet).unwrap(); + rw_stream.write(overwrite_msg.as_bytes()).unwrap(); } { let mut read_stream = File::open_mode(filename, Open, Read); - read_stream.read(read_mem); + read_stream.read(read_mem).unwrap(); } - unlink(filename); + unlink(filename).unwrap(); let read_str = str::from_utf8(read_mem).unwrap(); assert!(read_str == final_msg.to_owned()); }) @@ -869,24 +813,24 @@ mod test { let filename = &tmpdir.join("file_rt_io_file_test_seek_shakedown.txt"); { let mut rw_stream = File::open_mode(filename, Open, ReadWrite); - rw_stream.write(initial_msg.as_bytes()); + rw_stream.write(initial_msg.as_bytes()).unwrap(); } { let mut read_stream = File::open_mode(filename, Open, Read); - read_stream.seek(-4, SeekEnd); - read_stream.read(read_mem); + read_stream.seek(-4, SeekEnd).unwrap(); + read_stream.read(read_mem).unwrap(); assert_eq!(str::from_utf8(read_mem).unwrap(), chunk_three); - read_stream.seek(-9, SeekCur); - read_stream.read(read_mem); + read_stream.seek(-9, SeekCur).unwrap(); + read_stream.read(read_mem).unwrap(); assert_eq!(str::from_utf8(read_mem).unwrap(), chunk_two); - read_stream.seek(0, SeekSet); - read_stream.read(read_mem); + read_stream.seek(0, SeekSet).unwrap(); + read_stream.read(read_mem).unwrap(); assert_eq!(str::from_utf8(read_mem).unwrap(), chunk_one); } - unlink(filename); + unlink(filename).unwrap(); }) iotest!(fn file_test_stat_is_correct_on_is_file() { @@ -895,36 +839,36 @@ mod test { { let mut fs = File::open_mode(filename, Open, ReadWrite); let msg = "hw"; - fs.write(msg.as_bytes()); + fs.write(msg.as_bytes()).unwrap(); } - let stat_res = stat(filename); + let stat_res = stat(filename).unwrap(); assert_eq!(stat_res.kind, io::TypeFile); - unlink(filename); + unlink(filename).unwrap(); }) iotest!(fn file_test_stat_is_correct_on_is_dir() { let tmpdir = tmpdir(); let filename = &tmpdir.join("file_stat_correct_on_is_dir"); - mkdir(filename, io::UserRWX); - let stat_res = filename.stat(); + mkdir(filename, io::UserRWX).unwrap(); + let stat_res = filename.stat().unwrap(); assert!(stat_res.kind == io::TypeDirectory); - rmdir(filename); + rmdir(filename).unwrap(); }) iotest!(fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() { let tmpdir = tmpdir(); let dir = &tmpdir.join("fileinfo_false_on_dir"); - mkdir(dir, io::UserRWX); + mkdir(dir, io::UserRWX).unwrap(); assert!(dir.is_file() == false); - rmdir(dir); + rmdir(dir).unwrap(); }) iotest!(fn file_test_fileinfo_check_exists_before_and_after_file_creation() { let tmpdir = tmpdir(); let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt"); - File::create(file).write(bytes!("foo")); + File::create(file).write(bytes!("foo")).unwrap(); assert!(file.exists()); - unlink(file); + unlink(file).unwrap(); assert!(!file.exists()); }) @@ -932,10 +876,10 @@ mod test { let tmpdir = tmpdir(); let dir = &tmpdir.join("before_and_after_dir"); assert!(!dir.exists()); - mkdir(dir, io::UserRWX); + mkdir(dir, io::UserRWX).unwrap(); assert!(dir.exists()); assert!(dir.is_dir()); - rmdir(dir); + rmdir(dir).unwrap(); assert!(!dir.exists()); }) @@ -943,21 +887,21 @@ mod test { use std::str; let tmpdir = tmpdir(); let dir = &tmpdir.join("di_readdir"); - mkdir(dir, io::UserRWX); + mkdir(dir, io::UserRWX).unwrap(); let prefix = "foo"; for n in range(0,3) { let f = dir.join(format!("{}.txt", n)); - let mut w = File::create(&f); + let mut w = File::create(&f).unwrap(); let msg_str = (prefix + n.to_str().to_owned()).to_owned(); let msg = msg_str.as_bytes(); - w.write(msg); + w.write(msg).unwrap(); } - let files = readdir(dir); + let files = readdir(dir).unwrap(); let mut mem = [0u8, .. 4]; for f in files.iter() { { let n = f.filestem_str(); - File::open(f).read(mem); + File::open(f).read(mem).unwrap(); let read_str = str::from_utf8(mem).unwrap(); let expected = match n { None|Some("") => fail!("really shouldn't happen.."), @@ -965,13 +909,13 @@ mod test { }; assert_eq!(expected.as_slice(), read_str); } - unlink(f); + unlink(f).unwrap(); } - rmdir(dir); + rmdir(dir).unwrap(); }) iotest!(fn recursive_mkdir_slash() { - mkdir_recursive(&Path::new("/"), io::UserRWX); + mkdir_recursive(&Path::new("/"), io::UserRWX).unwrap(); }) iotest!(fn unicode_path_is_dir() { @@ -982,12 +926,12 @@ mod test { let mut dirpath = tmpdir.path().clone(); dirpath.push(format!("test-가一ー你好")); - mkdir(&dirpath, io::UserRWX); + mkdir(&dirpath, io::UserRWX).unwrap(); assert!(dirpath.is_dir()); let mut filepath = dirpath; filepath.push("unicode-file-\uac00\u4e00\u30fc\u4f60\u597d.rs"); - File::create(&filepath); // ignore return; touch only + File::create(&filepath).unwrap(); // ignore return; touch only assert!(!filepath.is_dir()); assert!(filepath.exists()); }) @@ -999,7 +943,7 @@ mod test { let tmpdir = tmpdir(); let unicode = tmpdir.path(); let unicode = unicode.join(format!("test-각丁ー再见")); - mkdir(&unicode, io::UserRWX); + mkdir(&unicode, io::UserRWX).unwrap(); assert!(unicode.exists()); assert!(!Path::new("test/unicode-bogus-path-각丁ー再见").exists()); }) @@ -1007,7 +951,7 @@ mod test { iotest!(fn copy_file_does_not_exist() { let from = Path::new("test/nonexistent-bogus-path"); let to = Path::new("test/other-bogus-path"); - match io::result(|| copy(&from, &to)) { + match copy(&from, &to) { Ok(..) => fail!(), Err(..) => { assert!(!from.exists()); @@ -1021,20 +965,20 @@ mod test { let input = tmpdir.join("in.txt"); let out = tmpdir.join("out.txt"); - File::create(&input).write(bytes!("hello")); - copy(&input, &out); - let contents = File::open(&out).read_to_end(); + File::create(&input).write(bytes!("hello")).unwrap(); + copy(&input, &out).unwrap(); + let contents = File::open(&out).read_to_end().unwrap(); assert_eq!(contents.as_slice(), bytes!("hello")); - assert_eq!(input.stat().perm, out.stat().perm); + assert_eq!(input.stat().unwrap().perm, out.stat().unwrap().perm); }) iotest!(fn copy_file_dst_dir() { let tmpdir = tmpdir(); let out = tmpdir.join("out"); - File::create(&out); - match io::result(|| copy(&out, tmpdir.path())) { + File::create(&out).unwrap(); + match copy(&out, tmpdir.path()) { Ok(..) => fail!(), Err(..) => {} } }) @@ -1044,11 +988,11 @@ mod test { let input = tmpdir.join("in"); let output = tmpdir.join("out"); - File::create(&input).write("foo".as_bytes()); - File::create(&output).write("bar".as_bytes()); - copy(&input, &output); + File::create(&input).write("foo".as_bytes()).unwrap(); + File::create(&output).write("bar".as_bytes()).unwrap(); + copy(&input, &output).unwrap(); - assert_eq!(File::open(&output).read_to_end(), + assert_eq!(File::open(&output).read_to_end().unwrap(), (bytes!("foo")).to_owned()); }) @@ -1056,7 +1000,7 @@ mod test { let tmpdir = tmpdir(); let out = tmpdir.join("out"); - match io::result(|| copy(tmpdir.path(), &out)) { + match copy(tmpdir.path(), &out) { Ok(..) => fail!(), Err(..) => {} } assert!(!out.exists()); @@ -1067,13 +1011,13 @@ mod test { let input = tmpdir.join("in.txt"); let out = tmpdir.join("out.txt"); - File::create(&input); - chmod(&input, io::UserRead); - copy(&input, &out); - assert!(out.stat().perm & io::UserWrite == 0); + File::create(&input).unwrap(); + chmod(&input, io::UserRead).unwrap(); + copy(&input, &out).unwrap(); + assert!(out.stat().unwrap().perm & io::UserWrite == 0); - chmod(&input, io::UserFile); - chmod(&out, io::UserFile); + chmod(&input, io::UserFile).unwrap(); + chmod(&out, io::UserFile).unwrap(); }) #[cfg(not(windows))] // FIXME(#10264) operation not permitted? @@ -1082,26 +1026,27 @@ mod test { let input = tmpdir.join("in.txt"); let out = tmpdir.join("out.txt"); - File::create(&input).write("foobar".as_bytes()); - symlink(&input, &out); + File::create(&input).write("foobar".as_bytes()).unwrap(); + symlink(&input, &out).unwrap(); if cfg!(not(windows)) { - assert_eq!(lstat(&out).kind, io::TypeSymlink); + assert_eq!(lstat(&out).unwrap().kind, io::TypeSymlink); } - assert_eq!(stat(&out).size, stat(&input).size); - assert_eq!(File::open(&out).read_to_end(), (bytes!("foobar")).to_owned()); + assert_eq!(stat(&out).unwrap().size, stat(&input).unwrap().size); + assert_eq!(File::open(&out).read_to_end().unwrap(), + (bytes!("foobar")).to_owned()); }) #[cfg(not(windows))] // apparently windows doesn't like symlinks iotest!(fn symlink_noexist() { let tmpdir = tmpdir(); // symlinks can point to things that don't exist - symlink(&tmpdir.join("foo"), &tmpdir.join("bar")); + symlink(&tmpdir.join("foo"), &tmpdir.join("bar")).unwrap(); assert!(readlink(&tmpdir.join("bar")).unwrap() == tmpdir.join("foo")); }) iotest!(fn readlink_not_symlink() { let tmpdir = tmpdir(); - match io::result(|| readlink(tmpdir.path())) { + match readlink(tmpdir.path()) { Ok(..) => fail!("wanted a failure"), Err(..) => {} } @@ -1112,22 +1057,23 @@ mod test { let input = tmpdir.join("in.txt"); let out = tmpdir.join("out.txt"); - File::create(&input).write("foobar".as_bytes()); - link(&input, &out); + File::create(&input).write("foobar".as_bytes()).unwrap(); + link(&input, &out).unwrap(); if cfg!(not(windows)) { - assert_eq!(lstat(&out).kind, io::TypeFile); - assert_eq!(stat(&out).unstable.nlink, 2); + assert_eq!(lstat(&out).unwrap().kind, io::TypeFile); + assert_eq!(stat(&out).unwrap().unstable.nlink, 2); } - assert_eq!(stat(&out).size, stat(&input).size); - assert_eq!(File::open(&out).read_to_end(), (bytes!("foobar")).to_owned()); + assert_eq!(stat(&out).unwrap().size, stat(&input).unwrap().size); + assert_eq!(File::open(&out).read_to_end().unwrap(), + (bytes!("foobar")).to_owned()); // can't link to yourself - match io::result(|| link(&input, &input)) { + match link(&input, &input) { Ok(..) => fail!("wanted a failure"), Err(..) => {} } // can't link to something that doesn't exist - match io::result(|| link(&tmpdir.join("foo"), &tmpdir.join("bar"))) { + match link(&tmpdir.join("foo"), &tmpdir.join("bar")) { Ok(..) => fail!("wanted a failure"), Err(..) => {} } @@ -1137,17 +1083,17 @@ mod test { let tmpdir = tmpdir(); let file = tmpdir.join("in.txt"); - File::create(&file); - assert!(stat(&file).perm & io::UserWrite == io::UserWrite); - chmod(&file, io::UserRead); - assert!(stat(&file).perm & io::UserWrite == 0); + File::create(&file).unwrap(); + assert!(stat(&file).unwrap().perm & io::UserWrite == io::UserWrite); + chmod(&file, io::UserRead).unwrap(); + assert!(stat(&file).unwrap().perm & io::UserWrite == 0); - match io::result(|| chmod(&tmpdir.join("foo"), io::UserRWX)) { + match chmod(&tmpdir.join("foo"), io::UserRWX) { Ok(..) => fail!("wanted a failure"), Err(..) => {} } - chmod(&file, io::UserFile); + chmod(&file, io::UserFile).unwrap(); }) iotest!(fn sync_doesnt_kill_anything() { @@ -1155,11 +1101,11 @@ mod test { let path = tmpdir.join("in.txt"); let mut file = File::open_mode(&path, io::Open, io::ReadWrite).unwrap(); - file.fsync(); - file.datasync(); - file.write(bytes!("foo")); - file.fsync(); - file.datasync(); + file.fsync().unwrap(); + file.datasync().unwrap(); + file.write(bytes!("foo")).unwrap(); + file.fsync().unwrap(); + file.datasync().unwrap(); drop(file); }) @@ -1168,28 +1114,28 @@ mod test { let path = tmpdir.join("in.txt"); let mut file = File::open_mode(&path, io::Open, io::ReadWrite).unwrap(); - file.write(bytes!("foo")); - file.fsync(); + file.write(bytes!("foo")).unwrap(); + file.fsync().unwrap(); // Do some simple things with truncation - assert_eq!(stat(&path).size, 3); - file.truncate(10); - assert_eq!(stat(&path).size, 10); - file.write(bytes!("bar")); - file.fsync(); - assert_eq!(stat(&path).size, 10); - assert_eq!(File::open(&path).read_to_end(), + assert_eq!(stat(&path).unwrap().size, 3); + file.truncate(10).unwrap(); + assert_eq!(stat(&path).unwrap().size, 10); + file.write(bytes!("bar")).unwrap(); + file.fsync().unwrap(); + assert_eq!(stat(&path).unwrap().size, 10); + assert_eq!(File::open(&path).read_to_end().unwrap(), (bytes!("foobar", 0, 0, 0, 0)).to_owned()); // Truncate to a smaller length, don't seek, and then write something. // Ensure that the intermediate zeroes are all filled in (we're seeked // past the end of the file). - file.truncate(2); - assert_eq!(stat(&path).size, 2); - file.write(bytes!("wut")); - file.fsync(); - assert_eq!(stat(&path).size, 9); - assert_eq!(File::open(&path).read_to_end(), + file.truncate(2).unwrap(); + assert_eq!(stat(&path).unwrap().size, 2); + file.write(bytes!("wut")).unwrap(); + file.fsync().unwrap(); + assert_eq!(stat(&path).unwrap().size, 9); + assert_eq!(File::open(&path).read_to_end().unwrap(), (bytes!("fo", 0, 0, 0, 0, "wut")).to_owned()); drop(file); }) @@ -1197,8 +1143,7 @@ mod test { iotest!(fn open_flavors() { let tmpdir = tmpdir(); - match io::result(|| File::open_mode(&tmpdir.join("a"), io::Open, - io::Read)) { + match File::open_mode(&tmpdir.join("a"), io::Open, io::Read) { Ok(..) => fail!(), Err(..) => {} } File::open_mode(&tmpdir.join("b"), io::Open, io::Write).unwrap(); @@ -1208,46 +1153,46 @@ mod test { File::open_mode(&tmpdir.join("f"), io::Truncate, io::Write).unwrap(); File::open_mode(&tmpdir.join("g"), io::Truncate, io::ReadWrite).unwrap(); - File::create(&tmpdir.join("h")).write("foo".as_bytes()); + File::create(&tmpdir.join("h")).write("foo".as_bytes()).unwrap(); File::open_mode(&tmpdir.join("h"), io::Open, io::Read).unwrap(); { let mut f = File::open_mode(&tmpdir.join("h"), io::Open, io::Read).unwrap(); - match io::result(|| f.write("wut".as_bytes())) { + match f.write("wut".as_bytes()) { Ok(..) => fail!(), Err(..) => {} } } - assert_eq!(stat(&tmpdir.join("h")).size, 3); + assert_eq!(stat(&tmpdir.join("h")).unwrap().size, 3); { let mut f = File::open_mode(&tmpdir.join("h"), io::Append, io::Write).unwrap(); - f.write("bar".as_bytes()); + f.write("bar".as_bytes()).unwrap(); } - assert_eq!(stat(&tmpdir.join("h")).size, 6); + assert_eq!(stat(&tmpdir.join("h")).unwrap().size, 6); { let mut f = File::open_mode(&tmpdir.join("h"), io::Truncate, io::Write).unwrap(); - f.write("bar".as_bytes()); + f.write("bar".as_bytes()).unwrap(); } - assert_eq!(stat(&tmpdir.join("h")).size, 3); + assert_eq!(stat(&tmpdir.join("h")).unwrap().size, 3); }) #[test] fn utime() { let tmpdir = tmpdir(); let path = tmpdir.join("a"); - File::create(&path); + File::create(&path).unwrap(); - change_file_times(&path, 1000, 2000); - assert_eq!(path.stat().accessed, 1000); - assert_eq!(path.stat().modified, 2000); + change_file_times(&path, 1000, 2000).unwrap(); + assert_eq!(path.stat().unwrap().accessed, 1000); + assert_eq!(path.stat().unwrap().modified, 2000); } #[test] fn utime_noexist() { let tmpdir = tmpdir(); - match io::result(|| change_file_times(&tmpdir.join("a"), 100, 200)) { + match change_file_times(&tmpdir.join("a"), 100, 200) { Ok(..) => fail!(), Err(..) => {} } diff --git a/src/libstd/io/mem.rs b/src/libstd/io/mem.rs index c185951feca..395ece17ede 100644 --- a/src/libstd/io/mem.rs +++ b/src/libstd/io/mem.rs @@ -13,9 +13,10 @@ use cmp::max; use cmp::min; use container::Container; -use option::{Option, Some, None}; -use super::{Reader, Writer, Seek, Buffer, IoError, SeekStyle, io_error, - OtherIoError}; +use option::None; +use result::{Err, Ok}; +use io; +use io::{Reader, Writer, Seek, Buffer, IoError, SeekStyle, IoResult}; use vec; use vec::{Vector, ImmutableVector, MutableVector, OwnedCloneableVector}; @@ -24,6 +25,7 @@ use vec::{Vector, ImmutableVector, MutableVector, OwnedCloneableVector}; /// # Example /// /// ```rust +/// # #[allow(unused_must_use)]; /// use std::io::MemWriter; /// /// let mut w = MemWriter::new(); @@ -59,7 +61,7 @@ impl MemWriter { } impl Writer for MemWriter { - fn write(&mut self, buf: &[u8]) { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { // Make sure the internal buffer is as least as big as where we // currently are let difference = self.pos as i64 - self.buf.len() as i64; @@ -86,14 +88,15 @@ impl Writer for MemWriter { // Bump us forward self.pos += buf.len(); + Ok(()) } } // FIXME(#10432) impl Seek for MemWriter { - fn tell(&self) -> u64 { self.pos as u64 } + fn tell(&self) -> IoResult<u64> { Ok(self.pos as u64) } - fn seek(&mut self, pos: i64, style: SeekStyle) { + fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { // compute offset as signed and clamp to prevent overflow let offset = match style { SeekSet => { 0 } @@ -102,6 +105,7 @@ impl Seek for MemWriter { } as i64; self.pos = max(0, offset+pos) as uint; + Ok(()) } } @@ -110,11 +114,12 @@ impl Seek for MemWriter { /// # Example /// /// ```rust +/// # #[allow(unused_must_use)]; /// use std::io::MemReader; /// /// let mut r = MemReader::new(~[0, 1, 2]); /// -/// assert_eq!(r.read_to_end(), ~[0, 1, 2]); +/// assert_eq!(r.read_to_end().unwrap(), ~[0, 1, 2]); /// ``` pub struct MemReader { priv buf: ~[u8], @@ -148,8 +153,8 @@ impl MemReader { } impl Reader for MemReader { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { - if self.eof() { return None } + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { + if self.eof() { return Err(io::standard_error(io::EndOfFile)) } let write_len = min(buf.len(), self.buf.len() - self.pos); { @@ -161,28 +166,31 @@ impl Reader for MemReader { self.pos += write_len; assert!(self.pos <= self.buf.len()); - return Some(write_len); + return Ok(write_len); } } impl Seek for MemReader { - fn tell(&self) -> u64 { self.pos as u64 } - fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } + fn tell(&self) -> IoResult<u64> { Ok(self.pos as u64) } + fn seek(&mut self, _pos: i64, _style: SeekStyle) -> IoResult<()> { fail!() } } impl Buffer for MemReader { - fn fill<'a>(&'a mut self) -> &'a [u8] { self.buf.slice_from(self.pos) } + fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]> { + Ok(self.buf.slice_from(self.pos)) + } fn consume(&mut self, amt: uint) { self.pos += amt; } } /// Writes to a fixed-size byte slice /// -/// If a write will not fit in the buffer, it raises the `io_error` -/// condition and does not write any data. +/// If a write will not fit in the buffer, it returns an error and does not +/// write any data. /// /// # Example /// /// ```rust +/// # #[allow(unused_must_use)]; /// use std::io::BufWriter; /// /// let mut buf = [0, ..4]; @@ -207,28 +215,28 @@ impl<'a> BufWriter<'a> { } impl<'a> Writer for BufWriter<'a> { - fn write(&mut self, buf: &[u8]) { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { // raises a condition if the entire write does not fit in the buffer let max_size = self.buf.len(); if self.pos >= max_size || (self.pos + buf.len()) > max_size { - io_error::cond.raise(IoError { - kind: OtherIoError, + return Err(IoError { + kind: io::OtherIoError, desc: "Trying to write past end of buffer", detail: None - }); - return; + }) } vec::bytes::copy_memory(self.buf.mut_slice_from(self.pos), buf); self.pos += buf.len(); + Ok(()) } } // FIXME(#10432) impl<'a> Seek for BufWriter<'a> { - fn tell(&self) -> u64 { self.pos as u64 } + fn tell(&self) -> IoResult<u64> { Ok(self.pos as u64) } - fn seek(&mut self, pos: i64, style: SeekStyle) { + fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { // compute offset as signed and clamp to prevent overflow let offset = match style { SeekSet => { 0 } @@ -237,6 +245,7 @@ impl<'a> Seek for BufWriter<'a> { } as i64; self.pos = max(0, offset+pos) as uint; + Ok(()) } } @@ -246,12 +255,13 @@ impl<'a> Seek for BufWriter<'a> { /// # Example /// /// ```rust +/// # #[allow(unused_must_use)]; /// use std::io::BufReader; /// /// let mut buf = [0, 1, 2, 3]; /// let mut r = BufReader::new(buf); /// -/// assert_eq!(r.read_to_end(), ~[0, 1, 2, 3]); +/// assert_eq!(r.read_to_end().unwrap(), ~[0, 1, 2, 3]); /// ``` pub struct BufReader<'a> { priv buf: &'a [u8], @@ -274,8 +284,8 @@ impl<'a> BufReader<'a> { } impl<'a> Reader for BufReader<'a> { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { - if self.eof() { return None } + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { + if self.eof() { return Err(io::standard_error(io::EndOfFile)) } let write_len = min(buf.len(), self.buf.len() - self.pos); { @@ -287,18 +297,19 @@ impl<'a> Reader for BufReader<'a> { self.pos += write_len; assert!(self.pos <= self.buf.len()); - return Some(write_len); + return Ok(write_len); } } impl<'a> Seek for BufReader<'a> { - fn tell(&self) -> u64 { self.pos as u64 } - - fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } + fn tell(&self) -> IoResult<u64> { Ok(self.pos as u64) } + fn seek(&mut self, _pos: i64, _style: SeekStyle) -> IoResult<()> { fail!() } } impl<'a> Buffer for BufReader<'a> { - fn fill<'a>(&'a mut self) -> &'a [u8] { self.buf.slice_from(self.pos) } + fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]> { + Ok(self.buf.slice_from(self.pos)) + } fn consume(&mut self, amt: uint) { self.pos += amt; } } @@ -307,33 +318,34 @@ mod test { use prelude::*; use super::*; use io::*; + use io; #[test] fn test_mem_writer() { let mut writer = MemWriter::new(); - assert_eq!(writer.tell(), 0); - writer.write([0]); - assert_eq!(writer.tell(), 1); - writer.write([1, 2, 3]); - writer.write([4, 5, 6, 7]); - assert_eq!(writer.tell(), 8); + assert_eq!(writer.tell(), Ok(0)); + writer.write([0]).unwrap(); + assert_eq!(writer.tell(), Ok(1)); + writer.write([1, 2, 3]).unwrap(); + writer.write([4, 5, 6, 7]).unwrap(); + assert_eq!(writer.tell(), Ok(8)); assert_eq!(writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7]); - writer.seek(0, SeekSet); - assert_eq!(writer.tell(), 0); - writer.write([3, 4]); + writer.seek(0, SeekSet).unwrap(); + assert_eq!(writer.tell(), Ok(0)); + writer.write([3, 4]).unwrap(); assert_eq!(writer.get_ref(), [3, 4, 2, 3, 4, 5, 6, 7]); - writer.seek(1, SeekCur); - writer.write([0, 1]); + writer.seek(1, SeekCur).unwrap(); + writer.write([0, 1]).unwrap(); assert_eq!(writer.get_ref(), [3, 4, 2, 0, 1, 5, 6, 7]); - writer.seek(-1, SeekEnd); - writer.write([1, 2]); + writer.seek(-1, SeekEnd).unwrap(); + writer.write([1, 2]).unwrap(); assert_eq!(writer.get_ref(), [3, 4, 2, 0, 1, 5, 6, 1, 2]); - writer.seek(1, SeekEnd); - writer.write([1]); + writer.seek(1, SeekEnd).unwrap(); + writer.write([1]).unwrap(); assert_eq!(writer.get_ref(), [3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1]); } @@ -342,12 +354,12 @@ mod test { let mut buf = [0 as u8, ..8]; { let mut writer = BufWriter::new(buf); - assert_eq!(writer.tell(), 0); - writer.write([0]); - assert_eq!(writer.tell(), 1); - writer.write([1, 2, 3]); - writer.write([4, 5, 6, 7]); - assert_eq!(writer.tell(), 8); + assert_eq!(writer.tell(), Ok(0)); + writer.write([0]).unwrap(); + assert_eq!(writer.tell(), Ok(1)); + writer.write([1, 2, 3]).unwrap(); + writer.write([4, 5, 6, 7]).unwrap(); + assert_eq!(writer.tell(), Ok(8)); } assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7]); } @@ -357,24 +369,24 @@ mod test { let mut buf = [0 as u8, ..8]; { let mut writer = BufWriter::new(buf); - assert_eq!(writer.tell(), 0); - writer.write([1]); - assert_eq!(writer.tell(), 1); + assert_eq!(writer.tell(), Ok(0)); + writer.write([1]).unwrap(); + assert_eq!(writer.tell(), Ok(1)); - writer.seek(2, SeekSet); - assert_eq!(writer.tell(), 2); - writer.write([2]); - assert_eq!(writer.tell(), 3); + writer.seek(2, SeekSet).unwrap(); + assert_eq!(writer.tell(), Ok(2)); + writer.write([2]).unwrap(); + assert_eq!(writer.tell(), Ok(3)); - writer.seek(-2, SeekCur); - assert_eq!(writer.tell(), 1); - writer.write([3]); - assert_eq!(writer.tell(), 2); + writer.seek(-2, SeekCur).unwrap(); + assert_eq!(writer.tell(), Ok(1)); + writer.write([3]).unwrap(); + assert_eq!(writer.tell(), Ok(2)); - writer.seek(-1, SeekEnd); - assert_eq!(writer.tell(), 7); - writer.write([4]); - assert_eq!(writer.tell(), 8); + writer.seek(-1, SeekEnd).unwrap(); + assert_eq!(writer.tell(), Ok(7)); + writer.write([4]).unwrap(); + assert_eq!(writer.tell(), Ok(8)); } assert_eq!(buf, [1, 3, 2, 0, 0, 0, 0, 4]); @@ -384,35 +396,31 @@ mod test { fn test_buf_writer_error() { let mut buf = [0 as u8, ..2]; let mut writer = BufWriter::new(buf); - writer.write([0]); - - let mut called = false; - io_error::cond.trap(|err| { - assert_eq!(err.kind, OtherIoError); - called = true; - }).inside(|| { - writer.write([0, 0]); - }); - assert!(called); + writer.write([0]).unwrap(); + + match writer.write([0, 0]) { + Ok(..) => fail!(), + Err(e) => assert_eq!(e.kind, io::OtherIoError), + } } #[test] fn test_mem_reader() { let mut reader = MemReader::new(~[0, 1, 2, 3, 4, 5, 6, 7]); let mut buf = []; - assert_eq!(reader.read(buf), Some(0)); - assert_eq!(reader.tell(), 0); + assert_eq!(reader.read(buf), Ok(0)); + assert_eq!(reader.tell(), Ok(0)); let mut buf = [0]; - assert_eq!(reader.read(buf), Some(1)); - assert_eq!(reader.tell(), 1); + assert_eq!(reader.read(buf), Ok(1)); + assert_eq!(reader.tell(), Ok(1)); assert_eq!(buf, [0]); let mut buf = [0, ..4]; - assert_eq!(reader.read(buf), Some(4)); - assert_eq!(reader.tell(), 5); + assert_eq!(reader.read(buf), Ok(4)); + assert_eq!(reader.tell(), Ok(5)); assert_eq!(buf, [1, 2, 3, 4]); - assert_eq!(reader.read(buf), Some(3)); + assert_eq!(reader.read(buf), Ok(3)); assert_eq!(buf.slice(0, 3), [5, 6, 7]); - assert_eq!(reader.read(buf), None); + assert!(reader.read(buf).is_err()); } #[test] @@ -420,64 +428,64 @@ mod test { let in_buf = ~[0, 1, 2, 3, 4, 5, 6, 7]; let mut reader = BufReader::new(in_buf); let mut buf = []; - assert_eq!(reader.read(buf), Some(0)); - assert_eq!(reader.tell(), 0); + assert_eq!(reader.read(buf), Ok(0)); + assert_eq!(reader.tell(), Ok(0)); let mut buf = [0]; - assert_eq!(reader.read(buf), Some(1)); - assert_eq!(reader.tell(), 1); + assert_eq!(reader.read(buf), Ok(1)); + assert_eq!(reader.tell(), Ok(1)); assert_eq!(buf, [0]); let mut buf = [0, ..4]; - assert_eq!(reader.read(buf), Some(4)); - assert_eq!(reader.tell(), 5); + assert_eq!(reader.read(buf), Ok(4)); + assert_eq!(reader.tell(), Ok(5)); assert_eq!(buf, [1, 2, 3, 4]); - assert_eq!(reader.read(buf), Some(3)); + assert_eq!(reader.read(buf), Ok(3)); assert_eq!(buf.slice(0, 3), [5, 6, 7]); - assert_eq!(reader.read(buf), None); + assert!(reader.read(buf).is_err()); } #[test] fn test_read_char() { let b = bytes!("Việt"); let mut r = BufReader::new(b); - assert_eq!(r.read_char(), Some('V')); - assert_eq!(r.read_char(), Some('i')); - assert_eq!(r.read_char(), Some('ệ')); - assert_eq!(r.read_char(), Some('t')); - assert_eq!(r.read_char(), None); + assert_eq!(r.read_char(), Ok('V')); + assert_eq!(r.read_char(), Ok('i')); + assert_eq!(r.read_char(), Ok('ệ')); + assert_eq!(r.read_char(), Ok('t')); + assert!(r.read_char().is_err()); } #[test] fn test_read_bad_char() { let b = bytes!(0x80); let mut r = BufReader::new(b); - assert_eq!(r.read_char(), None); + assert!(r.read_char().is_err()); } #[test] fn test_write_strings() { let mut writer = MemWriter::new(); - writer.write_str("testing"); - writer.write_line("testing"); - writer.write_str("testing"); + writer.write_str("testing").unwrap(); + writer.write_line("testing").unwrap(); + writer.write_str("testing").unwrap(); let mut r = BufReader::new(writer.get_ref()); - assert_eq!(r.read_to_str(), ~"testingtesting\ntesting"); + assert_eq!(r.read_to_str().unwrap(), ~"testingtesting\ntesting"); } #[test] fn test_write_char() { let mut writer = MemWriter::new(); - writer.write_char('a'); - writer.write_char('\n'); - writer.write_char('ệ'); + writer.write_char('a').unwrap(); + writer.write_char('\n').unwrap(); + writer.write_char('ệ').unwrap(); let mut r = BufReader::new(writer.get_ref()); - assert_eq!(r.read_to_str(), ~"a\nệ"); + assert_eq!(r.read_to_str().unwrap(), ~"a\nệ"); } #[test] fn test_read_whole_string_bad() { let buf = [0xff]; let mut r = BufReader::new(buf); - match result(|| r.read_to_str()) { + match r.read_to_str() { Ok(..) => fail!(), Err(..) => {} } diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 69f0cf96ffc..7690c88478f 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -29,7 +29,6 @@ Some examples of obvious things you might want to do use std::io::BufferedReader; use std::io::stdin; - # let _g = ::std::io::ignore_io_error(); let mut stdin = BufferedReader::new(stdin()); for line in stdin.lines() { print!("{}", line); @@ -41,16 +40,15 @@ Some examples of obvious things you might want to do ```rust use std::io::File; - # let _g = ::std::io::ignore_io_error(); let contents = File::open(&Path::new("message.txt")).read_to_end(); ``` * Write a line to a file ```rust + # #[allow(unused_must_use)]; use std::io::File; - # let _g = ::std::io::ignore_io_error(); let mut file = File::create(&Path::new("message.txt")); file.write(bytes!("hello, file!\n")); # drop(file); @@ -63,7 +61,6 @@ Some examples of obvious things you might want to do use std::io::BufferedReader; use std::io::File; - # let _g = ::std::io::ignore_io_error(); let path = Path::new("message.txt"); let mut file = BufferedReader::new(File::open(&path)); for line in file.lines() { @@ -77,7 +74,6 @@ Some examples of obvious things you might want to do use std::io::BufferedReader; use std::io::File; - # let _g = ::std::io::ignore_io_error(); let path = Path::new("message.txt"); let mut file = BufferedReader::new(File::open(&path)); let lines: ~[~str] = file.lines().collect(); @@ -88,10 +84,10 @@ Some examples of obvious things you might want to do `write_str` and `write_line` methods. ```rust,should_fail + # #[allow(unused_must_use)]; use std::io::net::ip::SocketAddr; use std::io::net::tcp::TcpStream; - # let _g = ::std::io::ignore_io_error(); let addr = from_str::<SocketAddr>("127.0.0.1:8080").unwrap(); let mut socket = TcpStream::connect(addr).unwrap(); socket.write(bytes!("GET / HTTP/1.0\n\n")); @@ -168,72 +164,51 @@ asynchronous request completes. # Error Handling I/O is an area where nearly every operation can result in unexpected -errors. It should allow errors to be handled efficiently. -It needs to be convenient to use I/O when you don't care -about dealing with specific errors. +errors. Errors should be painfully visible when they happen, and handling them +should be easy to work with. It should be convenient to handle specific I/O +errors, and it should also be convenient to not deal with I/O errors. Rust's I/O employs a combination of techniques to reduce boilerplate while still providing feedback about errors. The basic strategy: -* Errors are fatal by default, resulting in task failure -* Errors raise the `io_error` condition which provides an opportunity to inspect - an IoError object containing details. -* Return values must have a sensible null or zero value which is returned - if a condition is handled successfully. This may be an `Option`, an empty - vector, or other designated error value. -* Common traits are implemented for `Option`, e.g. `impl<R: Reader> Reader for Option<R>`, - so that nullable values do not have to be 'unwrapped' before use. +* All I/O operations return `IoResult<T>` which is equivalent to + `Result<T, IoError>`. The core `Result` type is defined in the `std::result` + module. +* If the `Result` type goes unused, then the compiler will by default emit a + warning about the unused result. +* Common traits are implemented for `IoResult`, e.g. + `impl<R: Reader> Reader for IoResult<R>`, so that error values do not have + to be 'unwrapped' before use. These features combine in the API to allow for expressions like `File::create(&Path::new("diary.txt")).write(bytes!("Met a girl.\n"))` without having to worry about whether "diary.txt" exists or whether the write succeeds. As written, if either `new` or `write_line` -encounters an error the task will fail. +encounters an error then the result of the entire expression will +be an error. If you wanted to handle the error though you might write: ```rust +# #[allow(unused_must_use)]; use std::io::File; -use std::io::{IoError, io_error}; -let mut error = None; -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"); +match File::create(&Path::new("diary.txt")).write(bytes!("Met a girl.\n")) { + Ok(()) => { /* succeeded */ } + Err(e) => println!("failed to write to my diary: {}", e), } + # ::std::io::fs::unlink(&Path::new("diary.txt")); ``` -FIXME: Need better condition handling syntax - -In this case the condition handler will have the opportunity to -inspect the IoError raised by either the call to `new` or the call to -`write_line`, but then execution will continue. - -So what actually happens if `new` encounters an error? To understand -that it's important to know that what `new` returns is not a `File` -but an `Option<File>`. If the file does not open, and the condition -is handled, then `new` will simply return `None`. Because there is an -implementation of `Writer` (the trait required ultimately required for -types to implement `write_line`) there is no need to inspect or unwrap -the `Option<File>` and we simply call `write_line` on it. If `new` -returned a `None` then the followup call to `write_line` will also -raise an error. - -## Concerns about this strategy - -This structure will encourage a programming style that is prone -to errors similar to null pointer dereferences. -In particular code written to ignore errors and expect conditions to be unhandled -will start passing around null or zero objects when wrapped in a condition handler. - -* FIXME: How should we use condition handlers that return values? -* FIXME: Should EOF raise default conditions when EOF is not an error? +So what actually happens if `create` encounters an error? +It's important to know that what `new` returns is not a `File` +but an `IoResult<File>`. If the file does not open, then `new` will simply +return `Err(..)`. Because there is an implementation of `Writer` (the trait +required ultimately required for types to implement `write_line`) there is no +need to inspect or unwrap the `IoResult<File>` and we simply call `write_line` +on it. If `new` returned an `Err(..)` then the followup call to `write_line` +will also return an error. # Issues with i/o scheduler affinity, work stealing, task pinning @@ -287,18 +262,19 @@ Out of scope */ #[allow(missing_doc)]; +#[deny(unused_must_use)]; use cast; use char::Char; -use condition::Guard; use container::Container; +use fmt; use int; use iter::Iterator; use option::{Option, Some, None}; use path::Path; use result::{Ok, Err, Result}; -use str; use str::{StrSlice, OwnedStr}; +use str; use to_str::ToStr; use uint; use unstable::finally::Finally; @@ -347,8 +323,8 @@ mod mem; /// Non-blocking access to stdin, stdout, stderr pub mod stdio; -/// Implementations for Option -mod option; +/// Implementations for Result +mod result; /// Extension traits pub mod extensions; @@ -373,17 +349,30 @@ mod comm_adapters; // https://groups.google.com/forum/#!topic/libuv/oQO1HJAIDdA static DEFAULT_BUF_SIZE: uint = 1024 * 64; +pub type IoResult<T> = Result<T, IoError>; + /// The type passed to I/O condition handlers to indicate error /// /// # FIXME /// /// Is something like this sufficient? It's kind of archaic +#[deriving(Eq, Clone)] pub struct IoError { kind: IoErrorKind, desc: &'static str, detail: Option<~str> } +impl fmt::Show for IoError { + fn fmt(err: &IoError, fmt: &mut fmt::Formatter) -> fmt::Result { + if_ok!(fmt.buf.write_str(err.desc)); + match err.detail { + Some(ref s) => write!(fmt.buf, " ({})", *s), + None => Ok(()) + } + } +} + // FIXME: #8242 implementing manually because deriving doesn't work for some reason impl ToStr for IoError { fn to_str(&self) -> ~str { @@ -398,9 +387,8 @@ impl ToStr for IoError { } } -#[deriving(Eq)] +#[deriving(Eq, Clone)] pub enum IoErrorKind { - PreviousIoError, OtherIoError, EndOfFile, FileNotFound, @@ -424,7 +412,6 @@ pub enum IoErrorKind { impl ToStr for IoErrorKind { fn to_str(&self) -> ~str { match *self { - PreviousIoError => ~"PreviousIoError", OtherIoError => ~"OtherIoError", EndOfFile => ~"EndOfFile", FileNotFound => ~"FileNotFound", @@ -446,184 +433,130 @@ impl ToStr for IoErrorKind { } } -// FIXME: Can't put doc comments on macros -// Raised by `I/O` operations on error. -condition! { - pub io_error: IoError -> (); -} - -/// Helper for wrapper calls where you want to -/// ignore any io_errors that might be raised -pub fn ignore_io_error() -> Guard<'static,IoError,()> { - io_error::cond.trap(|_| { - // just swallow the error.. downstream users - // who can make a decision based on a None result - // won't care - }).guard() -} - -/// Helper for catching an I/O error and wrapping it in a Result object. The -/// return result will be the last I/O error that happened or the result of the -/// closure if no error occurred. -pub fn result<T>(cb: || -> T) -> Result<T, IoError> { - let mut err = None; - let ret = io_error::cond.trap(|e| { - if err.is_none() { - err = Some(e); - } - }).inside(cb); - match err { - Some(e) => Err(e), - None => Ok(ret), - } -} - pub trait Reader { - // Only two methods which need to get implemented for this trait + // Only method which need to get implemented for this trait /// Read bytes, up to the length of `buf` and place them in `buf`. /// Returns the number of bytes read. The number of bytes read my - /// be less than the number requested, even 0. Returns `None` on EOF. - /// - /// # Failure + /// be less than the number requested, even 0. Returns `Err` on EOF. /// - /// Raises the `io_error` condition on error. If the condition - /// is handled then no guarantee is made about the number of bytes - /// read and the contents of `buf`. If the condition is handled - /// returns `None` (FIXME see below). + /// # Error /// - /// # FIXME - /// - /// * Should raise_default error on eof? - /// * If the condition is handled it should still return the bytes read, - /// in which case there's no need to return Option - but then you *have* - /// to install a handler to detect eof. - /// - /// This doesn't take a `len` argument like the old `read`. - /// Will people often need to slice their vectors to call this - /// and will that be annoying? - /// Is it actually possible for 0 bytes to be read successfully? - fn read(&mut self, buf: &mut [u8]) -> Option<uint>; + /// If an error occurs during this I/O operation, then it is returned as + /// `Err(IoError)`. Note that end-of-file is considered an error, and can be + /// inspected for in the error's `kind` field. Also note that reading 0 + /// bytes is not considered an error in all circumstances + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint>; // Convenient helper methods based on the above methods - /// Reads a single byte. Returns `None` on EOF. - /// - /// # Failure - /// - /// Raises the same conditions as the `read` method. Returns - /// `None` if the condition is handled. - fn read_byte(&mut self) -> Option<u8> { + /// Reads a single byte. Returns `Err` on EOF. + fn read_byte(&mut self) -> IoResult<u8> { let mut buf = [0]; - match self.read(buf) { - Some(0) => { - debug!("read 0 bytes. trying again"); - self.read_byte() + loop { + match self.read(buf) { + Ok(0) => { + debug!("read 0 bytes. trying again"); + } + Ok(1) => return Ok(buf[0]), + Ok(_) => unreachable!(), + Err(e) => return Err(e) } - Some(1) => Some(buf[0]), - Some(_) => unreachable!(), - None => None } } /// Reads `len` bytes and appends them to a vector. /// /// May push fewer than the requested number of bytes on error - /// or EOF. Returns true on success, false on EOF or error. - /// - /// # Failure - /// - /// Raises the same conditions as `read`. Additionally raises `io_error` - /// on EOF. If `io_error` is handled then `push_bytes` may push less - /// than the requested number of bytes. - fn push_bytes(&mut self, buf: &mut ~[u8], len: uint) { - unsafe { - let start_len = buf.len(); - let mut total_read = 0; - - buf.reserve_additional(len); - buf.set_len(start_len + len); - - (|| { - while total_read < len { - let len = buf.len(); - let slice = buf.mut_slice(start_len + total_read, len); - match self.read(slice) { - Some(nread) => { - total_read += nread; - } - None => { - io_error::cond.raise(standard_error(EndOfFile)); - break; - } + /// or EOF. If `Ok(())` is returned, then all of the requested bytes were + /// pushed on to the vector, otherwise the amount `len` bytes couldn't be + /// read (an error was encountered), and the error is returned. + fn push_bytes(&mut self, buf: &mut ~[u8], len: uint) -> IoResult<()> { + let start_len = buf.len(); + let mut total_read = 0; + + buf.reserve_additional(len); + unsafe { buf.set_len(start_len + len); } + + (|| { + while total_read < len { + let len = buf.len(); + let slice = buf.mut_slice(start_len + total_read, len); + match self.read(slice) { + Ok(nread) => { + total_read += nread; } + Err(e) => return Err(e) } - }).finally(|| buf.set_len(start_len + total_read)) - } + } + Ok(()) + }).finally(|| unsafe { buf.set_len(start_len + total_read) }) } /// Reads `len` bytes and gives you back a new vector of length `len` /// - /// # Failure + /// # Error /// - /// Raises the same conditions as `read`. Additionally raises `io_error` - /// on EOF. If `io_error` is handled then the returned vector may - /// contain less than the requested number of bytes. - fn read_bytes(&mut self, len: uint) -> ~[u8] { + /// Fails with the same conditions as `read`. Additionally returns error on + /// on EOF. Note that if an error is returned, then some number of bytes may + /// have already been consumed from the underlying reader, and they are lost + /// (not returned as part of the error). If this is unacceptable, then it is + /// recommended to use the `push_bytes` or `read` methods. + fn read_bytes(&mut self, len: uint) -> IoResult<~[u8]> { let mut buf = vec::with_capacity(len); - self.push_bytes(&mut buf, len); - return buf; + match self.push_bytes(&mut buf, len) { + Ok(()) => Ok(buf), + Err(e) => Err(e), + } } /// Reads all remaining bytes from the stream. /// - /// # Failure + /// # Error /// - /// Raises the same conditions as the `read` method except for - /// `EndOfFile` which is swallowed. - fn read_to_end(&mut self) -> ~[u8] { + /// Returns any non-EOF error immediately. Previously read bytes are + /// discarded when an error is returned. + /// + /// When EOF is encountered, all bytes read up to that point are returned. + fn read_to_end(&mut self) -> IoResult<~[u8]> { let mut buf = vec::with_capacity(DEFAULT_BUF_SIZE); - let mut keep_reading = true; - io_error::cond.trap(|e| { - if e.kind == EndOfFile { - keep_reading = false; - } else { - io_error::cond.raise(e) - } - }).inside(|| { - while keep_reading { - self.push_bytes(&mut buf, DEFAULT_BUF_SIZE) + loop { + match self.push_bytes(&mut buf, DEFAULT_BUF_SIZE) { + Ok(()) => {} + Err(ref e) if e.kind == EndOfFile => break, + Err(e) => return Err(e) } - }); - return buf; + } + return Ok(buf); } /// Reads all of the remaining bytes of this stream, interpreting them as a /// UTF-8 encoded stream. The corresponding string is returned. /// - /// # Failure + /// # Error /// - /// This function will raise all the same conditions as the `read` method, - /// along with raising a condition if the input is not valid UTF-8. - fn read_to_str(&mut self) -> ~str { - match str::from_utf8_owned(self.read_to_end()) { - Some(s) => s, - None => { - io_error::cond.raise(standard_error(InvalidInput)); - ~"" + /// This function returns all of the same errors as `read_to_end` with an + /// additional error if the reader's contents are not a valid sequence of + /// UTF-8 bytes. + fn read_to_str(&mut self) -> IoResult<~str> { + self.read_to_end().and_then(|s| { + match str::from_utf8_owned(s) { + Some(s) => Ok(s), + None => Err(standard_error(InvalidInput)), } - } + }) } /// Create an iterator that reads a single byte on /// each iteration, until EOF. /// - /// # Failure + /// # Error /// - /// Raises the same conditions as the `read` method, for - /// each call to its `.next()` method. - /// Ends the iteration if the condition is handled. + /// 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. fn bytes<'r>(&'r mut self) -> extensions::Bytes<'r, Self> { extensions::Bytes::new(self) } @@ -633,225 +566,219 @@ pub trait Reader { /// Reads `n` little-endian unsigned integer bytes. /// /// `n` must be between 1 and 8, inclusive. - fn read_le_uint_n(&mut self, nbytes: uint) -> u64 { + fn read_le_uint_n(&mut self, nbytes: uint) -> IoResult<u64> { assert!(nbytes > 0 && nbytes <= 8); let mut val = 0u64; let mut pos = 0; let mut i = nbytes; while i > 0 { - val += (self.read_u8() as u64) << pos; + val += (if_ok!(self.read_u8()) as u64) << pos; pos += 8; i -= 1; } - val + Ok(val) } /// Reads `n` little-endian signed integer bytes. /// /// `n` must be between 1 and 8, inclusive. - fn read_le_int_n(&mut self, nbytes: uint) -> i64 { - extend_sign(self.read_le_uint_n(nbytes), nbytes) + fn read_le_int_n(&mut self, nbytes: uint) -> IoResult<i64> { + self.read_le_uint_n(nbytes).map(|i| extend_sign(i, nbytes)) } /// Reads `n` big-endian unsigned integer bytes. /// /// `n` must be between 1 and 8, inclusive. - fn read_be_uint_n(&mut self, nbytes: uint) -> u64 { + fn read_be_uint_n(&mut self, nbytes: uint) -> IoResult<u64> { assert!(nbytes > 0 && nbytes <= 8); let mut val = 0u64; let mut i = nbytes; while i > 0 { i -= 1; - val += (self.read_u8() as u64) << i * 8; + val += (if_ok!(self.read_u8()) as u64) << i * 8; } - val + Ok(val) } /// Reads `n` big-endian signed integer bytes. /// /// `n` must be between 1 and 8, inclusive. - fn read_be_int_n(&mut self, nbytes: uint) -> i64 { - extend_sign(self.read_be_uint_n(nbytes), nbytes) + fn read_be_int_n(&mut self, nbytes: uint) -> IoResult<i64> { + self.read_be_uint_n(nbytes).map(|i| extend_sign(i, nbytes)) } /// Reads a little-endian unsigned integer. /// /// The number of bytes returned is system-dependant. - fn read_le_uint(&mut self) -> uint { - self.read_le_uint_n(uint::BYTES) as uint + fn read_le_uint(&mut self) -> IoResult<uint> { + self.read_le_uint_n(uint::BYTES).map(|i| i as uint) } /// Reads a little-endian integer. /// /// The number of bytes returned is system-dependant. - fn read_le_int(&mut self) -> int { - self.read_le_int_n(int::BYTES) as int + fn read_le_int(&mut self) -> IoResult<int> { + self.read_le_int_n(int::BYTES).map(|i| i as int) } /// Reads a big-endian unsigned integer. /// /// The number of bytes returned is system-dependant. - fn read_be_uint(&mut self) -> uint { - self.read_be_uint_n(uint::BYTES) as uint + fn read_be_uint(&mut self) -> IoResult<uint> { + self.read_be_uint_n(uint::BYTES).map(|i| i as uint) } /// Reads a big-endian integer. /// /// The number of bytes returned is system-dependant. - fn read_be_int(&mut self) -> int { - self.read_be_int_n(int::BYTES) as int + fn read_be_int(&mut self) -> IoResult<int> { + self.read_be_int_n(int::BYTES).map(|i| i as int) } /// Reads a big-endian `u64`. /// /// `u64`s are 8 bytes long. - fn read_be_u64(&mut self) -> u64 { + fn read_be_u64(&mut self) -> IoResult<u64> { self.read_be_uint_n(8) } /// Reads a big-endian `u32`. /// /// `u32`s are 4 bytes long. - fn read_be_u32(&mut self) -> u32 { - self.read_be_uint_n(4) as u32 + fn read_be_u32(&mut self) -> IoResult<u32> { + self.read_be_uint_n(4).map(|i| i as u32) } /// Reads a big-endian `u16`. /// /// `u16`s are 2 bytes long. - fn read_be_u16(&mut self) -> u16 { - self.read_be_uint_n(2) as u16 + fn read_be_u16(&mut self) -> IoResult<u16> { + self.read_be_uint_n(2).map(|i| i as u16) } /// Reads a big-endian `i64`. /// /// `i64`s are 8 bytes long. - fn read_be_i64(&mut self) -> i64 { + fn read_be_i64(&mut self) -> IoResult<i64> { self.read_be_int_n(8) } /// Reads a big-endian `i32`. /// /// `i32`s are 4 bytes long. - fn read_be_i32(&mut self) -> i32 { - self.read_be_int_n(4) as i32 + fn read_be_i32(&mut self) -> IoResult<i32> { + self.read_be_int_n(4).map(|i| i as i32) } /// Reads a big-endian `i16`. /// /// `i16`s are 2 bytes long. - fn read_be_i16(&mut self) -> i16 { - self.read_be_int_n(2) as i16 + fn read_be_i16(&mut self) -> IoResult<i16> { + self.read_be_int_n(2).map(|i| i as i16) } /// Reads a big-endian `f64`. /// /// `f64`s are 8 byte, IEEE754 double-precision floating point numbers. - fn read_be_f64(&mut self) -> f64 { - unsafe { - cast::transmute::<u64, f64>(self.read_be_u64()) - } + fn read_be_f64(&mut self) -> IoResult<f64> { + self.read_be_u64().map(|i| unsafe { + cast::transmute::<u64, f64>(i) + }) } /// Reads a big-endian `f32`. /// /// `f32`s are 4 byte, IEEE754 single-precision floating point numbers. - fn read_be_f32(&mut self) -> f32 { - unsafe { - cast::transmute::<u32, f32>(self.read_be_u32()) - } + fn read_be_f32(&mut self) -> IoResult<f32> { + self.read_be_u32().map(|i| unsafe { + cast::transmute::<u32, f32>(i) + }) } /// Reads a little-endian `u64`. /// /// `u64`s are 8 bytes long. - fn read_le_u64(&mut self) -> u64 { + fn read_le_u64(&mut self) -> IoResult<u64> { self.read_le_uint_n(8) } /// Reads a little-endian `u32`. /// /// `u32`s are 4 bytes long. - fn read_le_u32(&mut self) -> u32 { - self.read_le_uint_n(4) as u32 + fn read_le_u32(&mut self) -> IoResult<u32> { + self.read_le_uint_n(4).map(|i| i as u32) } /// Reads a little-endian `u16`. /// /// `u16`s are 2 bytes long. - fn read_le_u16(&mut self) -> u16 { - self.read_le_uint_n(2) as u16 + fn read_le_u16(&mut self) -> IoResult<u16> { + self.read_le_uint_n(2).map(|i| i as u16) } /// Reads a little-endian `i64`. /// /// `i64`s are 8 bytes long. - fn read_le_i64(&mut self) -> i64 { + fn read_le_i64(&mut self) -> IoResult<i64> { self.read_le_int_n(8) } /// Reads a little-endian `i32`. /// /// `i32`s are 4 bytes long. - fn read_le_i32(&mut self) -> i32 { - self.read_le_int_n(4) as i32 + fn read_le_i32(&mut self) -> IoResult<i32> { + self.read_le_int_n(4).map(|i| i as i32) } /// Reads a little-endian `i16`. /// /// `i16`s are 2 bytes long. - fn read_le_i16(&mut self) -> i16 { - self.read_le_int_n(2) as i16 + fn read_le_i16(&mut self) -> IoResult<i16> { + self.read_le_int_n(2).map(|i| i as i16) } /// Reads a little-endian `f64`. /// /// `f64`s are 8 byte, IEEE754 double-precision floating point numbers. - fn read_le_f64(&mut self) -> f64 { - unsafe { - cast::transmute::<u64, f64>(self.read_le_u64()) - } + fn read_le_f64(&mut self) -> IoResult<f64> { + self.read_le_u64().map(|i| unsafe { + cast::transmute::<u64, f64>(i) + }) } /// Reads a little-endian `f32`. /// /// `f32`s are 4 byte, IEEE754 single-precision floating point numbers. - fn read_le_f32(&mut self) -> f32 { - unsafe { - cast::transmute::<u32, f32>(self.read_le_u32()) - } + fn read_le_f32(&mut self) -> IoResult<f32> { + self.read_le_u32().map(|i| unsafe { + cast::transmute::<u32, f32>(i) + }) } /// Read a u8. /// /// `u8`s are 1 byte. - fn read_u8(&mut self) -> u8 { - match self.read_byte() { - Some(b) => b, - None => 0 - } + fn read_u8(&mut self) -> IoResult<u8> { + self.read_byte() } /// Read an i8. /// /// `i8`s are 1 byte. - fn read_i8(&mut self) -> i8 { - match self.read_byte() { - Some(b) => b as i8, - None => 0 - } + fn read_i8(&mut self) -> IoResult<i8> { + self.read_byte().map(|i| i as i8) } } impl Reader for ~Reader { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.read(buf) } + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.read(buf) } } impl<'a> Reader for &'a mut Reader { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.read(buf) } + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.read(buf) } } fn extend_sign(val: u64, nbytes: uint) -> i64 { @@ -860,19 +787,22 @@ fn extend_sign(val: u64, nbytes: uint) -> i64 { } pub trait Writer { - /// Write the given buffer + /// Write the entirety of a given buffer /// - /// # Failure + /// # Errors /// - /// Raises the `io_error` condition on error - fn write(&mut self, buf: &[u8]); + /// If an error happens during the I/O operation, the error is returned as + /// `Err`. Note that it is considered an error if the entire buffer could + /// not be written, and if an error is returned then it is unknown how much + /// data (if any) was actually written. + fn write(&mut self, buf: &[u8]) -> IoResult<()>; /// Flush this output stream, ensuring that all intermediately buffered /// contents reach their destination. /// /// This is by default a no-op and implementers of the `Writer` trait should /// decide whether their stream needs to be buffered or not. - fn flush(&mut self) {} + fn flush(&mut self) -> IoResult<()> { Ok(()) } /// Write a rust string into this sink. /// @@ -880,8 +810,8 @@ pub trait Writer { /// If other encodings are desired, it is recommended to compose this stream /// with another performing the conversion, or to use `write` with a /// converted byte-array instead. - fn write_str(&mut self, s: &str) { - self.write(s.as_bytes()); + fn write_str(&mut self, s: &str) -> IoResult<()> { + self.write(s.as_bytes()) } /// Writes a string into this sink, and then writes a literal newline (`\n`) @@ -891,125 +821,124 @@ pub trait Writer { /// /// If other encodings or line ending flavors are desired, it is recommended /// that the `write` method is used specifically instead. - fn write_line(&mut self, s: &str) { - self.write_str(s); - self.write(['\n' as u8]); + fn write_line(&mut self, s: &str) -> IoResult<()> { + self.write_str(s).and_then(|()| self.write(['\n' as u8])) } /// Write a single char, encoded as UTF-8. - fn write_char(&mut self, c: char) { + fn write_char(&mut self, c: char) -> IoResult<()> { let mut buf = [0u8, ..4]; let n = c.encode_utf8(buf.as_mut_slice()); - self.write(buf.slice_to(n)); + self.write(buf.slice_to(n)) } /// Write the result of passing n through `int::to_str_bytes`. - fn write_int(&mut self, n: int) { + fn write_int(&mut self, n: int) -> IoResult<()> { int::to_str_bytes(n, 10u, |bytes| self.write(bytes)) } /// Write the result of passing n through `uint::to_str_bytes`. - fn write_uint(&mut self, n: uint) { + fn write_uint(&mut self, n: uint) -> IoResult<()> { uint::to_str_bytes(n, 10u, |bytes| self.write(bytes)) } /// Write a little-endian uint (number of bytes depends on system). - fn write_le_uint(&mut self, n: uint) { + fn write_le_uint(&mut self, n: uint) -> IoResult<()> { extensions::u64_to_le_bytes(n as u64, uint::BYTES, |v| self.write(v)) } /// Write a little-endian int (number of bytes depends on system). - fn write_le_int(&mut self, n: int) { + fn write_le_int(&mut self, n: int) -> IoResult<()> { extensions::u64_to_le_bytes(n as u64, int::BYTES, |v| self.write(v)) } /// Write a big-endian uint (number of bytes depends on system). - fn write_be_uint(&mut self, n: uint) { + fn write_be_uint(&mut self, n: uint) -> IoResult<()> { extensions::u64_to_be_bytes(n as u64, uint::BYTES, |v| self.write(v)) } /// Write a big-endian int (number of bytes depends on system). - fn write_be_int(&mut self, n: int) { + fn write_be_int(&mut self, n: int) -> IoResult<()> { extensions::u64_to_be_bytes(n as u64, int::BYTES, |v| self.write(v)) } /// Write a big-endian u64 (8 bytes). - fn write_be_u64(&mut self, n: u64) { + fn write_be_u64(&mut self, n: u64) -> IoResult<()> { extensions::u64_to_be_bytes(n, 8u, |v| self.write(v)) } /// Write a big-endian u32 (4 bytes). - fn write_be_u32(&mut self, n: u32) { + fn write_be_u32(&mut self, n: u32) -> IoResult<()> { extensions::u64_to_be_bytes(n as u64, 4u, |v| self.write(v)) } /// Write a big-endian u16 (2 bytes). - fn write_be_u16(&mut self, n: u16) { + fn write_be_u16(&mut self, n: u16) -> IoResult<()> { extensions::u64_to_be_bytes(n as u64, 2u, |v| self.write(v)) } /// Write a big-endian i64 (8 bytes). - fn write_be_i64(&mut self, n: i64) { + fn write_be_i64(&mut self, n: i64) -> IoResult<()> { extensions::u64_to_be_bytes(n as u64, 8u, |v| self.write(v)) } /// Write a big-endian i32 (4 bytes). - fn write_be_i32(&mut self, n: i32) { + fn write_be_i32(&mut self, n: i32) -> IoResult<()> { extensions::u64_to_be_bytes(n as u64, 4u, |v| self.write(v)) } /// Write a big-endian i16 (2 bytes). - fn write_be_i16(&mut self, n: i16) { + fn write_be_i16(&mut self, n: i16) -> IoResult<()> { extensions::u64_to_be_bytes(n as u64, 2u, |v| self.write(v)) } /// Write a big-endian IEEE754 double-precision floating-point (8 bytes). - fn write_be_f64(&mut self, f: f64) { + fn write_be_f64(&mut self, f: f64) -> IoResult<()> { unsafe { self.write_be_u64(cast::transmute(f)) } } /// Write a big-endian IEEE754 single-precision floating-point (4 bytes). - fn write_be_f32(&mut self, f: f32) { + fn write_be_f32(&mut self, f: f32) -> IoResult<()> { unsafe { self.write_be_u32(cast::transmute(f)) } } /// Write a little-endian u64 (8 bytes). - fn write_le_u64(&mut self, n: u64) { + fn write_le_u64(&mut self, n: u64) -> IoResult<()> { extensions::u64_to_le_bytes(n, 8u, |v| self.write(v)) } /// Write a little-endian u32 (4 bytes). - fn write_le_u32(&mut self, n: u32) { + fn write_le_u32(&mut self, n: u32) -> IoResult<()> { extensions::u64_to_le_bytes(n as u64, 4u, |v| self.write(v)) } /// Write a little-endian u16 (2 bytes). - fn write_le_u16(&mut self, n: u16) { + fn write_le_u16(&mut self, n: u16) -> IoResult<()> { extensions::u64_to_le_bytes(n as u64, 2u, |v| self.write(v)) } /// Write a little-endian i64 (8 bytes). - fn write_le_i64(&mut self, n: i64) { + fn write_le_i64(&mut self, n: i64) -> IoResult<()> { extensions::u64_to_le_bytes(n as u64, 8u, |v| self.write(v)) } /// Write a little-endian i32 (4 bytes). - fn write_le_i32(&mut self, n: i32) { + fn write_le_i32(&mut self, n: i32) -> IoResult<()> { extensions::u64_to_le_bytes(n as u64, 4u, |v| self.write(v)) } /// Write a little-endian i16 (2 bytes). - fn write_le_i16(&mut self, n: i16) { + fn write_le_i16(&mut self, n: i16) -> IoResult<()> { extensions::u64_to_le_bytes(n as u64, 2u, |v| self.write(v)) } /// Write a little-endian IEEE754 double-precision floating-point /// (8 bytes). - fn write_le_f64(&mut self, f: f64) { + fn write_le_f64(&mut self, f: f64) -> IoResult<()> { unsafe { self.write_le_u64(cast::transmute(f)) } @@ -1017,31 +946,31 @@ pub trait Writer { /// Write a little-endian IEEE754 single-precision floating-point /// (4 bytes). - fn write_le_f32(&mut self, f: f32) { + fn write_le_f32(&mut self, f: f32) -> IoResult<()> { unsafe { self.write_le_u32(cast::transmute(f)) } } /// Write a u8 (1 byte). - fn write_u8(&mut self, n: u8) { + fn write_u8(&mut self, n: u8) -> IoResult<()> { self.write([n]) } /// Write a i8 (1 byte). - fn write_i8(&mut self, n: i8) { + fn write_i8(&mut self, n: i8) -> IoResult<()> { self.write([n as u8]) } } impl Writer for ~Writer { - fn write(&mut self, buf: &[u8]) { self.write(buf) } - fn flush(&mut self) { self.flush() } + fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.write(buf) } + fn flush(&mut self) -> IoResult<()> { self.flush() } } impl<'a> Writer for &'a mut Writer { - fn write(&mut self, buf: &[u8]) { self.write(buf) } - fn flush(&mut self) { self.flush() } + fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.write(buf) } + fn flush(&mut self) -> IoResult<()> { self.flush() } } pub trait Stream: Reader + Writer { } @@ -1057,18 +986,18 @@ impl<T: Reader + Writer> Stream for T {} /// an iteration, but continue to yield elements if iteration /// is attempted again. /// -/// # Failure +/// # Error /// -/// Raises the same conditions as the `read` method except for `EndOfFile` -/// which is swallowed. -/// Iteration yields `None` if the condition is handled. +/// 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. 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() + self.buffer.read_line().ok() } } @@ -1085,11 +1014,12 @@ pub trait Buffer: Reader { /// consumed from this buffer returned to ensure that the bytes are never /// returned twice. /// - /// # Failure + /// # Error /// - /// This function will raise on the `io_error` condition if a read error is - /// encountered. - fn fill<'a>(&'a mut self) -> &'a [u8]; + /// This function will return an I/O error if the underlying reader was + /// read, but returned an error. Note that it is not an error to return a + /// 0-length buffer. + fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]>; /// Tells this buffer that `amt` bytes have been consumed from the buffer, /// so they should no longer be returned in calls to `fill` or `read`. @@ -1103,108 +1033,117 @@ pub trait Buffer: Reader { /// /// ```rust /// use std::io::{BufferedReader, stdin}; - /// # let _g = ::std::io::ignore_io_error(); /// /// let mut reader = BufferedReader::new(stdin()); /// - /// let input = reader.read_line().unwrap_or(~"nothing"); + /// let input = reader.read_line().ok().unwrap_or(~"nothing"); /// ``` /// - /// # Failure + /// # Error + /// + /// This function has the same error semantics as `read_until`: + /// + /// * All non-EOF errors will be returned immediately + /// * If an error is returned previously consumed bytes are lost + /// * EOF is only returned if no bytes have been read + /// * Reach EOF may mean that the delimiter is not present in the return + /// value /// - /// This function will raise on the `io_error` condition (except for - /// `EndOfFile` which is swallowed) if a read error is encountered. - /// The task will also fail if sequence of bytes leading up to - /// the newline character are not valid UTF-8. - fn read_line(&mut self) -> Option<~str> { - self.read_until('\n' as u8).map(|line| str::from_utf8_owned(line).unwrap()) + /// Additionally, this function can fail if the line of input read is not a + /// valid UTF-8 sequence of bytes. + fn read_line(&mut self) -> IoResult<~str> { + self.read_until('\n' as u8).and_then(|line| + match str::from_utf8_owned(line) { + Some(s) => Ok(s), + None => Err(standard_error(InvalidInput)), + } + ) } /// Create an iterator that reads a line on each iteration until EOF. /// - /// # Failure + /// # Error /// - /// Iterator raises the same conditions as the `read` method - /// except for `EndOfFile`. + /// 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. fn lines<'r>(&'r mut self) -> Lines<'r, Self> { - Lines { - buffer: self, - } + Lines { buffer: self } } /// Reads a sequence of bytes leading up to a specified delimiter. Once the /// specified byte is encountered, reading ceases and the bytes up to and /// including the delimiter are returned. /// - /// # Failure + /// # Error /// - /// This function will raise on the `io_error` condition if a read error is - /// encountered, except that `EndOfFile` is swallowed. - fn read_until(&mut self, byte: u8) -> Option<~[u8]> { + /// If any I/O error is encountered other than EOF, the error is immediately + /// returned. Note that this may discard bytes which have already been read, + /// and those bytes will *not* be returned. It is recommended to use other + /// methods if this case is worrying. + /// + /// If EOF is encountered, then this function will return EOF if 0 bytes + /// have been read, otherwise the pending byte buffer is returned. This + /// is the reason that the byte buffer returned may not always contain the + /// delimiter. + fn read_until(&mut self, byte: u8) -> IoResult<~[u8]> { let mut res = ~[]; - io_error::cond.trap(|e| { - if e.kind != EndOfFile { - io_error::cond.raise(e); - } - }).inside(|| { - let mut used; - loop { - { - let available = self.fill(); - match available.iter().position(|&b| b == byte) { - Some(i) => { - res.push_all(available.slice_to(i + 1)); - used = i + 1; - break - } - None => { - res.push_all(available); - used = available.len(); - } + let mut used; + loop { + { + let available = match self.fill() { + Ok(n) => n, + Err(ref e) if res.len() > 0 && e.kind == EndOfFile => { + used = 0; + break + } + Err(e) => return Err(e) + }; + match available.iter().position(|&b| b == byte) { + Some(i) => { + res.push_all(available.slice_to(i + 1)); + used = i + 1; + break + } + None => { + res.push_all(available); + used = available.len(); } } - if used == 0 { - break - } - self.consume(used); } self.consume(used); - }); - return if res.len() == 0 {None} else {Some(res)}; - + } + self.consume(used); + Ok(res) } /// Reads the next utf8-encoded character from the underlying stream. /// - /// This will return `None` if the following sequence of bytes in the - /// stream are not a valid utf8-sequence, or if an I/O error is encountered. - /// - /// # Failure - /// - /// This function will raise on the `io_error` condition if a read error is - /// encountered. - fn read_char(&mut self) -> Option<char> { - let width = { - let available = self.fill(); - if available.len() == 0 { return None } // read error - str::utf8_char_width(available[0]) - }; - if width == 0 { return None } // not uf8 - let mut buf = [0, ..4]; + /// # Error + /// + /// If an I/O error occurs, or EOF, then this function will return `Err`. + /// This function will also return error if the stream does not contain a + /// valid utf-8 encoded codepoint as the next few bytes in the stream. + fn read_char(&mut self) -> IoResult<char> { + let first_byte = if_ok!(self.read_byte()); + let width = str::utf8_char_width(first_byte); + if width == 1 { return Ok(first_byte as char) } + if width == 0 { return Err(standard_error(InvalidInput)) } // not utf8 + let mut buf = [first_byte, 0, 0, 0]; { - let mut start = 0; - loop { - match self.read(buf.mut_slice(start, width)) { - Some(n) if n == width - start => break, - Some(n) if n < width - start => { start += n; } - Some(..) | None => return None // read error + let mut start = 1; + while start < width { + match if_ok!(self.read(buf.mut_slice(start, width))) { + n if n == width - start => break, + n if n < width - start => { start += n; } + _ => return Err(standard_error(InvalidInput)), } } } match str::from_utf8(buf.slice_to(width)) { - Some(s) => Some(s.char_at(0)), - None => None + Some(s) => Ok(s.char_at(0)), + None => Err(standard_error(InvalidInput)) } } } @@ -1222,7 +1161,7 @@ pub enum SeekStyle { /// * Are `u64` and `i64` the right choices? pub trait Seek { /// Return position of file cursor in the stream - fn tell(&self) -> u64; + fn tell(&self) -> IoResult<u64>; /// Seek to an offset in a stream /// @@ -1231,31 +1170,35 @@ pub trait Seek { /// # FIXME /// /// * What is the behavior when seeking past the end of a stream? - fn seek(&mut self, pos: i64, style: SeekStyle); + fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()>; } -/// A listener is a value that can consume itself to start listening for connections. +/// A listener is a value that can consume itself to start listening for +/// connections. +/// /// Doing so produces some sort of Acceptor. pub trait Listener<T, A: Acceptor<T>> { /// Spin up the listener and start queuing incoming connections /// - /// # Failure + /// # Error /// - /// Raises `io_error` condition. If the condition is handled, - /// then `listen` returns `None`. - fn listen(self) -> Option<A>; + /// Returns `Err` if this listener could not be bound to listen for + /// connections. In all cases, this listener is consumed. + fn listen(self) -> IoResult<A>; } /// An acceptor is a value that presents incoming connections pub trait Acceptor<T> { /// Wait for and accept an incoming connection /// - /// # Failure - /// Raise `io_error` condition. If the condition is handled, - /// then `accept` returns `None`. - fn accept(&mut self) -> Option<T>; + /// # Error + /// + /// Returns `Err` if an I/O error is encountered. + fn accept(&mut self) -> IoResult<T>; - /// Create an iterator over incoming connection attempts + /// Create an iterator over incoming connection attempts. + /// + /// Note that I/O errors will be yielded by the iterator itself. fn incoming<'r>(&'r mut self) -> IncomingConnections<'r, Self> { IncomingConnections { inc: self } } @@ -1264,23 +1207,22 @@ pub trait Acceptor<T> { /// An infinite iterator over incoming connection attempts. /// Calling `next` will block the task until a connection is attempted. /// -/// Since connection attempts can continue forever, this iterator always returns Some. -/// The Some contains another Option representing whether the connection attempt was succesful. -/// A successful connection will be wrapped in Some. -/// A failed connection is represented as a None and raises a condition. +/// Since connection attempts can continue forever, this iterator always returns +/// `Some`. The `Some` contains the `IoResult` representing whether the +/// connection attempt was succesful. A successful connection will be wrapped +/// in `Ok`. A failed connection is represented as an `Err`. pub struct IncomingConnections<'a, A> { priv inc: &'a mut A, } -impl<'a, T, A: Acceptor<T>> Iterator<Option<T>> for IncomingConnections<'a, A> { - fn next(&mut self) -> Option<Option<T>> { +impl<'a, T, A: Acceptor<T>> Iterator<IoResult<T>> for IncomingConnections<'a, A> { + fn next(&mut self) -> Option<IoResult<T>> { Some(self.inc.accept()) } } pub fn standard_error(kind: IoErrorKind) -> IoError { let desc = match kind { - PreviousIoError => "failing due to previous I/O error", EndOfFile => "end of file", IoUnavailable => "I/O is unavailable", InvalidInput => "invalid input", @@ -1314,7 +1256,7 @@ pub enum FileMode { } /// Access permissions with which the file should be opened. `File`s -/// opened with `Read` will raise an `io_error` condition if written to. +/// opened with `Read` will return an error if written to. pub enum FileAccess { Read, Write, diff --git a/src/libstd/io/net/addrinfo.rs b/src/libstd/io/net/addrinfo.rs index 29bf6261a07..e9ffe97f1c3 100644 --- a/src/libstd/io/net/addrinfo.rs +++ b/src/libstd/io/net/addrinfo.rs @@ -17,8 +17,9 @@ getaddrinfo() */ -use option::{Option, Some, None}; +use io::IoResult; use io::net::ip::{SocketAddr, IpAddr}; +use option::{Option, Some, None}; use rt::rtio::{IoFactory, LocalIo}; use vec::ImmutableVector; @@ -69,11 +70,7 @@ pub struct Info { /// Easy name resolution. Given a hostname, returns the list of IP addresses for /// that hostname. -/// -/// # Failure -/// -/// On failure, this will raise on the `io_error` condition. -pub fn get_host_addresses(host: &str) -> Option<~[IpAddr]> { +pub fn get_host_addresses(host: &str) -> IoResult<~[IpAddr]> { lookup(Some(host), None, None).map(|a| a.map(|i| i.address.ip)) } @@ -87,14 +84,10 @@ pub fn get_host_addresses(host: &str) -> Option<~[IpAddr]> { /// * hint - see the hint structure, and "man -s 3 getaddrinfo", for how this /// controls lookup /// -/// # Failure -/// -/// On failure, this will raise on the `io_error` condition. -/// /// FIXME: this is not public because the `Hint` structure is not ready for public /// consumption just yet. fn lookup(hostname: Option<&str>, servname: Option<&str>, hint: Option<Hint>) - -> Option<~[Info]> { + -> IoResult<~[Info]> { LocalIo::maybe_raise(|io| io.get_host_addresses(hostname, servname, hint)) } @@ -115,6 +108,6 @@ mod test { iotest!(fn issue_10663() { // Something should happen here, but this certainly shouldn't cause // everything to die. The actual outcome we don't care too much about. - get_host_addresses("example.com"); + get_host_addresses("example.com").unwrap(); } #[ignore]) } diff --git a/src/libstd/io/net/tcp.rs b/src/libstd/io/net/tcp.rs index 475e3b206f2..a0bdc193d98 100644 --- a/src/libstd/io/net/tcp.rs +++ b/src/libstd/io/net/tcp.rs @@ -8,11 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use option::{Option, Some, None}; -use result::{Ok, Err}; use io::net::ip::SocketAddr; -use io::{Reader, Writer, Listener, Acceptor}; -use io::{io_error, EndOfFile}; +use io::{Reader, Writer, Listener, Acceptor, IoResult}; use rt::rtio::{IoFactory, LocalIo, RtioSocket, RtioTcpListener}; use rt::rtio::{RtioTcpAcceptor, RtioTcpStream}; @@ -25,57 +22,27 @@ impl TcpStream { TcpStream { obj: s } } - pub fn connect(addr: SocketAddr) -> Option<TcpStream> { + pub fn connect(addr: SocketAddr) -> IoResult<TcpStream> { LocalIo::maybe_raise(|io| { io.tcp_connect(addr).map(TcpStream::new) }) } - pub fn peer_name(&mut self) -> Option<SocketAddr> { - match self.obj.peer_name() { - Ok(pn) => Some(pn), - Err(ioerr) => { - debug!("failed to get peer name: {:?}", ioerr); - io_error::cond.raise(ioerr); - None - } - } + pub fn peer_name(&mut self) -> IoResult<SocketAddr> { + self.obj.peer_name() } - pub fn socket_name(&mut self) -> Option<SocketAddr> { - match self.obj.socket_name() { - Ok(sn) => Some(sn), - Err(ioerr) => { - debug!("failed to get socket name: {:?}", ioerr); - io_error::cond.raise(ioerr); - None - } - } + pub fn socket_name(&mut self) -> IoResult<SocketAddr> { + self.obj.socket_name() } } impl Reader for TcpStream { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { - match self.obj.read(buf) { - Ok(read) => Some(read), - Err(ioerr) => { - // EOF is indicated by returning None - if ioerr.kind != EndOfFile { - io_error::cond.raise(ioerr); - } - return None; - } - } - } + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.obj.read(buf) } } impl Writer for TcpStream { - fn write(&mut self, buf: &[u8]) { - match self.obj.write(buf) { - Ok(_) => (), - Err(ioerr) => io_error::cond.raise(ioerr), - } - } + fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.obj.write(buf) } } pub struct TcpListener { @@ -83,33 +50,20 @@ pub struct TcpListener { } impl TcpListener { - pub fn bind(addr: SocketAddr) -> Option<TcpListener> { + pub fn bind(addr: SocketAddr) -> IoResult<TcpListener> { LocalIo::maybe_raise(|io| { io.tcp_bind(addr).map(|l| TcpListener { obj: l }) }) } - pub fn socket_name(&mut self) -> Option<SocketAddr> { - match self.obj.socket_name() { - Ok(sn) => Some(sn), - Err(ioerr) => { - debug!("failed to get socket name: {:?}", ioerr); - io_error::cond.raise(ioerr); - None - } - } + pub fn socket_name(&mut self) -> IoResult<SocketAddr> { + self.obj.socket_name() } } impl Listener<TcpStream, TcpAcceptor> for TcpListener { - fn listen(self) -> Option<TcpAcceptor> { - match self.obj.listen() { - Ok(acceptor) => Some(TcpAcceptor { obj: acceptor }), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None - } - } + fn listen(self) -> IoResult<TcpAcceptor> { + self.obj.listen().map(|acceptor| TcpAcceptor { obj: acceptor }) } } @@ -118,14 +72,8 @@ pub struct TcpAcceptor { } impl Acceptor<TcpStream> for TcpAcceptor { - fn accept(&mut self) -> Option<TcpStream> { - match self.obj.accept() { - Ok(s) => Some(TcpStream::new(s)), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None - } - } + fn accept(&mut self) -> IoResult<TcpStream> { + self.obj.accept().map(TcpStream::new) } } @@ -138,29 +86,19 @@ mod test { // FIXME #11530 this fails on android because tests are run as root iotest!(fn bind_error() { - let mut called = false; - io_error::cond.trap(|e| { - assert!(e.kind == PermissionDenied); - called = true; - }).inside(|| { - let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 1 }; - let listener = TcpListener::bind(addr); - assert!(listener.is_none()); - }); - assert!(called); + let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 1 }; + match TcpListener::bind(addr) { + Ok(..) => fail!(), + Err(e) => assert_eq!(e.kind, PermissionDenied), + } } #[ignore(cfg(windows))] #[ignore(cfg(target_os = "android"))]) iotest!(fn connect_error() { - let mut called = false; - io_error::cond.trap(|e| { - assert_eq!(e.kind, ConnectionRefused); - called = true; - }).inside(|| { - let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 1 }; - let stream = TcpStream::connect(addr); - assert!(stream.is_none()); - }); - assert!(called); + let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 1 }; + match TcpStream::connect(addr) { + Ok(..) => fail!(), + Err(e) => assert_eq!(e.kind, ConnectionRefused), + } }) iotest!(fn smoke_test_ip4() { @@ -170,14 +108,14 @@ mod test { spawn(proc() { port.recv(); let mut stream = TcpStream::connect(addr); - stream.write([99]); + stream.write([99]).unwrap(); }); let mut acceptor = TcpListener::bind(addr).listen(); chan.send(()); let mut stream = acceptor.accept(); let mut buf = [0]; - stream.read(buf); + stream.read(buf).unwrap(); assert!(buf[0] == 99); }) @@ -188,14 +126,14 @@ mod test { spawn(proc() { port.recv(); let mut stream = TcpStream::connect(addr); - stream.write([99]); + stream.write([99]).unwrap(); }); let mut acceptor = TcpListener::bind(addr).listen(); chan.send(()); let mut stream = acceptor.accept(); let mut buf = [0]; - stream.read(buf); + stream.read(buf).unwrap(); assert!(buf[0] == 99); }) @@ -214,7 +152,7 @@ mod test { let mut stream = acceptor.accept(); let mut buf = [0]; let nread = stream.read(buf); - assert!(nread.is_none()); + assert!(nread.is_err()); }) iotest!(fn read_eof_ip6() { @@ -232,7 +170,7 @@ mod test { let mut stream = acceptor.accept(); let mut buf = [0]; let nread = stream.read(buf); - assert!(nread.is_none()); + assert!(nread.is_err()); }) iotest!(fn read_eof_twice_ip4() { @@ -250,17 +188,15 @@ mod test { let mut stream = acceptor.accept(); let mut buf = [0]; let nread = stream.read(buf); - assert!(nread.is_none()); - io_error::cond.trap(|e| { - if cfg!(windows) { - assert_eq!(e.kind, NotConnected); - } else { - fail!(); + assert!(nread.is_err()); + + match stream.read(buf) { + Ok(..) => fail!(), + Err(ref e) => { + assert!(e.kind == NotConnected || e.kind == EndOfFile, + "unknown kind: {:?}", e.kind); } - }).inside(|| { - let nread = stream.read(buf); - assert!(nread.is_none()); - }) + } }) iotest!(fn read_eof_twice_ip6() { @@ -278,17 +214,15 @@ mod test { let mut stream = acceptor.accept(); let mut buf = [0]; let nread = stream.read(buf); - assert!(nread.is_none()); - io_error::cond.trap(|e| { - if cfg!(windows) { - assert_eq!(e.kind, NotConnected); - } else { - fail!(); + assert!(nread.is_err()); + + match stream.read(buf) { + Ok(..) => fail!(), + Err(ref e) => { + assert!(e.kind == NotConnected || e.kind == EndOfFile, + "unknown kind: {:?}", e.kind); } - }).inside(|| { - let nread = stream.read(buf); - assert!(nread.is_none()); - }) + } }) iotest!(fn write_close_ip4() { @@ -306,19 +240,16 @@ mod test { let mut stream = acceptor.accept(); let buf = [0]; loop { - let mut stop = false; - io_error::cond.trap(|e| { - // NB: ECONNRESET on linux, EPIPE on mac, ECONNABORTED - // on windows - assert!(e.kind == ConnectionReset || - e.kind == BrokenPipe || - e.kind == ConnectionAborted, - "unknown error: {:?}", e); - stop = true; - }).inside(|| { - stream.write(buf); - }); - if stop { break } + match stream.write(buf) { + Ok(..) => {} + Err(e) => { + assert!(e.kind == ConnectionReset || + e.kind == BrokenPipe || + e.kind == ConnectionAborted, + "unknown error: {:?}", e); + break; + } + } } }) @@ -337,19 +268,16 @@ mod test { let mut stream = acceptor.accept(); let buf = [0]; loop { - let mut stop = false; - io_error::cond.trap(|e| { - // NB: ECONNRESET on linux, EPIPE on mac, ECONNABORTED - // on windows - assert!(e.kind == ConnectionReset || - e.kind == BrokenPipe || - e.kind == ConnectionAborted, - "unknown error: {:?}", e); - stop = true; - }).inside(|| { - stream.write(buf); - }); - if stop { break } + match stream.write(buf) { + Ok(..) => {} + Err(e) => { + assert!(e.kind == ConnectionReset || + e.kind == BrokenPipe || + e.kind == ConnectionAborted, + "unknown error: {:?}", e); + break; + } + } } }) @@ -362,7 +290,7 @@ mod test { port.recv(); for _ in range(0, max) { let mut stream = TcpStream::connect(addr); - stream.write([99]); + stream.write([99]).unwrap(); } }); @@ -370,7 +298,7 @@ mod test { chan.send(()); for ref mut stream in acceptor.incoming().take(max) { let mut buf = [0]; - stream.read(buf); + stream.read(buf).unwrap(); assert_eq!(buf[0], 99); } }) @@ -384,7 +312,7 @@ mod test { port.recv(); for _ in range(0, max) { let mut stream = TcpStream::connect(addr); - stream.write([99]); + stream.write([99]).unwrap(); } }); @@ -392,7 +320,7 @@ mod test { chan.send(()); for ref mut stream in acceptor.incoming().take(max) { let mut buf = [0]; - stream.read(buf); + stream.read(buf).unwrap(); assert_eq!(buf[0], 99); } }) @@ -410,7 +338,7 @@ mod test { spawn(proc() { let mut stream = stream; let mut buf = [0]; - stream.read(buf); + stream.read(buf).unwrap(); assert!(buf[0] == i as u8); debug!("read"); }); @@ -429,7 +357,7 @@ mod test { // Connect again before writing connect(i + 1, addr); debug!("writing"); - stream.write([i as u8]); + stream.write([i as u8]).unwrap(); }); } }) @@ -447,7 +375,7 @@ mod test { spawn(proc() { let mut stream = stream; let mut buf = [0]; - stream.read(buf); + stream.read(buf).unwrap(); assert!(buf[0] == i as u8); debug!("read"); }); @@ -466,7 +394,7 @@ mod test { // Connect again before writing connect(i + 1, addr); debug!("writing"); - stream.write([i as u8]); + stream.write([i as u8]).unwrap(); }); } }) @@ -484,7 +412,7 @@ mod test { spawn(proc() { let mut stream = stream; let mut buf = [0]; - stream.read(buf); + stream.read(buf).unwrap(); assert!(buf[0] == 99); debug!("read"); }); @@ -503,7 +431,7 @@ mod test { // Connect again before writing connect(i + 1, addr); debug!("writing"); - stream.write([99]); + stream.write([99]).unwrap(); }); } }) @@ -521,7 +449,7 @@ mod test { spawn(proc() { let mut stream = stream; let mut buf = [0]; - stream.read(buf); + stream.read(buf).unwrap(); assert!(buf[0] == 99); debug!("read"); }); @@ -540,7 +468,7 @@ mod test { // Connect again before writing connect(i + 1, addr); debug!("writing"); - stream.write([99]); + stream.write([99]).unwrap(); }); } }) @@ -551,7 +479,7 @@ mod test { // Make sure socket_name gives // us the socket we binded to. let so_name = listener.socket_name(); - assert!(so_name.is_some()); + assert!(so_name.is_ok()); assert_eq!(addr, so_name.unwrap()); } @@ -561,20 +489,20 @@ mod test { spawn(proc() { let mut acceptor = TcpListener::bind(addr).listen(); chan.send(()); - acceptor.accept(); + acceptor.accept().unwrap(); }); port.recv(); let stream = TcpStream::connect(addr); - assert!(stream.is_some()); + assert!(stream.is_ok()); let mut stream = stream.unwrap(); // Make sure peer_name gives us the // address/port of the peer we've // connected to. let peer_name = stream.peer_name(); - assert!(peer_name.is_some()); + assert!(peer_name.is_ok()); assert_eq!(addr, peer_name.unwrap()); } @@ -593,37 +521,33 @@ mod test { let addr = next_test_ip4(); let (p, c) = Chan::new(); spawn(proc() { - let mut srv = TcpListener::bind(addr).listen(); + let mut srv = TcpListener::bind(addr).listen().unwrap(); c.send(()); let mut cl = srv.accept().unwrap(); - cl.write([10]); + cl.write([10]).unwrap(); let mut b = [0]; - cl.read(b); + cl.read(b).unwrap(); c.send(()); }); p.recv(); let mut c = TcpStream::connect(addr).unwrap(); let mut b = [0, ..10]; - assert_eq!(c.read(b), Some(1)); - c.write([1]); + assert_eq!(c.read(b), Ok(1)); + c.write([1]).unwrap(); p.recv(); }) iotest!(fn double_bind() { - let mut called = false; - io_error::cond.trap(|e| { - assert!(e.kind == ConnectionRefused || e.kind == OtherIoError); - called = true; - }).inside(|| { - let addr = next_test_ip4(); - let listener = TcpListener::bind(addr).unwrap().listen(); - assert!(listener.is_some()); - let listener2 = TcpListener::bind(addr).and_then(|l| - l.listen()); - assert!(listener2.is_none()); - }); - assert!(called); + let addr = next_test_ip4(); + let listener = TcpListener::bind(addr).unwrap().listen(); + assert!(listener.is_ok()); + match TcpListener::bind(addr).listen() { + Ok(..) => fail!(), + Err(e) => { + assert!(e.kind == ConnectionRefused || e.kind == OtherIoError); + } + } }) iotest!(fn fast_rebind() { @@ -632,7 +556,7 @@ mod test { spawn(proc() { port.recv(); - let _stream = TcpStream::connect(addr); + let _stream = TcpStream::connect(addr).unwrap(); // Close port.recv(); }); @@ -641,7 +565,7 @@ mod test { let mut acceptor = TcpListener::bind(addr).listen(); chan.send(()); { - let _stream = acceptor.accept(); + let _stream = acceptor.accept().unwrap(); // Close client chan.send(()); } diff --git a/src/libstd/io/net/udp.rs b/src/libstd/io/net/udp.rs index 1cf30d469f7..0ef62648afc 100644 --- a/src/libstd/io/net/udp.rs +++ b/src/libstd/io/net/udp.rs @@ -8,11 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use option::{Option, Some, None}; use result::{Ok, Err}; use io::net::ip::SocketAddr; -use io::{Reader, Writer}; -use io::{io_error, EndOfFile}; +use io::{Reader, Writer, IoResult}; use rt::rtio::{RtioSocket, RtioUdpSocket, IoFactory, LocalIo}; pub struct UdpSocket { @@ -20,45 +18,26 @@ pub struct UdpSocket { } impl UdpSocket { - pub fn bind(addr: SocketAddr) -> Option<UdpSocket> { + pub fn bind(addr: SocketAddr) -> IoResult<UdpSocket> { LocalIo::maybe_raise(|io| { io.udp_bind(addr).map(|s| UdpSocket { obj: s }) }) } - pub fn recvfrom(&mut self, buf: &mut [u8]) -> Option<(uint, SocketAddr)> { - match self.obj.recvfrom(buf) { - Ok((nread, src)) => Some((nread, src)), - Err(ioerr) => { - // EOF is indicated by returning None - if ioerr.kind != EndOfFile { - io_error::cond.raise(ioerr); - } - None - } - } + pub fn recvfrom(&mut self, buf: &mut [u8]) -> IoResult<(uint, SocketAddr)> { + self.obj.recvfrom(buf) } - pub fn sendto(&mut self, buf: &[u8], dst: SocketAddr) { - match self.obj.sendto(buf, dst) { - Ok(_) => (), - Err(ioerr) => io_error::cond.raise(ioerr), - } + pub fn sendto(&mut self, buf: &[u8], dst: SocketAddr) -> IoResult<()> { + self.obj.sendto(buf, dst) } pub fn connect(self, other: SocketAddr) -> UdpStream { UdpStream { socket: self, connectedTo: other } } - pub fn socket_name(&mut self) -> Option<SocketAddr> { - match self.obj.socket_name() { - Ok(sn) => Some(sn), - Err(ioerr) => { - debug!("failed to get socket name: {:?}", ioerr); - io_error::cond.raise(ioerr); - None - } - } + pub fn socket_name(&mut self) -> IoResult<SocketAddr> { + self.obj.socket_name() } } @@ -76,21 +55,21 @@ impl UdpStream { } impl Reader for UdpStream { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { let peer = self.connectedTo; self.as_socket(|sock| { match sock.recvfrom(buf) { - Some((_nread, src)) if src != peer => Some(0), - Some((nread, _src)) => Some(nread), - None => None, + Ok((_nread, src)) if src != peer => Ok(0), + Ok((nread, _src)) => Ok(nread), + Err(e) => Err(e), } }) } } impl Writer for UdpStream { - fn write(&mut self, buf: &[u8]) { - self.as_socket(|sock| sock.sendto(buf, self.connectedTo)); + fn write(&mut self, buf: &[u8]) -> IoResult<()> { + self.as_socket(|sock| sock.sendto(buf, self.connectedTo)) } } @@ -101,16 +80,11 @@ mod test { // FIXME #11530 this fails on android because tests are run as root iotest!(fn bind_error() { - let mut called = false; - io_error::cond.trap(|e| { - assert_eq!(e.kind, PermissionDenied); - called = true; - }).inside(|| { - let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 1 }; - let socket = UdpSocket::bind(addr); - assert!(socket.is_none()); - }); - assert!(called); + let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 1 }; + match UdpSocket::bind(addr) { + Ok(..) => fail!(), + Err(e) => assert_eq!(e.kind, PermissionDenied), + } } #[ignore(cfg(windows))] #[ignore(cfg(target_os = "android"))]) iotest!(fn socket_smoke_test_ip4() { @@ -121,29 +95,29 @@ mod test { spawn(proc() { match UdpSocket::bind(client_ip) { - Some(ref mut client) => { + Ok(ref mut client) => { port.recv(); - client.sendto([99], server_ip) + client.sendto([99], server_ip).unwrap() } - None => fail!() + Err(..) => fail!() } chan2.send(()); }); match UdpSocket::bind(server_ip) { - Some(ref mut server) => { + Ok(ref mut server) => { chan.send(()); let mut buf = [0]; match server.recvfrom(buf) { - Some((nread, src)) => { + Ok((nread, src)) => { assert_eq!(nread, 1); assert_eq!(buf[0], 99); assert_eq!(src, client_ip); } - None => fail!() + Err(..) => fail!() } } - None => fail!() + Err(..) => fail!() } port2.recv(); }) @@ -155,28 +129,28 @@ mod test { spawn(proc() { match UdpSocket::bind(client_ip) { - Some(ref mut client) => { + Ok(ref mut client) => { port.recv(); - client.sendto([99], server_ip) + client.sendto([99], server_ip).unwrap() } - None => fail!() + Err(..) => fail!() } }); match UdpSocket::bind(server_ip) { - Some(ref mut server) => { + Ok(ref mut server) => { chan.send(()); let mut buf = [0]; match server.recvfrom(buf) { - Some((nread, src)) => { + Ok((nread, src)) => { assert_eq!(nread, 1); assert_eq!(buf[0], 99); assert_eq!(src, client_ip); } - None => fail!() + Err(..) => fail!() } } - None => fail!() + Err(..) => fail!() } }) @@ -188,32 +162,32 @@ mod test { spawn(proc() { match UdpSocket::bind(client_ip) { - Some(client) => { + Ok(client) => { let client = ~client; let mut stream = client.connect(server_ip); port.recv(); - stream.write([99]); + stream.write([99]).unwrap(); } - None => fail!() + Err(..) => fail!() } chan2.send(()); }); match UdpSocket::bind(server_ip) { - Some(server) => { + Ok(server) => { let server = ~server; let mut stream = server.connect(client_ip); chan.send(()); let mut buf = [0]; match stream.read(buf) { - Some(nread) => { + Ok(nread) => { assert_eq!(nread, 1); assert_eq!(buf[0], 99); } - None => fail!() + Err(..) => fail!() } } - None => fail!() + Err(..) => fail!() } port2.recv(); }) @@ -226,32 +200,32 @@ mod test { spawn(proc() { match UdpSocket::bind(client_ip) { - Some(client) => { + Ok(client) => { let client = ~client; let mut stream = client.connect(server_ip); port.recv(); - stream.write([99]); + stream.write([99]).unwrap(); } - None => fail!() + Err(..) => fail!() } chan2.send(()); }); match UdpSocket::bind(server_ip) { - Some(server) => { + Ok(server) => { let server = ~server; let mut stream = server.connect(client_ip); chan.send(()); let mut buf = [0]; match stream.read(buf) { - Some(nread) => { + Ok(nread) => { assert_eq!(nread, 1); assert_eq!(buf[0], 99); } - None => fail!() + Err(..) => fail!() } } - None => fail!() + Err(..) => fail!() } port2.recv(); }) @@ -259,13 +233,13 @@ mod test { pub fn socket_name(addr: SocketAddr) { let server = UdpSocket::bind(addr); - assert!(server.is_some()); + assert!(server.is_ok()); let mut server = server.unwrap(); // Make sure socket_name gives // us the socket we binded to. let so_name = server.socket_name(); - assert!(so_name.is_some()); + assert!(so_name.is_ok()); assert_eq!(addr, so_name.unwrap()); } diff --git a/src/libstd/io/net/unix.rs b/src/libstd/io/net/unix.rs index d470e9bfda1..ce95b987663 100644 --- a/src/libstd/io/net/unix.rs +++ b/src/libstd/io/net/unix.rs @@ -28,7 +28,7 @@ use c_str::ToCStr; use rt::rtio::{IoFactory, LocalIo, RtioUnixListener}; use rt::rtio::{RtioUnixAcceptor, RtioPipe}; use io::pipe::PipeStream; -use io::{io_error, Listener, Acceptor, Reader, Writer}; +use io::{Listener, Acceptor, Reader, Writer, IoResult}; /// A stream which communicates over a named pipe. pub struct UnixStream { @@ -45,20 +45,17 @@ impl UnixStream { /// /// The returned stream will be closed when the object falls out of scope. /// - /// # Failure - /// - /// This function will raise on the `io_error` condition if the connection - /// could not be made. - /// /// # Example /// - /// use std::io::net::unix::UnixStream; + /// ```rust + /// # #[allow(unused_must_use)]; + /// use std::io::net::unix::UnixStream; /// - /// let server = Path("path/to/my/socket"); - /// let mut stream = UnixStream::connect(&server); - /// stream.write([1, 2, 3]); - /// - pub fn connect<P: ToCStr>(path: &P) -> Option<UnixStream> { + /// let server = Path::new("path/to/my/socket"); + /// let mut stream = UnixStream::connect(&server); + /// stream.write([1, 2, 3]); + /// ``` + pub fn connect<P: ToCStr>(path: &P) -> IoResult<UnixStream> { LocalIo::maybe_raise(|io| { io.unix_connect(&path.to_c_str()).map(UnixStream::new) }) @@ -66,11 +63,11 @@ impl UnixStream { } impl Reader for UnixStream { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.obj.read(buf) } + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.obj.read(buf) } } impl Writer for UnixStream { - fn write(&mut self, buf: &[u8]) { self.obj.write(buf) } + fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.obj.write(buf) } } pub struct UnixListener { @@ -84,23 +81,20 @@ impl UnixListener { /// /// This listener will be closed when it falls out of scope. /// - /// # Failure - /// - /// This function will raise on the `io_error` condition if the specified - /// path could not be bound. - /// /// # Example /// - /// use std::io::net::unix::UnixListener; - /// - /// let server = Path("path/to/my/socket"); - /// let mut stream = UnixListener::bind(&server); - /// for client in stream.incoming() { - /// let mut client = client; - /// client.write([1, 2, 3, 4]); - /// } + /// ``` + /// use std::io::net::unix::UnixListener; + /// use std::io::Listener; /// - pub fn bind<P: ToCStr>(path: &P) -> Option<UnixListener> { + /// let server = Path::new("path/to/my/socket"); + /// let mut stream = UnixListener::bind(&server); + /// for client in stream.incoming() { + /// let mut client = client; + /// client.write([1, 2, 3, 4]); + /// } + /// ``` + pub fn bind<P: ToCStr>(path: &P) -> IoResult<UnixListener> { LocalIo::maybe_raise(|io| { io.unix_bind(&path.to_c_str()).map(|s| UnixListener { obj: s }) }) @@ -108,14 +102,8 @@ impl UnixListener { } impl Listener<UnixStream, UnixAcceptor> for UnixListener { - fn listen(self) -> Option<UnixAcceptor> { - match self.obj.listen() { - Ok(acceptor) => Some(UnixAcceptor { obj: acceptor }), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None - } - } + fn listen(self) -> IoResult<UnixAcceptor> { + self.obj.listen().map(|obj| UnixAcceptor { obj: obj }) } } @@ -124,14 +112,8 @@ pub struct UnixAcceptor { } impl Acceptor<UnixStream> for UnixAcceptor { - fn accept(&mut self) -> Option<UnixStream> { - match self.obj.accept() { - Ok(s) => Some(UnixStream::new(s)), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None - } - } + fn accept(&mut self) -> IoResult<UnixStream> { + self.obj.accept().map(UnixStream::new) } } @@ -159,39 +141,29 @@ mod tests { #[test] fn bind_error() { - let mut called = false; - io_error::cond.trap(|e| { - assert!(e.kind == PermissionDenied); - called = true; - }).inside(|| { - let listener = UnixListener::bind(&("path/to/nowhere")); - assert!(listener.is_none()); - }); - assert!(called); + match UnixListener::bind(&("path/to/nowhere")) { + Ok(..) => fail!(), + Err(e) => assert_eq!(e.kind, PermissionDenied), + } } #[test] fn connect_error() { - let mut called = false; - io_error::cond.trap(|e| { - assert_eq!(e.kind, - if cfg!(windows) {OtherIoError} else {FileNotFound}); - called = true; - }).inside(|| { - let stream = UnixStream::connect(&("path/to/nowhere")); - assert!(stream.is_none()); - }); - assert!(called); + match UnixStream::connect(&("path/to/nowhere")) { + Ok(..) => fail!(), + Err(e) => assert_eq!(e.kind, + if cfg!(windows) {OtherIoError} else {FileNotFound}) + } } #[test] fn smoke() { smalltest(proc(mut server) { let mut buf = [0]; - server.read(buf); + server.read(buf).unwrap(); assert!(buf[0] == 99); }, proc(mut client) { - client.write([99]); + client.write([99]).unwrap(); }) } @@ -199,8 +171,8 @@ mod tests { fn read_eof() { smalltest(proc(mut server) { let mut buf = [0]; - assert!(server.read(buf).is_none()); - assert!(server.read(buf).is_none()); + assert!(server.read(buf).is_err()); + assert!(server.read(buf).is_err()); }, proc(_client) { // drop the client }) @@ -210,15 +182,15 @@ mod tests { fn write_begone() { smalltest(proc(mut server) { let buf = [0]; - let mut stop = false; - while !stop{ - io_error::cond.trap(|e| { - assert!(e.kind == BrokenPipe || e.kind == NotConnected, - "unknown error {:?}", e); - stop = true; - }).inside(|| { - server.write(buf); - }) + loop { + match server.write(buf) { + Ok(..) => {} + Err(e) => { + assert!(e.kind == BrokenPipe || e.kind == NotConnected, + "unknown error {:?}", e); + break; + } + } } }, proc(_client) { // drop the client @@ -236,7 +208,7 @@ mod tests { port.recv(); for _ in range(0, times) { let mut stream = UnixStream::connect(&path2); - stream.write([100]); + stream.write([100]).unwrap(); } }); @@ -245,7 +217,7 @@ mod tests { for _ in range(0, times) { let mut client = acceptor.accept(); let mut buf = [0]; - client.read(buf); + client.read(buf).unwrap(); assert_eq!(buf[0], 100); } } diff --git a/src/libstd/io/option.rs b/src/libstd/io/option.rs deleted file mode 100644 index e2eec652d9d..00000000000 --- a/src/libstd/io/option.rs +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementations of I/O traits for the Option type -//! -//! I/O constructors return option types to allow errors to be handled. -//! These implementations allow e.g. `Option<File>` to be used -//! as a `Reader` without unwrapping the option first. - -use option::*; -use super::{Reader, Writer, Listener, Acceptor, Seek, SeekStyle}; -use super::{standard_error, PreviousIoError, io_error, IoError}; - -fn prev_io_error() -> IoError { - standard_error(PreviousIoError) -} - -impl<W: Writer> Writer for Option<W> { - fn write(&mut self, buf: &[u8]) { - match *self { - Some(ref mut writer) => writer.write(buf), - None => io_error::cond.raise(prev_io_error()) - } - } - - fn flush(&mut self) { - match *self { - Some(ref mut writer) => writer.flush(), - None => io_error::cond.raise(prev_io_error()) - } - } -} - -impl<R: Reader> Reader for Option<R> { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { - match *self { - Some(ref mut reader) => reader.read(buf), - None => { - io_error::cond.raise(prev_io_error()); - None - } - } - } -} - -impl<S: Seek> Seek for Option<S> { - fn tell(&self) -> u64 { - match *self { - Some(ref seeker) => seeker.tell(), - None => { - io_error::cond.raise(prev_io_error()); - 0 - } - } - } - fn seek(&mut self, pos: i64, style: SeekStyle) { - match *self { - Some(ref mut seeker) => seeker.seek(pos, style), - None => io_error::cond.raise(prev_io_error()) - } - } -} - -impl<T, A: Acceptor<T>, L: Listener<T, A>> Listener<T, A> for Option<L> { - fn listen(self) -> Option<A> { - match self { - Some(listener) => listener.listen(), - None => { - io_error::cond.raise(prev_io_error()); - None - } - } - } -} - -impl<T, A: Acceptor<T>> Acceptor<T> for Option<A> { - fn accept(&mut self) -> Option<T> { - match *self { - Some(ref mut acceptor) => acceptor.accept(), - None => { - io_error::cond.raise(prev_io_error()); - None - } - } - } -} - -#[cfg(test)] -mod test { - use prelude::*; - use super::super::mem::*; - use super::super::{PreviousIoError, io_error}; - - #[test] - fn test_option_writer() { - let mut writer: Option<MemWriter> = Some(MemWriter::new()); - writer.write([0, 1, 2]); - writer.flush(); - assert_eq!(writer.unwrap().unwrap(), ~[0, 1, 2]); - } - - #[test] - fn test_option_writer_error() { - let mut writer: Option<MemWriter> = None; - - let mut called = false; - io_error::cond.trap(|err| { - assert_eq!(err.kind, PreviousIoError); - called = true; - }).inside(|| { - writer.write([0, 0, 0]); - }); - assert!(called); - - let mut called = false; - io_error::cond.trap(|err| { - assert_eq!(err.kind, PreviousIoError); - called = true; - }).inside(|| { - writer.flush(); - }); - assert!(called); - } - - #[test] - fn test_option_reader() { - let mut reader: Option<MemReader> = Some(MemReader::new(~[0, 1, 2, 3])); - let mut buf = [0, 0]; - reader.read(buf); - assert_eq!(buf, [0, 1]); - } - - #[test] - fn test_option_reader_error() { - let mut reader: Option<MemReader> = None; - let mut buf = []; - - let mut called = false; - io_error::cond.trap(|err| { - assert_eq!(err.kind, PreviousIoError); - called = true; - }).inside(|| { - reader.read(buf); - }); - assert!(called); - } -} diff --git a/src/libstd/io/pipe.rs b/src/libstd/io/pipe.rs index 9919d333f41..ca85707149b 100644 --- a/src/libstd/io/pipe.rs +++ b/src/libstd/io/pipe.rs @@ -14,7 +14,7 @@ //! enough so that pipes can be created to child processes. use prelude::*; -use io::{io_error, EndOfFile}; +use io::IoResult; use libc; use rt::rtio::{RtioPipe, LocalIo}; @@ -32,17 +32,15 @@ impl PipeStream { /// /// # Example /// - /// use std::libc; - /// use std::io::pipe; + /// ```rust + /// # #[allow(unused_must_use)]; + /// use std::libc; + /// use std::io::pipe::PipeStream; /// - /// let mut pipe = PipeStream::open(libc::STDERR_FILENO); - /// pipe.write(bytes!("Hello, stderr!")); - /// - /// # Failure - /// - /// If the pipe cannot be created, an error will be raised on the - /// `io_error` condition. - pub fn open(fd: libc::c_int) -> Option<PipeStream> { + /// let mut pipe = PipeStream::open(libc::STDERR_FILENO); + /// pipe.write(bytes!("Hello, stderr!")); + /// ``` + pub fn open(fd: libc::c_int) -> IoResult<PipeStream> { LocalIo::maybe_raise(|io| { io.pipe_open(fd).map(|obj| PipeStream { obj: obj }) }) @@ -54,29 +52,11 @@ impl PipeStream { } impl Reader for PipeStream { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { - match self.obj.read(buf) { - Ok(read) => Some(read), - Err(ioerr) => { - // EOF is indicated by returning None - if ioerr.kind != EndOfFile { - io_error::cond.raise(ioerr); - } - return None; - } - } - } + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.obj.read(buf) } } impl Writer for PipeStream { - fn write(&mut self, buf: &[u8]) { - match self.obj.write(buf) { - Ok(_) => (), - Err(ioerr) => { - io_error::cond.raise(ioerr); - } - } - } + fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.obj.write(buf) } } #[cfg(test)] @@ -91,12 +71,12 @@ mod test { let (p, c) = Chan::new(); spawn(proc() { let mut out = out; - out.write([10]); + out.write([10]).unwrap(); p.recv(); // don't close the pipe until the other read has finished }); let mut buf = [0, ..10]; - input.read(buf); + input.read(buf).unwrap(); c.send(()); }) } diff --git a/src/libstd/io/process.rs b/src/libstd/io/process.rs index 6a10f24916f..ccf3d4582de 100644 --- a/src/libstd/io/process.rs +++ b/src/libstd/io/process.rs @@ -14,7 +14,7 @@ use prelude::*; use libc; use io; -use io::io_error; +use io::IoResult; use rt::rtio::{RtioProcess, IoFactory, LocalIo}; use fmt; @@ -93,7 +93,7 @@ pub enum ProcessExit { impl fmt::Show for ProcessExit { /// Format a ProcessExit enum, to nicely present the information. - fn fmt(obj: &ProcessExit, f: &mut fmt::Formatter) { + fn fmt(obj: &ProcessExit, f: &mut fmt::Formatter) -> fmt::Result { match *obj { ExitStatus(code) => write!(f.buf, "exit code: {}", code), ExitSignal(code) => write!(f.buf, "signal: {}", code), @@ -118,7 +118,7 @@ impl ProcessExit { impl Process { /// Creates a new pipe initialized, but not bound to any particular /// source/destination - pub fn new(config: ProcessConfig) -> Option<Process> { + pub fn new(config: ProcessConfig) -> IoResult<Process> { let mut config = Some(config); LocalIo::maybe_raise(|io| { io.spawn(config.take_unwrap()).map(|(p, io)| { @@ -141,14 +141,9 @@ impl Process { /// Note that this is purely a wrapper around libuv's `uv_process_kill` /// function. /// - /// If the signal delivery fails, then the `io_error` condition is raised on - pub fn signal(&mut self, signal: int) { - match self.handle.kill(signal) { - Ok(()) => {} - Err(err) => { - io_error::cond.raise(err) - } - } + /// If the signal delivery fails, the corresponding error is returned. + pub fn signal(&mut self, signal: int) -> IoResult<()> { + self.handle.kill(signal) } /// Wait for the child to exit completely, returning the status that it @@ -176,7 +171,6 @@ impl Drop for Process { mod tests { use io::process::{ProcessConfig, Process}; use prelude::*; - use str; // FIXME(#10380) #[cfg(unix, not(target_os="android"))] @@ -190,7 +184,7 @@ mod tests { io: io, }; let p = Process::new(args); - assert!(p.is_some()); + assert!(p.is_ok()); let mut p = p.unwrap(); assert!(p.wait().success()); }) @@ -206,7 +200,7 @@ mod tests { cwd: None, io: io, }; - match io::result(|| Process::new(args)) { + match Process::new(args) { Ok(..) => fail!(), Err(..) => {} } @@ -224,7 +218,7 @@ mod tests { io: io, }; let p = Process::new(args); - assert!(p.is_some()); + assert!(p.is_ok()); let mut p = p.unwrap(); assert!(p.wait().matches_exit_status(1)); }) @@ -240,7 +234,7 @@ mod tests { io: io, }; let p = Process::new(args); - assert!(p.is_some()); + assert!(p.is_ok()); let mut p = p.unwrap(); match p.wait() { process::ExitSignal(1) => {}, @@ -249,20 +243,12 @@ mod tests { }) pub fn read_all(input: &mut Reader) -> ~str { - let mut ret = ~""; - let mut buf = [0, ..1024]; - loop { - match input.read(buf) { - None => { break } - Some(n) => { ret.push_str(str::from_utf8(buf.slice_to(n)).unwrap()); } - } - } - return ret; + input.read_to_str().unwrap() } pub fn run_output(args: ProcessConfig) -> ~str { let p = Process::new(args); - assert!(p.is_some()); + assert!(p.is_ok()); let mut p = p.unwrap(); assert!(p.io[0].is_none()); assert!(p.io[1].is_some()); @@ -312,8 +298,8 @@ mod tests { cwd: None, io: io, }; - let mut p = Process::new(args).expect("didn't create a proces?!"); - p.io[0].get_mut_ref().write("foobar".as_bytes()); + let mut p = Process::new(args).unwrap(); + p.io[0].get_mut_ref().write("foobar".as_bytes()).unwrap(); p.io[0] = None; // close stdin; let out = read_all(p.io[1].get_mut_ref() as &mut Reader); assert!(p.wait().success()); diff --git a/src/libstd/io/result.rs b/src/libstd/io/result.rs new file mode 100644 index 00000000000..8e03cffd0fb --- /dev/null +++ b/src/libstd/io/result.rs @@ -0,0 +1,128 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementations of I/O traits for the IoResult type +//! +//! I/O constructors return option types to allow errors to be handled. +//! These implementations allow e.g. `IoResult<File>` to be used +//! as a `Reader` without unwrapping the result first. + +use clone::Clone; +use result::{Ok, Err}; +use super::{Reader, Writer, Listener, Acceptor, Seek, SeekStyle, IoResult}; + +impl<W: Writer> Writer for IoResult<W> { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { + match *self { + Ok(ref mut writer) => writer.write(buf), + Err(ref e) => Err((*e).clone()) + } + } + + fn flush(&mut self) -> IoResult<()> { + match *self { + Ok(ref mut writer) => writer.flush(), + Err(ref e) => Err(e.clone()), + } + } +} + +impl<R: Reader> Reader for IoResult<R> { + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { + match *self { + Ok(ref mut reader) => reader.read(buf), + Err(ref e) => Err(e.clone()), + } + } +} + +impl<S: Seek> Seek for IoResult<S> { + fn tell(&self) -> IoResult<u64> { + match *self { + Ok(ref seeker) => seeker.tell(), + Err(ref e) => Err(e.clone()), + } + } + fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { + match *self { + Ok(ref mut seeker) => seeker.seek(pos, style), + Err(ref e) => Err(e.clone()) + } + } +} + +impl<T, A: Acceptor<T>, L: Listener<T, A>> Listener<T, A> for IoResult<L> { + fn listen(self) -> IoResult<A> { + match self { + Ok(listener) => listener.listen(), + Err(e) => Err(e), + } + } +} + +impl<T, A: Acceptor<T>> Acceptor<T> for IoResult<A> { + fn accept(&mut self) -> IoResult<T> { + match *self { + Ok(ref mut acceptor) => acceptor.accept(), + Err(ref e) => Err(e.clone()), + } + } +} + +#[cfg(test)] +mod test { + use prelude::*; + use super::super::mem::*; + use io; + + #[test] + fn test_option_writer() { + let mut writer: io::IoResult<MemWriter> = Ok(MemWriter::new()); + writer.write([0, 1, 2]).unwrap(); + writer.flush().unwrap(); + assert_eq!(writer.unwrap().unwrap(), ~[0, 1, 2]); + } + + #[test] + fn test_option_writer_error() { + let mut writer: io::IoResult<MemWriter> = + Err(io::standard_error(io::EndOfFile)); + + match writer.write([0, 0, 0]) { + Ok(..) => fail!(), + Err(e) => assert_eq!(e.kind, io::EndOfFile), + } + match writer.flush() { + Ok(..) => fail!(), + Err(e) => assert_eq!(e.kind, io::EndOfFile), + } + } + + #[test] + fn test_option_reader() { + let mut reader: io::IoResult<MemReader> = + Ok(MemReader::new(~[0, 1, 2, 3])); + let mut buf = [0, 0]; + reader.read(buf).unwrap(); + assert_eq!(buf, [0, 1]); + } + + #[test] + fn test_option_reader_error() { + let mut reader: io::IoResult<MemReader> = + Err(io::standard_error(io::EndOfFile)); + let mut buf = []; + + match reader.read(buf) { + Ok(..) => fail!(), + Err(e) => assert_eq!(e.kind, io::EndOfFile), + } + } +} diff --git a/src/libstd/io/signal.rs b/src/libstd/io/signal.rs index 5575e289b59..75804c40c58 100644 --- a/src/libstd/io/signal.rs +++ b/src/libstd/io/signal.rs @@ -20,10 +20,11 @@ definitions for a number of signals. */ use clone::Clone; +use result::{Ok, Err}; use comm::{Port, SharedChan}; use container::{Map, MutableMap}; use hashmap; -use option::{Some, None}; +use io; use rt::rtio::{IoFactory, LocalIo, RtioSignal}; #[repr(int)] @@ -112,23 +113,22 @@ impl Listener { /// a signal, and a later call to `recv` will return the signal that was /// received while no task was waiting on it. /// - /// # Failure + /// # Error /// /// If this function fails to register a signal handler, then an error will - /// be raised on the `io_error` condition and the function will return - /// false. - pub fn register(&mut self, signum: Signum) -> bool { + /// be returned. + pub fn register(&mut self, signum: Signum) -> io::IoResult<()> { if self.handles.contains_key(&signum) { - return true; // self is already listening to signum, so succeed + return Ok(()); // self is already listening to signum, so succeed } match LocalIo::maybe_raise(|io| { io.signal(signum, self.chan.clone()) }) { - Some(handle) => { + Ok(handle) => { self.handles.insert(signum, handle); - true + Ok(()) } - None => false + Err(e) => Err(e) } } @@ -159,7 +159,7 @@ mod test { #[test] #[cfg(unix, not(target_os="android"))] // FIXME(#10378) fn test_io_signal_smoketest() { let mut signal = Listener::new(); - signal.register(Interrupt); + signal.register(Interrupt).unwrap(); sigint(); timer::sleep(10); match signal.port.recv() { @@ -172,8 +172,8 @@ mod test { fn test_io_signal_two_signal_one_signum() { let mut s1 = Listener::new(); let mut s2 = Listener::new(); - s1.register(Interrupt); - s2.register(Interrupt); + s1.register(Interrupt).unwrap(); + s2.register(Interrupt).unwrap(); sigint(); timer::sleep(10); match s1.port.recv() { @@ -190,8 +190,8 @@ mod test { fn test_io_signal_unregister() { let mut s1 = Listener::new(); let mut s2 = Listener::new(); - s1.register(Interrupt); - s2.register(Interrupt); + s1.register(Interrupt).unwrap(); + s2.register(Interrupt).unwrap(); s2.unregister(Interrupt); sigint(); timer::sleep(10); @@ -203,15 +203,14 @@ mod test { fn test_io_signal_invalid_signum() { use io; use super::User1; + use result::{Ok, Err}; let mut s = Listener::new(); let mut called = false; - io::io_error::cond.trap(|_| { - called = true; - }).inside(|| { - if s.register(User1) { + match s.register(User1) { + Ok(..) => { fail!("Unexpected successful registry of signum {:?}", User1); } - }); - assert!(called); + Err(..) => {} + } } } diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index d9fa2a4fc33..937ad0783e9 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -18,6 +18,7 @@ about the stream or terminal that it is attached to. # Example ```rust +# #[allow(unused_must_use)]; use std::io; let mut out = io::stdout(); @@ -28,7 +29,7 @@ out.write(bytes!("Hello, world!")); use container::Container; use fmt; -use io::{Reader, Writer, io_error, IoError, OtherIoError, +use io::{Reader, Writer, IoResult, IoError, OtherIoError, standard_error, EndOfFile, LineBufferedWriter}; use libc; use option::{Option, Some, None}; @@ -114,7 +115,8 @@ fn reset_helper(w: ~Writer, match f(t.get(), w) { Some(mut w) => { drop(t); - w.flush(); + // FIXME: is failing right here? + w.flush().unwrap(); Some(w) } None => None @@ -155,9 +157,9 @@ pub fn set_stderr(stderr: ~Writer) -> Option<~Writer> { // // io1 aliases io2 // }) // }) -fn with_task_stdout(f: |&mut Writer|) { +fn with_task_stdout(f: |&mut Writer| -> IoResult<()> ) { let task: Option<~Task> = Local::try_take(); - match task { + let result = match task { Some(mut task) => { // Printing may run arbitrary code, so ensure that the task is in // TLS to allow all std services. Note that this means a print while @@ -169,7 +171,7 @@ fn with_task_stdout(f: |&mut Writer|) { if my_stdout.is_none() { my_stdout = Some(~LineBufferedWriter::new(stdout()) as ~Writer); } - f(*my_stdout.get_mut_ref()); + let ret = f(*my_stdout.get_mut_ref()); // Note that we need to be careful when putting the stdout handle // back into the task. If the handle was set to `Some` while @@ -184,22 +186,29 @@ fn with_task_stdout(f: |&mut Writer|) { let prev = util::replace(&mut t.get().stdout, my_stdout); drop(t); drop(prev); + ret } None => { struct Stdout; impl Writer for Stdout { - fn write(&mut self, data: &[u8]) { + fn write(&mut self, data: &[u8]) -> IoResult<()> { unsafe { libc::write(libc::STDOUT_FILENO, data.as_ptr() as *libc::c_void, data.len() as libc::size_t); } + Ok(()) // just ignore the results } } let mut io = Stdout; - f(&mut io as &mut Writer); + f(&mut io as &mut Writer) } + }; + + match result { + Ok(()) => {} + Err(e) => fail!("failed printing to stdout: {}", e), } } @@ -226,8 +235,7 @@ pub fn print(s: &str) { /// `\n` character is printed to the console after the string. pub fn println(s: &str) { with_task_stdout(|io| { - io.write(s.as_bytes()); - io.write(['\n' as u8]); + io.write(s.as_bytes()).and_then(|()| io.write(['\n' as u8])) }) } @@ -249,7 +257,7 @@ pub struct StdReader { } impl Reader for StdReader { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { let ret = match self.inner { TTY(ref mut tty) => tty.read(buf), File(ref mut file) => file.read(buf).map(|i| i as uint), @@ -260,15 +268,8 @@ impl Reader for StdReader { // return an actual EOF error, but apparently for stdin it's a // little different. Hence, here we convert a 0 length read to an // end-of-file indicator so the caller knows to stop reading. - Ok(0) => { - io_error::cond.raise(standard_error(EndOfFile)); - None - } - Ok(amt) => Some(amt), - Err(e) => { - io_error::cond.raise(e); - None - } + Ok(0) => { Err(standard_error(EndOfFile)) } + ret @ Ok(..) | ret @ Err(..) => ret, } } } @@ -283,30 +284,21 @@ impl StdWriter { /// when the writer is attached to something like a terminal, this is used /// to fetch the dimensions of the terminal. /// - /// If successful, returns Some((width, height)). + /// If successful, returns `Ok((width, height))`. /// - /// # Failure + /// # Error /// - /// This function will raise on the `io_error` condition if an error - /// happens. - pub fn winsize(&mut self) -> Option<(int, int)> { + /// This function will return an error if the output stream is not actually + /// connected to a TTY instance, or if querying the TTY instance fails. + pub fn winsize(&mut self) -> IoResult<(int, int)> { match self.inner { - TTY(ref mut tty) => { - match tty.get_winsize() { - Ok(p) => Some(p), - Err(e) => { - io_error::cond.raise(e); - None - } - } - } + TTY(ref mut tty) => tty.get_winsize(), File(..) => { - io_error::cond.raise(IoError { + Err(IoError { kind: OtherIoError, desc: "stream is not a tty", detail: None, - }); - None + }) } } } @@ -314,24 +306,19 @@ impl StdWriter { /// Controls whether this output stream is a "raw stream" or simply a normal /// stream. /// - /// # Failure + /// # Error /// - /// This function will raise on the `io_error` condition if an error - /// happens. - pub fn set_raw(&mut self, raw: bool) { + /// This function will return an error if the output stream is not actually + /// connected to a TTY instance, or if querying the TTY instance fails. + pub fn set_raw(&mut self, raw: bool) -> IoResult<()> { match self.inner { - TTY(ref mut tty) => { - match tty.set_raw(raw) { - Ok(()) => {}, - Err(e) => io_error::cond.raise(e), - } - } + TTY(ref mut tty) => tty.set_raw(raw), File(..) => { - io_error::cond.raise(IoError { + Err(IoError { kind: OtherIoError, desc: "stream is not a tty", detail: None, - }); + }) } } } @@ -346,14 +333,10 @@ impl StdWriter { } impl Writer for StdWriter { - fn write(&mut self, buf: &[u8]) { - let ret = match self.inner { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { + match self.inner { TTY(ref mut tty) => tty.write(buf), File(ref mut file) => file.write(buf), - }; - match ret { - Ok(()) => {} - Err(e) => io_error::cond.raise(e) } } } @@ -376,7 +359,7 @@ mod tests { set_stdout(~w as ~Writer); println!("hello!"); }); - assert_eq!(r.read_to_str(), ~"hello!\n"); + assert_eq!(r.read_to_str().unwrap(), ~"hello!\n"); }) iotest!(fn capture_stderr() { @@ -388,7 +371,7 @@ mod tests { set_stderr(~w as ~Writer); fail!("my special message"); }); - let s = r.read_to_str(); + let s = r.read_to_str().unwrap(); assert!(s.contains("my special message")); }) } diff --git a/src/libstd/io/timer.rs b/src/libstd/io/timer.rs index 24eaf6adf3f..692aaa7afd0 100644 --- a/src/libstd/io/timer.rs +++ b/src/libstd/io/timer.rs @@ -39,8 +39,8 @@ loop { */ use comm::Port; -use option::Option; use rt::rtio::{IoFactory, LocalIo, RtioTimer}; +use io::IoResult; pub struct Timer { priv obj: ~RtioTimer @@ -48,7 +48,8 @@ pub struct Timer { /// Sleep the current task for `msecs` milliseconds. pub fn sleep(msecs: u64) { - let mut timer = Timer::new().expect("timer::sleep: could not create a Timer"); + let timer = Timer::new(); + let mut timer = timer.ok().expect("timer::sleep: could not create a Timer"); timer.sleep(msecs) } @@ -57,7 +58,7 @@ impl Timer { /// Creates a new timer which can be used to put the current task to sleep /// for a number of milliseconds, or to possibly create channels which will /// get notified after an amount of time has passed. - pub fn new() -> Option<Timer> { + pub fn new() -> IoResult<Timer> { LocalIo::maybe_raise(|io| io.timer_init().map(|t| Timer { obj: t })) } diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs index a1794d24fc9..c4d92b36ecf 100644 --- a/src/libstd/io/util.rs +++ b/src/libstd/io/util.rs @@ -7,8 +7,10 @@ // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. + use prelude::*; use cmp; +use io; use vec::bytes::MutableByteVector; /// Wraps a `Reader`, limiting the number of bytes that can be read from it. @@ -25,9 +27,9 @@ impl<'a, R: Reader> LimitReader<'a, R> { } impl<'a, R: Reader> Reader for LimitReader<'a, R> { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> { if self.limit == 0 { - return None; + return Err(io::standard_error(io::EndOfFile)); } let len = cmp::min(self.limit, buf.len()); @@ -43,7 +45,7 @@ pub struct NullWriter; impl Writer for NullWriter { #[inline] - fn write(&mut self, _buf: &[u8]) { } + fn write(&mut self, _buf: &[u8]) -> io::IoResult<()> { Ok(()) } } /// A `Reader` which returns an infinite stream of 0 bytes, like /dev/zero. @@ -51,9 +53,9 @@ pub struct ZeroReader; impl Reader for ZeroReader { #[inline] - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> { buf.set_memory(0); - Some(buf.len()) + Ok(buf.len()) } } @@ -62,8 +64,8 @@ pub struct NullReader; impl Reader for NullReader { #[inline] - fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { - None + fn read(&mut self, _buf: &mut [u8]) -> io::IoResult<uint> { + Err(io::standard_error(io::EndOfFile)) } } @@ -81,17 +83,21 @@ impl MultiWriter { impl Writer for MultiWriter { #[inline] - fn write(&mut self, buf: &[u8]) { + fn write(&mut self, buf: &[u8]) -> io::IoResult<()> { + let mut ret = Ok(()); for writer in self.writers.mut_iter() { - writer.write(buf); + ret = ret.and(writer.write(buf)); } + return ret; } #[inline] - fn flush(&mut self) { + fn flush(&mut self) -> io::IoResult<()> { + let mut ret = Ok(()); for writer in self.writers.mut_iter() { - writer.flush(); + ret = ret.and(writer.flush()); } + return ret; } } @@ -111,20 +117,25 @@ impl<R: Reader, I: Iterator<R>> ChainedReader<I, R> { } impl<R: Reader, I: Iterator<R>> Reader for ChainedReader<I, R> { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> { loop { - match self.cur_reader { + let err = match self.cur_reader { Some(ref mut r) => { match r.read(buf) { - Some(len) => return Some(len), - None => {} + Ok(len) => return Ok(len), + Err(ref e) if e.kind == io::EndOfFile => None, + Err(e) => Some(e), } } None => break + }; + self.cur_reader = self.readers.next(); + match err { + Some(e) => return Err(e), + None => {} } - self.cur_reader = self.readers.next() } - None + Err(io::standard_error(io::EndOfFile)) } } @@ -150,27 +161,29 @@ impl<R: Reader, W: Writer> TeeReader<R, W> { } impl<R: Reader, W: Writer> Reader for TeeReader<R, W> { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { - self.reader.read(buf).map(|len| { - self.writer.write(buf.slice_to(len)); - len + fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> { + self.reader.read(buf).and_then(|len| { + self.writer.write(buf.slice_to(len)).map(|()| len) }) } } /// Copies all data from a `Reader` to a `Writer`. -pub fn copy<R: Reader, W: Writer>(r: &mut R, w: &mut W) { +pub fn copy<R: Reader, W: Writer>(r: &mut R, w: &mut W) -> io::IoResult<()> { let mut buf = [0, ..super::DEFAULT_BUF_SIZE]; loop { - match r.read(buf) { - Some(len) => w.write(buf.slice_to(len)), - None => break - } + let len = match r.read(buf) { + Ok(len) => len, + Err(ref e) if e.kind == io::EndOfFile => return Ok(()), + Err(e) => return Err(e), + }; + if_ok!(w.write(buf.slice_to(len))); } } #[cfg(test)] mod test { + use io; use io::{MemReader, MemWriter}; use super::*; use prelude::*; @@ -180,7 +193,7 @@ mod test { let mut r = MemReader::new(~[0, 1, 2]); { let mut r = LimitReader::new(&mut r, 4); - assert_eq!(~[0, 1, 2], r.read_to_end()); + assert_eq!(~[0, 1, 2], r.read_to_end().unwrap()); } } @@ -189,24 +202,24 @@ mod test { let mut r = MemReader::new(~[0, 1, 2]); { let mut r = LimitReader::new(&mut r, 2); - assert_eq!(~[0, 1], r.read_to_end()); + assert_eq!(~[0, 1], r.read_to_end().unwrap()); } - assert_eq!(~[2], r.read_to_end()); + assert_eq!(~[2], r.read_to_end().unwrap()); } #[test] fn test_null_writer() { let mut s = NullWriter; let buf = ~[0, 0, 0]; - s.write(buf); - s.flush(); + s.write(buf).unwrap(); + s.flush().unwrap(); } #[test] fn test_zero_reader() { let mut s = ZeroReader; let mut buf = ~[1, 2, 3]; - assert_eq!(s.read(buf), Some(3)); + assert_eq!(s.read(buf), Ok(3)); assert_eq!(~[0, 0, 0], buf); } @@ -214,7 +227,7 @@ mod test { fn test_null_reader() { let mut r = NullReader; let mut buf = ~[0]; - assert_eq!(r.read(buf), None); + assert!(r.read(buf).is_err()); } #[test] @@ -224,21 +237,23 @@ mod test { struct TestWriter; impl Writer for TestWriter { - fn write(&mut self, _buf: &[u8]) { + fn write(&mut self, _buf: &[u8]) -> io::IoResult<()> { unsafe { writes += 1 } + Ok(()) } - fn flush(&mut self) { + fn flush(&mut self) -> io::IoResult<()> { unsafe { flushes += 1 } + Ok(()) } } let mut multi = MultiWriter::new(~[~TestWriter as ~Writer, ~TestWriter as ~Writer]); - multi.write([1, 2, 3]); + multi.write([1, 2, 3]).unwrap(); assert_eq!(2, unsafe { writes }); assert_eq!(0, unsafe { flushes }); - multi.flush(); + multi.flush().unwrap(); assert_eq!(2, unsafe { writes }); assert_eq!(2, unsafe { flushes }); } @@ -248,14 +263,14 @@ mod test { let rs = ~[MemReader::new(~[0, 1]), MemReader::new(~[]), MemReader::new(~[2, 3])]; let mut r = ChainedReader::new(rs.move_iter()); - assert_eq!(~[0, 1, 2, 3], r.read_to_end()); + assert_eq!(~[0, 1, 2, 3], r.read_to_end().unwrap()); } #[test] fn test_tee_reader() { let mut r = TeeReader::new(MemReader::new(~[0, 1, 2]), MemWriter::new()); - assert_eq!(~[0, 1, 2], r.read_to_end()); + assert_eq!(~[0, 1, 2], r.read_to_end().unwrap()); let (_, w) = r.unwrap(); assert_eq!(~[0, 1, 2], w.unwrap()); } @@ -264,7 +279,7 @@ mod test { fn test_copy() { let mut r = MemReader::new(~[0, 1, 2, 3, 4]); let mut w = MemWriter::new(); - copy(&mut r, &mut w); + copy(&mut r, &mut w).unwrap(); assert_eq!(~[0, 1, 2, 3, 4], w.unwrap()); } } diff --git a/src/libstd/logging.rs b/src/libstd/logging.rs index 636d3ffd90a..c5e66ffc7be 100644 --- a/src/libstd/logging.rs +++ b/src/libstd/logging.rs @@ -102,6 +102,7 @@ use io::Writer; use ops::Drop; use option::{Some, None, Option}; use prelude::drop; +use result::{Ok, Err}; use rt::local::Local; use rt::task::Task; use util; @@ -131,13 +132,19 @@ struct DefaultLogger { impl Logger for DefaultLogger { // by default, just ignore the level fn log(&mut self, _level: u32, args: &fmt::Arguments) { - fmt::writeln(&mut self.handle, args); + match fmt::writeln(&mut self.handle, args) { + Err(e) => fail!("failed to log: {}", e), + Ok(()) => {} + } } } impl Drop for DefaultLogger { fn drop(&mut self) { - self.handle.flush(); + match self.handle.flush() { + Err(e) => fail!("failed to flush a logger: {}", e), + Ok(()) => {} + } } } diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 4032b63790b..b31ae92d742 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -197,3 +197,8 @@ macro_rules! local_data_key ( pub static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key; ) ) + +#[macro_export] +macro_rules! if_ok ( + ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) }) +) diff --git a/src/libstd/option.rs b/src/libstd/option.rs index 83cedd92a3f..19478e3dbb3 100644 --- a/src/libstd/option.rs +++ b/src/libstd/option.rs @@ -382,7 +382,7 @@ impl<T: Default> Option<T> { impl<T: fmt::Show> fmt::Show for Option<T> { #[inline] - fn fmt(s: &Option<T>, f: &mut fmt::Formatter) { + fn fmt(s: &Option<T>, f: &mut fmt::Formatter) -> fmt::Result { match *s { Some(ref t) => write!(f.buf, "Some({})", *t), None => write!(f.buf, "None") diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 0ea1c7510a1..541db01f148 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -372,9 +372,9 @@ pub fn self_exe_name() -> Option<Path> { fn load_self() -> Option<~[u8]> { use std::io; - match io::result(|| io::fs::readlink(&Path::new("/proc/self/exe"))) { - Ok(Some(path)) => Some(path.as_vec().to_owned()), - Ok(None) | Err(..) => None + match io::fs::readlink(&Path::new("/proc/self/exe")) { + Ok(path) => Some(path.as_vec().to_owned()), + Err(..) => None } } @@ -929,7 +929,7 @@ pub enum MapError { } impl fmt::Show for MapError { - fn fmt(val: &MapError, out: &mut fmt::Formatter) { + fn fmt(val: &MapError, out: &mut fmt::Formatter) -> fmt::Result { let str = match *val { ErrFdNotAvail => "fd not available for reading or writing", ErrInvalidFd => "Invalid fd", @@ -944,23 +944,19 @@ impl fmt::Show for MapError { ErrAlreadyExists => "File mapping for specified file already exists", ErrZeroLength => "Zero-length mapping not allowed", ErrUnknown(code) => { - write!(out.buf, "Unknown error = {}", code); - return + return write!(out.buf, "Unknown error = {}", code) }, ErrVirtualAlloc(code) => { - write!(out.buf, "VirtualAlloc failure = {}", code); - return + return write!(out.buf, "VirtualAlloc failure = {}", code) }, ErrCreateFileMappingW(code) => { - format!("CreateFileMappingW failure = {}", code); - return + return write!(out.buf, "CreateFileMappingW failure = {}", code) }, ErrMapViewOfFile(code) => { - write!(out.buf, "MapViewOfFile failure = {}", code); - return + return write!(out.buf, "MapViewOfFile failure = {}", code) } }; - write!(out.buf, "{}", str); + write!(out.buf, "{}", str) } } @@ -1496,7 +1492,6 @@ mod tests { use result::{Ok, Err}; use os::*; use libc::*; - use io; use io::fs; #[cfg(unix)] @@ -1540,9 +1535,9 @@ mod tests { assert!(*chunk.data == 0xbe); close(fd); } + drop(chunk); - let _guard = io::ignore_io_error(); - fs::unlink(&path); + fs::unlink(&path).unwrap(); } // More recursive_mkdir tests are in extra::tempfile diff --git a/src/libstd/path/mod.rs b/src/libstd/path/mod.rs index 86f96a1075b..4aa4a3feab1 100644 --- a/src/libstd/path/mod.rs +++ b/src/libstd/path/mod.rs @@ -533,7 +533,7 @@ pub struct Display<'a, P> { } impl<'a, P: GenericPath> fmt::Show for Display<'a, P> { - fn fmt(d: &Display<P>, f: &mut fmt::Formatter) { + fn fmt(d: &Display<P>, f: &mut fmt::Formatter) -> fmt::Result { d.with_str(|s| f.pad(s)) } } diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index c359d79d275..e9068c6b0c8 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -62,7 +62,7 @@ impl OSRng { pub fn new() -> OSRng { use path::Path; let reader = File::open(&Path::new("/dev/urandom")); - let reader = reader.expect("Error opening /dev/urandom"); + let reader = reader.ok().expect("Error opening /dev/urandom"); let reader_rng = ReaderRng::new(reader); OSRng { inner: reader_rng } diff --git a/src/libstd/rand/reader.rs b/src/libstd/rand/reader.rs index e19fbd9aaf8..621d70970f0 100644 --- a/src/libstd/rand/reader.rs +++ b/src/libstd/rand/reader.rs @@ -11,7 +11,7 @@ //! A wrapper around any Reader to treat it as an RNG. use container::Container; -use option::{Some, None}; +use result::{Ok, Err}; use io::Reader; use rand::Rng; @@ -49,26 +49,26 @@ impl<R: Reader> Rng for ReaderRng<R> { // platform just involves blitting the bytes into the memory // of the u32, similarly for BE on BE; avoiding byteswapping. if cfg!(target_endian="little") { - self.reader.read_le_u32() + self.reader.read_le_u32().unwrap() } else { - self.reader.read_be_u32() + self.reader.read_be_u32().unwrap() } } fn next_u64(&mut self) -> u64 { // see above for explanation. if cfg!(target_endian="little") { - self.reader.read_le_u64() + self.reader.read_le_u64().unwrap() } else { - self.reader.read_be_u64() + self.reader.read_be_u64().unwrap() } } fn fill_bytes(&mut self, v: &mut [u8]) { if v.len() == 0 { return } match self.reader.read(v) { - Some(n) if n == v.len() => return, - Some(n) => fail!("ReaderRng.fill_bytes could not fill buffer: \ - read {} out of {} bytes.", n, v.len()), - None => fail!("ReaderRng.fill_bytes reached eof.") + Ok(n) if n == v.len() => return, + Ok(n) => fail!("ReaderRng.fill_bytes could not fill buffer: \ + read {} out of {} bytes.", n, v.len()), + Err(e) => fail!("ReaderRng.fill_bytes error: {}", e) } } } diff --git a/src/libstd/reflect.rs b/src/libstd/reflect.rs index d6b4d3f5656..44ee5de7ac3 100644 --- a/src/libstd/reflect.rs +++ b/src/libstd/reflect.rs @@ -66,6 +66,8 @@ impl<V:TyVisitor + MovePtr> MovePtrAdaptor<V> { pub fn bump_past<T>(&mut self) { self.bump(mem::size_of::<T>()); } + + pub fn unwrap(self) -> V { self.inner } } /// Abstract type-directed pointer-movement using the MovePtr trait diff --git a/src/libstd/repr.rs b/src/libstd/repr.rs index 41ddf027787..f71649602b2 100644 --- a/src/libstd/repr.rs +++ b/src/libstd/repr.rs @@ -21,48 +21,57 @@ use char; use container::Container; use io; use iter::Iterator; -use option::{Some, None}; +use option::{Some, None, Option}; use ptr; use reflect; use reflect::{MovePtr, align}; +use result::{Ok, Err}; use str::StrSlice; use to_str::ToStr; use vec::OwnedVector; use unstable::intrinsics::{Disr, Opaque, TyDesc, TyVisitor, get_tydesc, visit_tydesc}; use unstable::raw; +macro_rules! if_ok( ($me:expr, $e:expr) => ( + match $e { + Ok(()) => {}, + Err(e) => { $me.last_err = Some(e); return false; } + } +) ) + /// Representations trait Repr { - fn write_repr(&self, writer: &mut io::Writer); + fn write_repr(&self, writer: &mut io::Writer) -> io::IoResult<()>; } impl Repr for () { - fn write_repr(&self, writer: &mut io::Writer) { - writer.write("()".as_bytes()); + fn write_repr(&self, writer: &mut io::Writer) -> io::IoResult<()> { + writer.write("()".as_bytes()) } } impl Repr for bool { - fn write_repr(&self, writer: &mut io::Writer) { + fn write_repr(&self, writer: &mut io::Writer) -> io::IoResult<()> { let s = if *self { "true" } else { "false" }; writer.write(s.as_bytes()) } } impl Repr for int { - fn write_repr(&self, writer: &mut io::Writer) { + fn write_repr(&self, writer: &mut io::Writer) -> io::IoResult<()> { ::int::to_str_bytes(*self, 10u, |bits| { - writer.write(bits); + writer.write(bits) }) } } macro_rules! int_repr(($ty:ident, $suffix:expr) => (impl Repr for $ty { - fn write_repr(&self, writer: &mut io::Writer) { + fn write_repr(&self, writer: &mut io::Writer) -> io::IoResult<()> { ::$ty::to_str_bytes(*self, 10u, |bits| { - writer.write(bits); - writer.write(bytes!($suffix)); + writer.write(bits).and_then(|()| { + writer.write(bytes!($suffix)) + }) }) } })) @@ -78,10 +87,11 @@ int_repr!(u32, "u32") int_repr!(u64, "u64") macro_rules! num_repr(($ty:ident, $suffix:expr) => (impl Repr for $ty { - fn write_repr(&self, writer: &mut io::Writer) { + fn write_repr(&self, writer: &mut io::Writer) -> io::IoResult<()> { let s = self.to_str(); - writer.write(s.as_bytes()); - writer.write(bytes!($suffix)); + writer.write(s.as_bytes()).and_then(|()| { + writer.write(bytes!($suffix)) + }) } })) @@ -100,7 +110,8 @@ pub struct ReprVisitor<'a> { priv ptr: *u8, priv ptr_stk: ~[*u8], priv var_stk: ~[VariantState], - priv writer: &'a mut io::Writer + priv writer: &'a mut io::Writer, + priv last_err: Option<io::IoError>, } pub fn ReprVisitor<'a>(ptr: *u8, @@ -110,6 +121,7 @@ pub fn ReprVisitor<'a>(ptr: *u8, ptr_stk: ~[], var_stk: ~[], writer: writer, + last_err: None, } } @@ -130,11 +142,10 @@ impl<'a> ReprVisitor<'a> { // Various helpers for the TyVisitor impl #[inline] - pub fn get<T>(&mut self, f: |&mut ReprVisitor, &T|) -> bool { + pub fn get<T>(&mut self, f: |&mut ReprVisitor, &T| -> bool) -> bool { unsafe { - f(self, transmute::<*u8,&T>(self.ptr)); + f(self, transmute::<*u8,&T>(self.ptr)) } - true } #[inline] @@ -152,43 +163,53 @@ impl<'a> ReprVisitor<'a> { ptr_stk: ~[], var_stk: ~[], writer: ::cast::transmute_copy(&self.writer), + last_err: None, }; let mut v = reflect::MovePtrAdaptor(u); // Obviously this should not be a thing, but blame #8401 for now visit_tydesc(inner, &mut v as &mut TyVisitor); - true + match v.unwrap().last_err { + Some(e) => { + self.last_err = Some(e); + false + } + None => true, + } } } #[inline] pub fn write<T:Repr>(&mut self) -> bool { self.get(|this, v:&T| { - v.write_repr(unsafe { ::cast::transmute_copy(&this.writer) }); + if_ok!(this, v.write_repr(this.writer)); + true }) } - pub fn write_escaped_slice(&mut self, slice: &str) { - self.writer.write(['"' as u8]); + pub fn write_escaped_slice(&mut self, slice: &str) -> bool { + if_ok!(self, self.writer.write(['"' as u8])); for ch in slice.chars() { - self.write_escaped_char(ch, true); + if !self.write_escaped_char(ch, true) { return false } } - self.writer.write(['"' as u8]); + if_ok!(self, self.writer.write(['"' as u8])); + true } - pub fn write_mut_qualifier(&mut self, mtbl: uint) { + pub fn write_mut_qualifier(&mut self, mtbl: uint) -> bool { if mtbl == 0 { - self.writer.write("mut ".as_bytes()); + if_ok!(self, self.writer.write("mut ".as_bytes())); } else if mtbl == 1 { // skip, this is ast::m_imm } else { fail!("invalid mutability value"); } + true } pub fn write_vec_range(&mut self, ptr: *(), len: uint, inner: *TyDesc) -> bool { let mut p = ptr as *u8; let (sz, al) = unsafe { ((*inner).size, (*inner).align) }; - self.writer.write(['[' as u8]); + if_ok!(self, self.writer.write(['[' as u8])); let mut first = true; let mut left = len; // unit structs have 0 size, and don't loop forever. @@ -197,13 +218,13 @@ impl<'a> ReprVisitor<'a> { if first { first = false; } else { - self.writer.write(", ".as_bytes()); + if_ok!(self, self.writer.write(", ".as_bytes())); } self.visit_ptr_inner(p as *u8, inner); p = align(unsafe { ptr::offset(p, sz as int) as uint }, al) as *u8; left -= dec; } - self.writer.write([']' as u8]); + if_ok!(self, self.writer.write([']' as u8])); true } @@ -211,8 +232,8 @@ impl<'a> ReprVisitor<'a> { self.write_vec_range(ptr::to_unsafe_ptr(&v.data), v.fill, inner) } - fn write_escaped_char(&mut self, ch: char, is_str: bool) { - match ch { + fn write_escaped_char(&mut self, ch: char, is_str: bool) -> bool { + if_ok!(self, match ch { '\t' => self.writer.write("\\t".as_bytes()), '\r' => self.writer.write("\\r".as_bytes()), '\n' => self.writer.write("\\n".as_bytes()), @@ -234,16 +255,18 @@ impl<'a> ReprVisitor<'a> { '\x20'..'\x7e' => self.writer.write([ch as u8]), _ => { char::escape_unicode(ch, |c| { - self.writer.write([c as u8]); - }) + let _ = self.writer.write([c as u8]); + }); + Ok(()) } - } + }); + return true; } } impl<'a> TyVisitor for ReprVisitor<'a> { fn visit_bot(&mut self) -> bool { - self.writer.write("!".as_bytes()); + if_ok!(self, self.writer.write("!".as_bytes())); true } fn visit_nil(&mut self) -> bool { self.write::<()>() } @@ -265,9 +288,10 @@ impl<'a> TyVisitor for ReprVisitor<'a> { fn visit_char(&mut self) -> bool { self.get::<char>(|this, &ch| { - this.writer.write(['\'' as u8]); - this.write_escaped_char(ch, false); - this.writer.write(['\'' as u8]); + if_ok!(this, this.writer.write(['\'' as u8])); + if !this.write_escaped_char(ch, false) { return false } + if_ok!(this, this.writer.write(['\'' as u8])); + true }) } @@ -277,8 +301,8 @@ impl<'a> TyVisitor for ReprVisitor<'a> { fn visit_estr_uniq(&mut self) -> bool { self.get::<~str>(|this, s| { - this.writer.write(['~' as u8]); - this.write_escaped_slice(*s); + if_ok!(this, this.writer.write(['~' as u8])); + this.write_escaped_slice(*s) }) } @@ -291,34 +315,35 @@ impl<'a> TyVisitor for ReprVisitor<'a> { _align: uint) -> bool { fail!(); } fn visit_box(&mut self, mtbl: uint, inner: *TyDesc) -> bool { - self.writer.write(['@' as u8]); + if_ok!(self, self.writer.write(['@' as u8])); self.write_mut_qualifier(mtbl); self.get::<&raw::Box<()>>(|this, b| { let p = ptr::to_unsafe_ptr(&b.data) as *u8; - this.visit_ptr_inner(p, inner); + this.visit_ptr_inner(p, inner) }) } fn visit_uniq(&mut self, _mtbl: uint, inner: *TyDesc) -> bool { - self.writer.write(['~' as u8]); + if_ok!(self, self.writer.write(['~' as u8])); self.get::<*u8>(|this, b| { - this.visit_ptr_inner(*b, inner); + this.visit_ptr_inner(*b, inner) }) } fn visit_ptr(&mut self, mtbl: uint, _inner: *TyDesc) -> bool { self.get::<*u8>(|this, p| { - write!(this.writer, "({} as *", *p); + if_ok!(this, write!(this.writer, "({} as *", *p)); this.write_mut_qualifier(mtbl); - this.writer.write("())".as_bytes()); + if_ok!(this, this.writer.write("())".as_bytes())); + true }) } fn visit_rptr(&mut self, mtbl: uint, inner: *TyDesc) -> bool { - self.writer.write(['&' as u8]); + if_ok!(self, self.writer.write(['&' as u8])); self.write_mut_qualifier(mtbl); self.get::<*u8>(|this, p| { - this.visit_ptr_inner(*p, inner); + this.visit_ptr_inner(*p, inner) }) } @@ -327,33 +352,33 @@ impl<'a> TyVisitor for ReprVisitor<'a> { fn visit_unboxed_vec(&mut self, mtbl: uint, inner: *TyDesc) -> bool { self.get::<raw::Vec<()>>(|this, b| { - this.write_unboxed_vec_repr(mtbl, b, inner); + this.write_unboxed_vec_repr(mtbl, b, inner) }) } fn visit_evec_box(&mut self, mtbl: uint, inner: *TyDesc) -> bool { self.get::<&raw::Box<raw::Vec<()>>>(|this, b| { - this.writer.write(['@' as u8]); + if_ok!(this, this.writer.write(['@' as u8])); this.write_mut_qualifier(mtbl); - this.write_unboxed_vec_repr(mtbl, &b.data, inner); + this.write_unboxed_vec_repr(mtbl, &b.data, inner) }) } fn visit_evec_uniq(&mut self, mtbl: uint, inner: *TyDesc) -> bool { self.get::<&raw::Vec<()>>(|this, b| { - this.writer.write(['~' as u8]); - this.write_unboxed_vec_repr(mtbl, *b, inner); + if_ok!(this, this.writer.write(['~' as u8])); + this.write_unboxed_vec_repr(mtbl, *b, inner) }) } fn visit_evec_slice(&mut self, mtbl: uint, inner: *TyDesc) -> bool { self.get::<raw::Slice<()>>(|this, s| { - this.writer.write(['&' as u8]); + if_ok!(this, this.writer.write(['&' as u8])); this.write_mut_qualifier(mtbl); let size = unsafe { if (*inner).size == 0 { 1 } else { (*inner).size } }; - this.write_vec_range(s.data, s.len * size, inner); + this.write_vec_range(s.data, s.len * size, inner) }) } @@ -361,42 +386,42 @@ impl<'a> TyVisitor for ReprVisitor<'a> { _: uint, inner: *TyDesc) -> bool { let assumed_size = if sz == 0 { n } else { sz }; self.get::<()>(|this, b| { - this.write_vec_range(ptr::to_unsafe_ptr(b), assumed_size, inner); + this.write_vec_range(ptr::to_unsafe_ptr(b), assumed_size, inner) }) } fn visit_enter_rec(&mut self, _n_fields: uint, _sz: uint, _align: uint) -> bool { - self.writer.write(['{' as u8]); + if_ok!(self, self.writer.write(['{' as u8])); true } fn visit_rec_field(&mut self, i: uint, name: &str, mtbl: uint, inner: *TyDesc) -> bool { if i != 0 { - self.writer.write(", ".as_bytes()); + if_ok!(self, self.writer.write(", ".as_bytes())); } self.write_mut_qualifier(mtbl); - self.writer.write(name.as_bytes()); - self.writer.write(": ".as_bytes()); + if_ok!(self, self.writer.write(name.as_bytes())); + if_ok!(self, self.writer.write(": ".as_bytes())); self.visit_inner(inner); true } fn visit_leave_rec(&mut self, _n_fields: uint, _sz: uint, _align: uint) -> bool { - self.writer.write(['}' as u8]); + if_ok!(self, self.writer.write(['}' as u8])); true } fn visit_enter_class(&mut self, name: &str, named_fields: bool, n_fields: uint, _sz: uint, _align: uint) -> bool { - self.writer.write(name.as_bytes()); + if_ok!(self, self.writer.write(name.as_bytes())); if n_fields != 0 { if named_fields { - self.writer.write(['{' as u8]); + if_ok!(self, self.writer.write(['{' as u8])); } else { - self.writer.write(['(' as u8]); + if_ok!(self, self.writer.write(['(' as u8])); } } true @@ -405,11 +430,11 @@ impl<'a> TyVisitor for ReprVisitor<'a> { fn visit_class_field(&mut self, i: uint, name: &str, named: bool, _mtbl: uint, inner: *TyDesc) -> bool { if i != 0 { - self.writer.write(", ".as_bytes()); + if_ok!(self, self.writer.write(", ".as_bytes())); } if named { - self.writer.write(name.as_bytes()); - self.writer.write(": ".as_bytes()); + if_ok!(self, self.writer.write(name.as_bytes())); + if_ok!(self, self.writer.write(": ".as_bytes())); } self.visit_inner(inner); true @@ -419,9 +444,9 @@ impl<'a> TyVisitor for ReprVisitor<'a> { _sz: uint, _align: uint) -> bool { if n_fields != 0 { if named_fields { - self.writer.write(['}' as u8]); + if_ok!(self, self.writer.write(['}' as u8])); } else { - self.writer.write([')' as u8]); + if_ok!(self, self.writer.write([')' as u8])); } } true @@ -429,13 +454,13 @@ impl<'a> TyVisitor for ReprVisitor<'a> { fn visit_enter_tup(&mut self, _n_fields: uint, _sz: uint, _align: uint) -> bool { - self.writer.write(['(' as u8]); + if_ok!(self, self.writer.write(['(' as u8])); true } fn visit_tup_field(&mut self, i: uint, inner: *TyDesc) -> bool { if i != 0 { - self.writer.write(", ".as_bytes()); + if_ok!(self, self.writer.write(", ".as_bytes())); } self.visit_inner(inner); true @@ -444,9 +469,9 @@ impl<'a> TyVisitor for ReprVisitor<'a> { fn visit_leave_tup(&mut self, _n_fields: uint, _sz: uint, _align: uint) -> bool { if _n_fields == 1 { - self.writer.write([',' as u8]); + if_ok!(self, self.writer.write([',' as u8])); } - self.writer.write([')' as u8]); + if_ok!(self, self.writer.write([')' as u8])); true } @@ -482,9 +507,9 @@ impl<'a> TyVisitor for ReprVisitor<'a> { } if write { - self.writer.write(name.as_bytes()); + if_ok!(self, self.writer.write(name.as_bytes())); if n_fields > 0 { - self.writer.write(['(' as u8]); + if_ok!(self, self.writer.write(['(' as u8])); } } true @@ -498,7 +523,7 @@ impl<'a> TyVisitor for ReprVisitor<'a> { match self.var_stk[self.var_stk.len() - 1] { Matched => { if i != 0 { - self.writer.write(", ".as_bytes()); + if_ok!(self, self.writer.write(", ".as_bytes())); } if ! self.visit_inner(inner) { return false; @@ -516,7 +541,7 @@ impl<'a> TyVisitor for ReprVisitor<'a> { match self.var_stk[self.var_stk.len() - 1] { Matched => { if n_fields > 0 { - self.writer.write([')' as u8]); + if_ok!(self, self.writer.write([')' as u8])); } } _ => () @@ -538,28 +563,29 @@ impl<'a> TyVisitor for ReprVisitor<'a> { fn visit_enter_fn(&mut self, _purity: uint, _proto: uint, _n_inputs: uint, _retstyle: uint) -> bool { - self.writer.write("fn(".as_bytes()); + if_ok!(self, self.writer.write("fn(".as_bytes())); true } fn visit_fn_input(&mut self, i: uint, _mode: uint, inner: *TyDesc) -> bool { if i != 0 { - self.writer.write(", ".as_bytes()); + if_ok!(self, self.writer.write(", ".as_bytes())); } let name = unsafe { (*inner).name }; - self.writer.write(name.as_bytes()); + if_ok!(self, self.writer.write(name.as_bytes())); true } - fn visit_fn_output(&mut self, _retstyle: uint, variadic: bool, inner: *TyDesc) -> bool { + fn visit_fn_output(&mut self, _retstyle: uint, variadic: bool, + inner: *TyDesc) -> bool { if variadic { - self.writer.write(", ...".as_bytes()); + if_ok!(self, self.writer.write(", ...".as_bytes())); } - self.writer.write(")".as_bytes()); + if_ok!(self, self.writer.write(")".as_bytes())); let name = unsafe { (*inner).name }; if name != "()" { - self.writer.write(" -> ".as_bytes()); - self.writer.write(name.as_bytes()); + if_ok!(self, self.writer.write(" -> ".as_bytes())); + if_ok!(self, self.writer.write(name.as_bytes())); } true } @@ -569,7 +595,7 @@ impl<'a> TyVisitor for ReprVisitor<'a> { fn visit_trait(&mut self, name: &str) -> bool { - self.writer.write(name.as_bytes()); + if_ok!(self, self.writer.write(name.as_bytes())); true } @@ -582,13 +608,17 @@ impl<'a> TyVisitor for ReprVisitor<'a> { fn visit_closure_ptr(&mut self, _ck: uint) -> bool { true } } -pub fn write_repr<T>(writer: &mut io::Writer, object: &T) { +pub fn write_repr<T>(writer: &mut io::Writer, object: &T) -> io::IoResult<()> { unsafe { let ptr = ptr::to_unsafe_ptr(object) as *u8; let tydesc = get_tydesc::<T>(); let u = ReprVisitor(ptr, writer); let mut v = reflect::MovePtrAdaptor(u); visit_tydesc(tydesc, &mut v as &mut TyVisitor); + match v.unwrap().last_err { + Some(e) => Err(e), + None => Ok(()), + } } } @@ -597,7 +627,7 @@ pub fn repr_to_str<T>(t: &T) -> ~str { use io; let mut result = io::MemWriter::new(); - write_repr(&mut result as &mut io::Writer, t); + write_repr(&mut result as &mut io::Writer, t).unwrap(); str::from_utf8_owned(result.unwrap()).unwrap() } @@ -615,7 +645,7 @@ fn test_repr() { fn exact_test<T>(t: &T, e:&str) { let mut m = io::MemWriter::new(); - write_repr(&mut m as &mut io::Writer, t); + write_repr(&mut m as &mut io::Writer, t).unwrap(); let s = str::from_utf8_owned(m.unwrap()).unwrap(); assert_eq!(s.as_slice(), e); } diff --git a/src/libstd/result.rs b/src/libstd/result.rs index cc8fdeaccfe..846bba7533f 100644 --- a/src/libstd/result.rs +++ b/src/libstd/result.rs @@ -208,7 +208,7 @@ impl<T, E> Result<T, E> { impl<T: fmt::Show, E: fmt::Show> fmt::Show for Result<T, E> { #[inline] - fn fmt(s: &Result<T, E>, f: &mut fmt::Formatter) { + fn fmt(s: &Result<T, E>, f: &mut fmt::Formatter) -> fmt::Result { match *s { Ok(ref t) => write!(f.buf, "Ok({})", *t), Err(ref e) => write!(f.buf, "Err({})", *e) diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 455a84b4ce3..35b1e21df06 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -16,13 +16,13 @@ use libc; use ops::Drop; use option::{Option, Some, None}; use path::Path; -use result::{Result, Ok, Err}; +use result::{Result, Err}; use rt::task::Task; use rt::local::Local; use ai = io::net::addrinfo; use io; -use io::IoError; +use io::{IoError, IoResult}; use io::net::ip::{IpAddr, SocketAddr}; use io::process::{ProcessConfig, ProcessExit}; use io::signal::Signum; @@ -116,23 +116,12 @@ impl<'a> LocalIo<'a> { return ret; } - pub fn maybe_raise<T>(f: |io: &mut IoFactory| -> Result<T, IoError>) - -> Option<T> + pub fn maybe_raise<T>(f: |io: &mut IoFactory| -> IoResult<T>) + -> IoResult<T> { match LocalIo::borrow() { - None => { - io::io_error::cond.raise(io::standard_error(io::IoUnavailable)); - None - } - Some(mut io) => { - match f(io.get()) { - Ok(t) => Some(t), - Err(ioerr) => { - io::io_error::cond.raise(ioerr); - None - } - } - } + None => Err(io::standard_error(io::IoUnavailable)), + Some(mut io) => f(io.get()), } } diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index 7c43e64f17b..515eb93001a 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -119,6 +119,7 @@ impl Task { // Run the task main function, then do some cleanup. f.finally(|| { + #[allow(unused_must_use)] fn close_outputs() { let mut task = Local::borrow(None::<Task>); let logger = task.get().logger.take(); @@ -126,8 +127,8 @@ impl Task { let stdout = task.get().stdout.take(); drop(task); drop(logger); // loggers are responsible for flushing - match stdout { Some(mut w) => w.flush(), None => {} } - match stderr { Some(mut w) => w.flush(), None => {} } + match stdout { Some(mut w) => { w.flush(); }, None => {} } + match stderr { Some(mut w) => { w.flush(); }, None => {} } } // First, flush/destroy the user stdout/logger because these diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index 4d2dcb6c51c..9aece13b84c 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -464,9 +464,10 @@ fn begin_unwind_inner(msg: ~Any, file: &'static str, line: uint) -> ! { match task.stderr.take() { Some(mut stderr) => { Local::put(task); - format_args!(|args| ::fmt::writeln(stderr, args), - "task '{}' failed at '{}', {}:{}", - n, msg_s, file, line); + // FIXME: what to do when the task printing fails? + let _err = format_args!(|args| ::fmt::writeln(stderr, args), + "task '{}' failed at '{}', {}:{}", + n, msg_s, file, line); task = Local::take(); match util::replace(&mut task.stderr, Some(stderr)) { diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs index 9c17c624987..69e240f30bc 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/rt/util.rs @@ -11,10 +11,12 @@ use container::Container; use fmt; use from_str::FromStr; +use io::IoResult; use iter::Iterator; use libc; use option::{Some, None, Option}; use os; +use result::Ok; use str::StrSlice; use unstable::running_on_valgrind; use vec::ImmutableVector; @@ -73,16 +75,17 @@ pub fn dumb_println(args: &fmt::Arguments) { struct Stderr; impl io::Writer for Stderr { - fn write(&mut self, data: &[u8]) { + fn write(&mut self, data: &[u8]) -> IoResult<()> { unsafe { libc::write(libc::STDERR_FILENO, data.as_ptr() as *libc::c_void, data.len() as libc::size_t); } + Ok(()) // yes, we're lying } } let mut w = Stderr; - fmt::writeln(&mut w as &mut io::Writer, args); + let _ = fmt::writeln(&mut w as &mut io::Writer, args); } pub fn abort(msg: &str) -> ! { diff --git a/src/libstd/run.rs b/src/libstd/run.rs index ef2374f6095..04e42b3eedf 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -11,6 +11,7 @@ //! Utilities for spawning and managing processes #[allow(missing_doc)]; +#[deny(unused_must_use)]; use comm::SharedChan; use io::Reader; @@ -119,7 +120,8 @@ impl Process { * * options - Options to configure the environment of the process, * the working directory and the standard IO streams. */ - pub fn new(prog: &str, args: &[~str], options: ProcessOptions) -> Option<Process> { + pub fn new(prog: &str, args: &[~str], + options: ProcessOptions) -> io::IoResult<Process> { let ProcessOptions { env, dir, in_fd, out_fd, err_fd } = options; let env = env.as_ref().map(|a| a.as_slice()); let cwd = dir.as_ref().map(|a| a.as_str().unwrap()); @@ -138,10 +140,7 @@ impl Process { cwd: cwd, io: rtio, }; - match process::Process::new(rtconfig) { - Some(inner) => Some(Process { inner: inner }), - None => None - } + process::Process::new(rtconfig).map(|p| Process { inner: p }) } /// Returns the unique id of the process @@ -224,19 +223,17 @@ impl Process { let ch_clone = ch.clone(); spawn(proc() { - let _guard = io::ignore_io_error(); let mut error = error; match error { Some(ref mut e) => ch.send((2, e.read_to_end())), - None => ch.send((2, ~[])) + None => ch.send((2, Ok(~[]))) } }); spawn(proc() { - let _guard = io::ignore_io_error(); let mut output = output; match output { Some(ref mut e) => ch_clone.send((1, e.read_to_end())), - None => ch_clone.send((1, ~[])) + None => ch_clone.send((1, Ok(~[]))) } }); @@ -251,8 +248,8 @@ impl Process { }; return ProcessOutput {status: status, - output: outs, - error: errs}; + output: outs.ok().unwrap_or(~[]), + error: errs.ok().unwrap_or(~[]) }; } /** @@ -262,9 +259,10 @@ impl Process { * On Posix OSs SIGTERM will be sent to the process. On Win32 * TerminateProcess(..) will be called. */ - pub fn destroy(&mut self) { - self.inner.signal(io::process::PleaseExitSignal); + pub fn destroy(&mut self) -> io::IoResult<()> { + let ret = self.inner.signal(io::process::PleaseExitSignal); self.finish(); + return ret; } /** @@ -274,9 +272,12 @@ impl Process { * On Posix OSs SIGKILL will be sent to the process. On Win32 * TerminateProcess(..) will be called. */ - pub fn force_destroy(&mut self) { - self.inner.signal(io::process::MustDieSignal); + pub fn force_destroy(&mut self) -> io::IoResult<()> { + // This should never fail because we own the process + let ret = self.inner.signal(io::process::MustDieSignal); self.finish(); + return ret; + } } @@ -293,18 +294,14 @@ impl Process { * * The process's exit code, or None if the child process could not be started */ -pub fn process_status(prog: &str, args: &[~str]) -> Option<ProcessExit> { - let mut opt_prog = Process::new(prog, args, ProcessOptions { +pub fn process_status(prog: &str, args: &[~str]) -> io::IoResult<ProcessExit> { + Process::new(prog, args, ProcessOptions { env: None, dir: None, in_fd: Some(unsafe { libc::dup(libc::STDIN_FILENO) }), out_fd: Some(unsafe { libc::dup(libc::STDOUT_FILENO) }), err_fd: Some(unsafe { libc::dup(libc::STDERR_FILENO) }) - }); - match opt_prog { - Some(ref mut prog) => Some(prog.finish()), - None => None - } + }).map(|mut p| p.finish()) } /** @@ -320,12 +317,10 @@ pub fn process_status(prog: &str, args: &[~str]) -> Option<ProcessExit> { * The process's stdout/stderr output and exit code, or None if the child process could not be * started. */ -pub fn process_output(prog: &str, args: &[~str]) -> Option<ProcessOutput> { - let mut opt_prog = Process::new(prog, args, ProcessOptions::new()); - match opt_prog { - Some(ref mut prog) => Some(prog.finish_with_output()), - None => None - } +pub fn process_output(prog: &str, args: &[~str]) -> io::IoResult<ProcessOutput> { + Process::new(prog, args, ProcessOptions::new()).map(|mut p| { + p.finish_with_output() + }) } #[cfg(test)] @@ -337,33 +332,25 @@ mod tests { use task::spawn; use unstable::running_on_valgrind; use io::pipe::PipeStream; - use io::{io_error, FileNotFound}; + use io::{FileNotFound}; use libc::c_int; #[test] #[cfg(not(target_os="android"))] // FIXME(#10380) fn test_process_status() { - let mut status = run::process_status("false", []).expect("failed to exec `false`"); + let mut status = run::process_status("false", []).unwrap(); assert!(status.matches_exit_status(1)); - status = run::process_status("true", []).expect("failed to exec `true`"); + status = run::process_status("true", []).unwrap(); assert!(status.success()); } #[test] fn test_process_output_fail_to_start() { - // If the executable does not exist, then the io_error condition should be raised with - // IoErrorKind FileNotFound. - - let mut trapped_io_error = false; - let opt_outp = io_error::cond.trap(|e| { - trapped_io_error = true; - assert_eq!(e.kind, FileNotFound); - }).inside(|| -> Option<run::ProcessOutput> { - run::process_output("/no-binary-by-this-name-should-exist", []) - }); - assert!(trapped_io_error); - assert!(opt_outp.is_none()); + match run::process_output("/no-binary-by-this-name-should-exist", []) { + Err(e) => assert_eq!(e.kind, FileNotFound), + Ok(..) => fail!() + } } #[test] @@ -371,7 +358,7 @@ mod tests { fn test_process_output_output() { let run::ProcessOutput {status, output, error} - = run::process_output("echo", [~"hello"]).expect("failed to exec `echo`"); + = run::process_output("echo", [~"hello"]).unwrap(); let output_str = str::from_utf8_owned(output).unwrap(); assert!(status.success()); @@ -387,7 +374,7 @@ mod tests { fn test_process_output_error() { let run::ProcessOutput {status, output, error} - = run::process_output("mkdir", [~"."]).expect("failed to exec `mkdir`"); + = run::process_output("mkdir", [~"."]).unwrap(); assert!(status.matches_exit_status(1)); assert_eq!(output, ~[]); @@ -408,7 +395,7 @@ mod tests { in_fd: Some(pipe_in.input), out_fd: Some(pipe_out.out), err_fd: Some(pipe_err.out) - }).expect("failed to exec `cat`"); + }).unwrap(); os::close(pipe_in.input as int); os::close(pipe_out.out as int); @@ -426,27 +413,18 @@ mod tests { fn writeclose(fd: c_int, s: &str) { let mut writer = PipeStream::open(fd); - writer.write(s.as_bytes()); + writer.write(s.as_bytes()).unwrap(); } fn readclose(fd: c_int) -> ~str { - let mut res = ~[]; - let mut reader = PipeStream::open(fd); - let mut buf = [0, ..1024]; - loop { - match reader.read(buf) { - Some(n) => { res.push_all(buf.slice_to(n)); } - None => break - } - } - str::from_utf8_owned(res).unwrap() + PipeStream::open(fd).read_to_str().unwrap() } #[test] #[cfg(not(target_os="android"))] // FIXME(#10380) fn test_finish_once() { let mut prog = run::Process::new("false", [], run::ProcessOptions::new()) - .expect("failed to exec `false`"); + .unwrap(); assert!(prog.finish().matches_exit_status(1)); } @@ -454,7 +432,7 @@ mod tests { #[cfg(not(target_os="android"))] // FIXME(#10380) fn test_finish_twice() { let mut prog = run::Process::new("false", [], run::ProcessOptions::new()) - .expect("failed to exec `false`"); + .unwrap(); assert!(prog.finish().matches_exit_status(1)); assert!(prog.finish().matches_exit_status(1)); } @@ -464,7 +442,7 @@ mod tests { fn test_finish_with_output_once() { let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions::new()) - .expect("failed to exec `echo`"); + .unwrap(); let run::ProcessOutput {status, output, error} = prog.finish_with_output(); let output_str = str::from_utf8_owned(output).unwrap(); @@ -482,7 +460,7 @@ mod tests { fn test_finish_with_output_twice() { let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions::new()) - .expect("failed to exec `echo`"); + .unwrap(); let run::ProcessOutput {status, output, error} = prog.finish_with_output(); @@ -511,14 +489,14 @@ mod tests { run::Process::new("pwd", [], run::ProcessOptions { dir: dir, .. run::ProcessOptions::new() - }).expect("failed to exec `pwd`") + }).unwrap() } #[cfg(unix,target_os="android")] fn run_pwd(dir: Option<&Path>) -> run::Process { run::Process::new("/system/bin/sh", [~"-c",~"pwd"], run::ProcessOptions { dir: dir, .. run::ProcessOptions::new() - }).expect("failed to exec `/system/bin/sh`") + }).unwrap() } #[cfg(windows)] @@ -526,7 +504,7 @@ mod tests { run::Process::new("cmd", [~"/c", ~"cd"], run::ProcessOptions { dir: dir, .. run::ProcessOptions::new() - }).expect("failed to run `cmd`") + }).unwrap() } #[test] @@ -537,8 +515,8 @@ mod tests { let parent_dir = os::getcwd(); let child_dir = Path::new(output.trim()); - let parent_stat = parent_dir.stat(); - let child_stat = child_dir.stat(); + let parent_stat = parent_dir.stat().unwrap(); + let child_stat = child_dir.stat().unwrap(); assert_eq!(parent_stat.unstable.device, child_stat.unstable.device); assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode); @@ -554,8 +532,8 @@ mod tests { let output = str::from_utf8_owned(prog.finish_with_output().output).unwrap(); let child_dir = Path::new(output.trim()); - let parent_stat = parent_dir.stat(); - let child_stat = child_dir.stat(); + let parent_stat = parent_dir.stat().unwrap(); + let child_stat = child_dir.stat().unwrap(); assert_eq!(parent_stat.unstable.device, child_stat.unstable.device); assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode); @@ -566,14 +544,14 @@ mod tests { run::Process::new("env", [], run::ProcessOptions { env: env, .. run::ProcessOptions::new() - }).expect("failed to exec `env`") + }).unwrap() } #[cfg(unix,target_os="android")] fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process { run::Process::new("/system/bin/sh", [~"-c",~"set"], run::ProcessOptions { env: env, .. run::ProcessOptions::new() - }).expect("failed to exec `/system/bin/sh`") + }).unwrap() } #[cfg(windows)] @@ -581,7 +559,7 @@ mod tests { run::Process::new("cmd", [~"/c", ~"set"], run::ProcessOptions { env: env, .. run::ProcessOptions::new() - }).expect("failed to run `cmd`") + }).unwrap() } #[test] diff --git a/src/libstd/task.rs b/src/libstd/task.rs index c8b69083086..5fa0c6431ab 100644 --- a/src/libstd/task.rs +++ b/src/libstd/task.rs @@ -541,7 +541,7 @@ fn test_avoid_copying_the_body_task_spawn() { #[test] fn test_avoid_copying_the_body_try() { avoid_copying_the_body(|f| { - try(proc() { + let _ = try(proc() { f() }); }) diff --git a/src/libstd/to_bytes.rs b/src/libstd/to_bytes.rs index 4c545de73b4..c8bd1907c5c 100644 --- a/src/libstd/to_bytes.rs +++ b/src/libstd/to_bytes.rs @@ -349,7 +349,7 @@ impl<A:IterBytes> ToBytes for A { let mut m = ::io::MemWriter::new(); self.iter_bytes(lsb0, |bytes| { - m.write(bytes); + m.write(bytes).unwrap(); true }); m.unwrap() diff --git a/src/libstd/unstable/sync.rs b/src/libstd/unstable/sync.rs index 3b2c86c3712..c2fa168a478 100644 --- a/src/libstd/unstable/sync.rs +++ b/src/libstd/unstable/sync.rs @@ -200,7 +200,7 @@ mod tests { // accesses will also fail. let x = Exclusive::new(1); let x2 = x.clone(); - task::try(proc() { + let _ = task::try(proc() { x2.with(|one| assert_eq!(*one, 2)) }); x.with(|one| assert_eq!(*one, 1)); |
