about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-11-03 03:57:18 +0000
committerbors <bors@rust-lang.org>2014-11-03 03:57:18 +0000
commitff50f24feb512075f3fcf9fc2801e4c853ff9316 (patch)
tree9842337cf63e33f73bed8ba4ee681a6a3e9549f5 /src/libstd
parentdcc5c3b31b294a19c369e7b1926528610230686d (diff)
parent38e0745e3f5e6c772c973c1d0b73abb0b20faba0 (diff)
downloadrust-ff50f24feb512075f3fcf9fc2801e4c853ff9316.tar.gz
rust-ff50f24feb512075f3fcf9fc2801e4c853ff9316.zip
auto merge of #17753 : aturon/rust/error-interop, r=alexcrichton
This PR:

* Adds the error interoperation traits (`Error` and `FromError`) to a new module, `std::error`, as per [RFC 70](https://github.com/rust-lang/rfcs/blob/master/active/0070-error-chaining.md). Note that this module must live in `std` in order to refer to `String`.

    Note that, until multidispatch lands, the `FromError` trait cannot be
usefully implemented outside of the blanket impl given here.

* Incorporates `std::error::FromError` into the `try!` macro.

* Implements `Error` for most existing error enumerations.

Closes #17747
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/error.rs111
-rw-r--r--src/libstd/io/mod.rs18
-rw-r--r--src/libstd/lib.rs2
-rw-r--r--src/libstd/macros.rs9
-rw-r--r--src/libstd/os.rs14
-rw-r--r--src/libstd/prelude.rs4
6 files changed, 154 insertions, 4 deletions
diff --git a/src/libstd/error.rs b/src/libstd/error.rs
new file mode 100644
index 00000000000..6bb9f4b473b
--- /dev/null
+++ b/src/libstd/error.rs
@@ -0,0 +1,111 @@
+// Copyright 2014 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.
+
+//! Traits for working with Errors.
+//!
+//! # The `Error` trait
+//!
+//! `Error` is a trait representing the basic expectations for error values,
+//! i.e. values of type `E` in `Result<T, E>`. At a minimum, errors must provide
+//! a description, but they may optionally provide additional detail and cause
+//! chain information:
+//!
+//! ```
+//! trait Error: Send {
+//!     fn description(&self) -> &str;
+//!
+//!     fn detail(&self) -> Option<String> { None }
+//!     fn cause(&self) -> Option<&Error> { None }
+//! }
+//! ```
+//!
+//! The `cause` method is generally used when errors cross "abstraction
+//! boundaries", i.e.  when a one module must report an error that is "caused"
+//! by an error from a lower-level module. This setup makes it possible for the
+//! high-level module to provide its own errors that do not commit to any
+//! particular implementation, but also reveal some of its implementation for
+//! debugging via `cause` chains.
+//!
+//! The trait inherits from `Any` to allow *downcasting*: converting from a
+//! trait object to a specific concrete type when applicable.
+//!
+//! # The `FromError` trait
+//!
+//! `FromError` is a simple trait that expresses conversions between different
+//! error types. To provide maximum flexibility, it does not require either of
+//! the types to actually implement the `Error` trait, although this will be the
+//! common case.
+//!
+//! The main use of this trait is in the `try!` macro, which uses it to
+//! automatically convert a given error to the error specified in a function's
+//! return type.
+//!
+//! For example,
+//!
+//! ```
+//! use std::error::FromError;
+//! use std::io::{File, IoError};
+//! use std::os::{MemoryMap, MapError};
+//! use std::path::Path;
+//!
+//! enum MyError {
+//!     Io(IoError),
+//!     Map(MapError)
+//! }
+//!
+//! impl FromError<IoError> for MyError {
+//!     fn from_error(err: IoError) -> MyError {
+//!         Io(err)
+//!     }
+//! }
+//!
+//! impl FromError<MapError> for MyError {
+//!     fn from_error(err: MapError) -> MyError {
+//!         Map(err)
+//!     }
+//! }
+//!
+//! #[allow(unused_variables)]
+//! fn open_and_map() -> Result<(), MyError> {
+//!     let f = try!(File::open(&Path::new("foo.txt")));
+//!     let m = try!(MemoryMap::new(0, &[]));
+//!     // do something interesting here...
+//!     Ok(())
+//! }
+//! ```
+
+use option::{Option, None};
+use kinds::Send;
+use string::String;
+
+/// Base functionality for all errors in Rust.
+pub trait Error: Send {
+    /// A short description of the error; usually a static string.
+    fn description(&self) -> &str;
+
+    /// A detailed description of the error, usually including dynamic information.
+    fn detail(&self) -> Option<String> { None }
+
+    /// The lower-level cause of this error, if any.
+    fn cause(&self) -> Option<&Error> { None }
+}
+
+/// A trait for types that can be converted from a given error type `E`.
+pub trait FromError<E> {
+    /// Perform the conversion.
+    fn from_error(err: E) -> Self;
+}
+
+// Any type is convertable from itself
+impl<E> FromError<E> for E {
+    fn from_error(err: E) -> E {
+        err
+    }
+}
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index c6f237ff1da..3dcd8d792a4 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -222,7 +222,9 @@ responding to errors that may occur while attempting to read the numbers.
 #![deny(unused_must_use)]
 
 use char::Char;
+use clone::Clone;
 use default::Default;
+use error::{FromError, Error};
 use fmt;
 use int;
 use iter::Iterator;
@@ -433,6 +435,22 @@ impl fmt::Show for IoError {
     }
 }
 
