Skip to content

Add accessors for io::Error's inner Error #25816

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 29, 2015
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 87 additions & 5 deletions src/libstd/io/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
///
Expand Down Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down Expand Up @@ -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();
}
}