From 4458b5a9d5f11af5cfeb2201a4065131baeeec36 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 26 May 2015 20:39:14 -0700 Subject: [PATCH 1/4] Delegate io::Error::cause to inner error --- src/libstd/io/error.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index 97c5a29d308a1..70e6d7eb26579 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -215,6 +215,13 @@ impl error::Error for Error { Repr::Custom(ref c) => c.error.description(), } } + + fn cause(&self) -> Option<&Error> { + match self.repr { + Repr::Os(..) => None, + Repr::Custom(ref c) => c.error.cause(), + } + } } fn _assert_error_is_sync_send() { From b529a7837bcbaee4a5e9f61ee659c94af7e41f60 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 26 May 2015 21:06:56 -0700 Subject: [PATCH 2/4] Add accessors for io::Error's inner error. error::Error itself has downcasting methods, so there's no need to duplicate those here. --- src/libstd/io/error.rs | 48 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index 70e6d7eb26579..c3a773617e0e8 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 { match self.repr { @@ -184,6 +183,43 @@ 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")] + pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync)> { + 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")] + pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync)> { + 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")] + pub fn into_inner(self) -> Option> { + 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 { @@ -216,7 +252,7 @@ impl error::Error for Error { } } - fn cause(&self) -> Option<&Error> { + fn cause(&self) -> Option<&error::Error> { match self.repr { Repr::Os(..) => None, Repr::Custom(ref c) => c.error.cause(), From f65ba38cc4d69089575580807b262a029b53c0e2 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 27 May 2015 23:03:04 -0700 Subject: [PATCH 3/4] Add a test for downcasting Ergonomics are a bit crappy right now because method resolution isn't smart enough to drop bounds, unfortunately. --- src/libstd/io/error.rs | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index c3a773617e0e8..449e49c08e509 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -188,7 +188,7 @@ impl Error { /// 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")] - pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync)> { + pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> { match self.repr { Repr::Os(..) => None, Repr::Custom(ref c) => Some(&*c.error), @@ -201,7 +201,7 @@ impl Error { /// 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")] - pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync)> { + 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), @@ -264,3 +264,39 @@ fn _assert_error_is_sync_send() { fn _is_sync_send() {} _is_sync_send::(); } + +#[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::(err.get_ref().unwrap())); + assert_eq!("asdf", err.get_ref().unwrap().description()); + assert!(error::Error::is::(err.get_mut().unwrap())); + let extracted = err.into_inner().unwrap(); + error::Error::downcast::(extracted).unwrap(); + } +} From aebf331431eeac6e91eba5072e2ee7f171cd1244 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 28 May 2015 10:34:40 -0700 Subject: [PATCH 4/4] Mention UFCS sadness in instability messages --- src/libstd/io/error.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index 449e49c08e509..85b957640fdab 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -187,7 +187,8 @@ impl Error { /// /// 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")] + #[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, @@ -200,7 +201,8 @@ impl Error { /// /// 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")] + #[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, @@ -212,7 +214,8 @@ impl Error { /// /// 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")] + #[unstable(feature = "io_error_inner", + reason = "recently added and requires UFCS to downcast")] pub fn into_inner(self) -> Option> { match self.repr { Repr::Os(..) => None,