+impl Error for IoError {
+    fn description(&self) -> &str {
+        self.desc
+    }
+
+    fn detail(&self) -> Option<String> {
+        self.detail.clone()
+    }
+}
+
+impl FromError<IoError> for Box<Error> {
+    fn from_error(err: IoError) -> Box<Error> {
+        box err
+    }
+}
+
 /// A list specifying general categories of I/O error.
 #[deriving(PartialEq, Eq, Clone, Show)]
 pub enum IoErrorKind {
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 67080f4551f..f10a1d5e5ed 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -218,6 +218,7 @@ pub mod time;
 
 /* Common traits */
 
+pub mod error;
 pub mod from_str;
 pub mod num;
 pub mod to_string;
@@ -257,6 +258,7 @@ mod std {
     pub use hash;
 
     pub use comm; // used for select!()
+    pub use error; // used for try!()
     pub use fmt; // used for any formatting strings
     pub use io; // used for println!()
     pub use local_data; // used for local_data_key!()
diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs
index 0712719dd04..55e364b1961 100644
--- a/src/libstd/macros.rs
+++ b/src/libstd/macros.rs
@@ -317,8 +317,13 @@ macro_rules! local_data_key(
 /// error if the value of the expression is `Err`. For more information, see
 /// `std::io`.
 #[macro_export]
-macro_rules! try(
-    ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
+macro_rules! try (
+    ($expr:expr) => ({
+        match $expr {
+            Ok(val) => val,
+            Err(err) => return Err(::std::error::FromError::from_error(err))
+        }
+    })
 )
 
 /// Create a `std::vec::Vec` containing the arguments.
diff --git a/src/libstd/os.rs b/src/libstd/os.rs
index 5b3c872d2b7..9846f7b653e 100644
--- a/src/libstd/os.rs
+++ b/src/libstd/os.rs
@@ -32,11 +32,13 @@
 #![allow(non_snake_case)]
 
 use clone::Clone;
+use error::{FromError, Error};
 use fmt;
 use io::{IoResult, IoError};
 use iter::Iterator;
 use libc::{c_void, c_int};
 use libc;
+use boxed::Box;
 use ops::Drop;
 use option::{Some, None, Option};
 use os;
@@ -48,6 +50,7 @@ use slice::{AsSlice, ImmutableSlice, MutableSlice, ImmutablePartialEqSlice};
 use slice::CloneableVector;
 use str::{Str, StrSlice, StrAllocating};
 use string::String;
+use to_string::ToString;
 use sync::atomic::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
 use vec::Vec;
 
@@ -1437,6 +1440,17 @@ impl fmt::Show for MapError {
     }
 }
 
+impl Error for MapError {
+    fn description(&self) -> &str { "memory map error" }
+    fn detail(&self) -> Option<String> { Some(self.to_string()) }
+}
+
+impl FromError<MapError> for Box<Error> {
+    fn from_error(err: MapError) -> Box<Error> {
+        box err
+    }
+}
+
 #[cfg(unix)]
 impl MemoryMap {
     /// Create a new mapping with the given `options`, at least `min_len` bytes
diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs
index b2ff29c0f7e..47befb2286b 100644
--- a/src/libstd/prelude.rs
+++ b/src/libstd/prelude.rs
@@ -48,8 +48,6 @@
 #[doc(no_inline)] pub use ops::{Index, IndexMut};
 #[doc(no_inline)] pub use ops::{Slice, SliceMut};
 #[doc(no_inline)] pub use ops::{Fn, FnMut, FnOnce};
-#[doc(no_inline)] pub use option::{Option, Some, None};
-#[doc(no_inline)] pub use result::{Result, Ok, Err};
 
 // Reexported functions
 #[doc(no_inline)] pub use from_str::from_str;
@@ -73,8 +71,10 @@
 #[doc(no_inline)] pub use num::{Signed, Unsigned, Primitive, Int, Float};
 #[doc(no_inline)] pub use num::{FloatMath, ToPrimitive, FromPrimitive};
 #[doc(no_inline)] pub use boxed::Box;
+#[doc(no_inline)] pub use option::{Option, Some, None};
 #[doc(no_inline)] pub use path::{GenericPath, Path, PosixPath, WindowsPath};
 #[doc(no_inline)] pub use ptr::{RawPtr, RawMutPtr};
+#[doc(no_inline)] pub use result::{Result, Ok, Err};
 #[doc(no_inline)] pub use io::{Buffer, Writer, Reader, Seek};
 #[doc(no_inline)] pub use str::{Str, StrVector, StrSlice};
 #[doc(no_inline)] pub use str::{IntoMaybeOwned, StrAllocating, UnicodeStrSlice};