Skip to content

Commit

Permalink
Add a new non-heap allocated variant to io::Error's representation.
Browse files Browse the repository at this point in the history
Implement From<ErrorKind> for io::Error, intended for use with errors
that should never be exposed to the user.
  • Loading branch information
Mark-Simulacrum committed Nov 2, 2016
1 parent ea4b94d commit 99234bb
Showing 1 changed file with 48 additions and 21 deletions.
69 changes: 48 additions & 21 deletions src/libstd/io/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use error;
use fmt;
use result;
use sys;
use convert::From;

/// A specialized [`Result`](../result/enum.Result.html) type for I/O
/// operations.
Expand Down Expand Up @@ -62,6 +63,7 @@ pub struct Error {

enum Repr {
Os(i32),
Simple(ErrorKind),
Custom(Box<Custom>),
}

Expand Down Expand Up @@ -171,6 +173,43 @@ pub enum ErrorKind {
__Nonexhaustive,
}

impl ErrorKind {
fn as_str(&self) -> &'static str {
match *self {
ErrorKind::NotFound => "entity not found",
ErrorKind::PermissionDenied => "permission denied",
ErrorKind::ConnectionRefused => "connection refused",
ErrorKind::ConnectionReset => "connection reset",
ErrorKind::ConnectionAborted => "connection aborted",
ErrorKind::NotConnected => "not connected",
ErrorKind::AddrInUse => "address in use",
ErrorKind::AddrNotAvailable => "address not available",
ErrorKind::BrokenPipe => "broken pipe",
ErrorKind::AlreadyExists => "entity already exists",
ErrorKind::WouldBlock => "operation would block",
ErrorKind::InvalidInput => "invalid input parameter",
ErrorKind::InvalidData => "invalid data",
ErrorKind::TimedOut => "timed out",
ErrorKind::WriteZero => "write zero",
ErrorKind::Interrupted => "operation interrupted",
ErrorKind::Other => "other os error",
ErrorKind::UnexpectedEof => "unexpected end of file",
ErrorKind::__Nonexhaustive => unreachable!()
}
}
}

/// Intended for use for errors not exposed to the user, where allocating onto
/// the heap (for normal construction via Error::new) is too costly.
#[stable(feature = "io_error_from_errorkind", since = "1.14.0")]
impl From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Error {
Error {
repr: Repr::Simple(kind)
}
}
}

impl Error {
/// Creates a new I/O error from a known kind of error as well as an
/// arbitrary error payload.
Expand Down Expand Up @@ -285,6 +324,7 @@ impl Error {
match self.repr {
Repr::Os(i) => Some(i),
Repr::Custom(..) => None,
Repr::Simple(..) => None,
}
}

Expand Down Expand Up @@ -317,6 +357,7 @@ impl Error {
pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> {
match self.repr {
Repr::Os(..) => None,
Repr::Simple(..) => None,
Repr::Custom(ref c) => Some(&*c.error),
}
}
Expand Down Expand Up @@ -387,6 +428,7 @@ impl Error {
pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync+'static)> {
match self.repr {
Repr::Os(..) => None,
Repr::Simple(..) => None,
Repr::Custom(ref mut c) => Some(&mut *c.error),
}
}
Expand Down Expand Up @@ -420,6 +462,7 @@ impl Error {
pub fn into_inner(self) -> Option<Box<error::Error+Send+Sync>> {
match self.repr {
Repr::Os(..) => None,
Repr::Simple(..) => None,
Repr::Custom(c) => Some(c.error)
}
}
Expand Down Expand Up @@ -447,6 +490,7 @@ impl Error {
match self.repr {
Repr::Os(code) => sys::decode_error_kind(code),
Repr::Custom(ref c) => c.kind,
Repr::Simple(kind) => kind,
}
}
}
Expand All @@ -458,6 +502,7 @@ impl fmt::Debug for Repr {
fmt.debug_struct("Os").field("code", code)
.field("message", &sys::os::error_string(*code)).finish(),
Repr::Custom(ref c) => fmt.debug_tuple("Custom").field(c).finish(),
Repr::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
}
}
}
Expand All @@ -471,6 +516,7 @@ impl fmt::Display for Error {
write!(fmt, "{} (os error {})", detail, code)
}
Repr::Custom(ref c) => c.error.fmt(fmt),
Repr::Simple(kind) => write!(fmt, "{}", kind.as_str()),
}
}
}
Expand All @@ -479,34 +525,15 @@ impl fmt::Display for Error {
impl error::Error for Error {
fn description(&self) -> &str {
match self.repr {
Repr::Os(..) => match self.kind() {
ErrorKind::NotFound => "entity not found",
ErrorKind::PermissionDenied => "permission denied",
ErrorKind::ConnectionRefused => "connection refused",
ErrorKind::ConnectionReset => "connection reset",
ErrorKind::ConnectionAborted => "connection aborted",
ErrorKind::NotConnected => "not connected",
ErrorKind::AddrInUse => "address in use",
ErrorKind::AddrNotAvailable => "address not available",
ErrorKind::BrokenPipe => "broken pipe",
ErrorKind::AlreadyExists => "entity already exists",
ErrorKind::WouldBlock => "operation would block",
ErrorKind::InvalidInput => "invalid input parameter",
ErrorKind::InvalidData => "invalid data",
ErrorKind::TimedOut => "timed out",
ErrorKind::WriteZero => "write zero",
ErrorKind::Interrupted => "operation interrupted",
ErrorKind::Other => "other os error",
ErrorKind::UnexpectedEof => "unexpected end of file",
ErrorKind::__Nonexhaustive => unreachable!()
},
Repr::Os(..) | Repr::Simple(..) => self.kind().as_str(),
Repr::Custom(ref c) => c.error.description(),
}
}

fn cause(&self) -> Option<&error::Error> {
match self.repr {
Repr::Os(..) => None,
Repr::Simple(..) => None,
Repr::Custom(ref c) => c.error.cause(),
}
}
Expand Down

0 comments on commit 99234bb

Please sign in to comment.