From 99234bbe9e9f89dcfdf28b9ee53fbcece5f19abb Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Tue, 1 Nov 2016 19:19:33 -0600 Subject: [PATCH] Add a new non-heap allocated variant to io::Error's representation. Implement From for io::Error, intended for use with errors that should never be exposed to the user. --- src/libstd/io/error.rs | 69 +++++++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 21 deletions(-) diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index ddf0030858e..659c8aa5aea 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -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. @@ -62,6 +63,7 @@ pub struct Error { enum Repr { Os(i32), + Simple(ErrorKind), Custom(Box), } @@ -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 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. @@ -285,6 +324,7 @@ impl Error { match self.repr { Repr::Os(i) => Some(i), Repr::Custom(..) => None, + Repr::Simple(..) => None, } } @@ -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), } } @@ -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), } } @@ -420,6 +462,7 @@ impl Error { pub fn into_inner(self) -> Option> { match self.repr { Repr::Os(..) => None, + Repr::Simple(..) => None, Repr::Custom(c) => Some(c.error) } } @@ -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, } } } @@ -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(), } } } @@ -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()), } } } @@ -479,27 +525,7 @@ 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(), } } @@ -507,6 +533,7 @@ impl error::Error for Error { fn cause(&self) -> Option<&error::Error> { match self.repr { Repr::Os(..) => None, + Repr::Simple(..) => None, Repr::Custom(ref c) => c.error.cause(), } }