about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-05-29 01:09:48 +0000
committerbors <bors@rust-lang.org>2015-05-29 01:09:48 +0000
commit99c2f779d2506c1ca678db5325a843414c4782d0 (patch)
treefb656cdf7ce26288090e5c2b8bd798dbcd7bc2ee
parent53941be9814f05496b3147da393c639a9d48957e (diff)
parentaebf331431eeac6e91eba5072e2ee7f171cd1244 (diff)
downloadrust-99c2f779d2506c1ca678db5325a843414c4782d0.tar.gz
rust-99c2f779d2506c1ca678db5325a843414c4782d0.zip
Auto merge of #25816 - sfackler:io-error-delegation, r=alexcrichton
The first commit simply forwards `io::Error`'s `cause` implementation to the inner error.

The second commit adds accessor methods for the inner error. Method names mirror those used elsewhere like `BufReader`.

r? @alexcrichton 
-rw-r--r--src/libstd/io/error.rs92
1 files changed, 87 insertions, 5 deletions
diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs
index 97c5a29d308..85b957640fd 100644
--- a/src/libstd/io/error.rs
+++ b/src/libstd/io/error.rs
@@ -129,9 +129,7 @@ impl Error {
     ///
     /// This function is used to generically create I/O errors which do not
     /// originate from the OS itself. The `error` argument is an arbitrary
-    /// payload which will be contained in this `Error`. Accessors as well as
-    /// downcasting will soon be added to this type as well to access the custom
-    /// information.
+    /// payload which will be contained in this `Error`.
     ///
     /// # Examples
     ///
@@ -174,8 +172,9 @@ impl Error {
 
     /// Returns the OS error that this error represents (if any).
     ///
-    /// If this `Error` was constructed via `last_os_error` then this function
-    /// will return `Some`, otherwise it will return `None`.
+    /// If this `Error` was constructed via `last_os_error` or
+    /// `from_raw_os_error`, then this function will return `Some`, otherwise
+    /// it will return `None`.
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn raw_os_error(&self) -> Option<i32> {
         match self.repr {
@@ -184,6 +183,46 @@ impl Error {
         }
     }
 
+    /// Returns a reference to the inner error wrapped by this error (if any).
+    ///
+    /// If this `Error` was constructed via `new` then this function will
+    /// return `Some`, otherwise it will return `None`.
+    #[unstable(feature = "io_error_inner",
+               reason = "recently added and requires UFCS to downcast")]
+    pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> {
+        match self.repr {
+            Repr::Os(..) => None,
+            Repr::Custom(ref c) => Some(&*c.error),
+        }
+    }
+
+    /// Returns a mutable reference to the inner error wrapped by this error
+    /// (if any).
+    ///
+    /// If this `Error` was constructed via `new` then this function will
+    /// return `Some`, otherwise it will return `None`.
+    #[unstable(feature = "io_error_inner",
+               reason = "recently added and requires UFCS to downcast")]
+    pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync+'static)> {
+        match self.repr {
+            Repr::Os(..) => None,
+            Repr::Custom(ref mut c) => Some(&mut *c.error),
+        }
+    }
+
+    /// Consumes the `Error`, returning its inner error (if any).
+    ///
+    /// If this `Error` was constructed via `new` then this function will
+    /// return `Some`, otherwise it will return `None`.
+    #[unstable(feature = "io_error_inner",
+               reason = "recently added and requires UFCS to downcast")]
+    pub fn into_inner(self) -> Option<Box<error::Error+Send+Sync>> {
+        match self.repr {
+            Repr::Os(..) => None,
+            Repr::Custom(c) => Some(c.error)
+        }
+    }
+
     /// Returns the corresponding `ErrorKind` for this error.
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn kind(&self) -> ErrorKind {
@@ -215,9 +254,52 @@ impl error::Error for Error {
             Repr::Custom(ref c) => c.error.description(),
         }
     }
+
+    fn cause(&self) -> Option<&error::Error> {
+        match self.repr {
+            Repr::Os(..) => None,
+            Repr::Custom(ref c) => c.error.cause(),
+        }
+    }
 }
 
 fn _assert_error_is_sync_send() {
     fn _is_sync_send<T: Sync+Send>() {}
     _is_sync_send::<Error>();
 }
+
+#[cfg(test)]
+mod test {
+    use prelude::v1::*;
+    use super::{Error, ErrorKind};
+    use error;
+    use error::Error as error_Error;
+    use fmt;
+
+    #[test]
+    fn test_downcasting() {
+        #[derive(Debug)]
+        struct TestError;
+
+        impl fmt::Display for TestError {
+            fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+                Ok(())
+            }
+        }
+
+        impl error::Error for TestError {
+            fn description(&self) -> &str {
+                "asdf"
+            }
+        }
+
+        // we have to call all of these UFCS style right now since method
+        // resolution won't implicitly drop the Send+Sync bounds
+        let mut err = Error::new(ErrorKind::Other, TestError);
+        assert!(error::Error::is::<TestError>(err.get_ref().unwrap()));
+        assert_eq!("asdf", err.get_ref().unwrap().description());
+        assert!(error::Error::is::<TestError>(err.get_mut().unwrap()));
+        let extracted = err.into_inner().unwrap();
+        error::Error::downcast::<TestError>(extracted).unwrap();
+    }
+}