aboutsummaryrefslogtreecommitdiff
path: root/src/system/io/error.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/system/io/error.rs')
-rw-r--r--src/system/io/error.rs341
1 files changed, 341 insertions, 0 deletions
diff --git a/src/system/io/error.rs b/src/system/io/error.rs
new file mode 100644
index 0000000..4b99e7a
--- /dev/null
+++ b/src/system/io/error.rs
@@ -0,0 +1,341 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+use std::error;
+use std::fmt;
+use std::result;
+
+/// A specialized [`Result`](../result/enum.Result.html) type for I/O
+/// operations.
+///
+/// This type is broadly used across `std::io` for any operation which may
+/// produce an error.
+///
+/// This typedef is generally used to avoid writing out `io::Error` directly and
+/// is otherwise a direct mapping to `Result`.
+///
+/// While usual Rust style is to import types directly, aliases of `Result`
+/// often are not, to make it easier to distinguish between them. `Result` is
+/// generally assumed to be `std::result::Result`, and so users of this alias
+/// will generally use `io::Result` instead of shadowing the prelude's import
+/// of `std::result::Result`.
+///
+/// # Examples
+///
+/// A convenience function that bubbles an `io::Result` to its caller:
+///
+/// ```
+/// use std::io;
+///
+/// fn get_string() -> io::Result<String> {
+/// let mut buffer = String::new();
+///
+/// try!(io::stdin().read_line(&mut buffer));
+///
+/// Ok(buffer)
+/// }
+/// ```
+pub type Result<T> = result::Result<T, Error>;
+
+/// The error type for I/O operations of the `Read`, `Write`, `Seek`, and
+/// associated traits.
+///
+/// Errors mostly originate from the underlying OS, but custom instances of
+/// `Error` can be created with crafted error messages and a particular value of
+/// `ErrorKind`.
+#[derive(Debug)]
+pub struct Error {
+ repr: Repr,
+}
+
+enum Repr {
+ Os(i32),
+ Custom(Box<Custom>),
+}
+
+#[derive(Debug)]
+struct Custom {
+ kind: ErrorKind,
+ error: Box<error::Error+Send+Sync>,
+}
+
+/// A list specifying general categories of I/O error.
+///
+/// This list is intended to grow over time and it is not recommended to
+/// exhaustively match against it.
+#[derive(Copy, PartialEq, Eq, Clone, Debug)]
+#[allow(deprecated)]
+pub enum ErrorKind {
+ /// An entity was not found, often a file.
+ NotFound,
+ /// The operation lacked the necessary privileges to complete.
+ PermissionDenied,
+ /// The connection was refused by the remote server.
+ ConnectionRefused,
+ /// The connection was reset by the remote server.
+ ConnectionReset,
+ /// The connection was aborted (terminated) by the remote server.
+ ConnectionAborted,
+ /// The network operation failed because it was not connected yet.
+ NotConnected,
+ /// A socket address could not be bound because the address is already in
+ /// use elsewhere.
+ AddrInUse,
+ /// A nonexistent interface was requested or the requested address was not
+ /// local.
+ AddrNotAvailable,
+ /// The operation failed because a pipe was closed.
+ BrokenPipe,
+ /// An entity already exists, often a file.
+ AlreadyExists,
+ /// The operation needs to block to complete, but the blocking operation was
+ /// requested to not occur.
+ WouldBlock,
+ /// A parameter was incorrect.
+ InvalidInput,
+ /// Data not valid for the operation were encountered.
+ ///
+ /// Unlike `InvalidInput`, this typically means that the operation
+ /// parameters were valid, however the error was caused by malformed
+ /// input data.
+ ///
+ /// For example, a function that reads a file into a string will error with
+ /// `InvalidData` if the file's contents are not valid UTF-8.
+ InvalidData,
+ /// The I/O operation's timeout expired, causing it to be canceled.
+ TimedOut,
+ /// An error returned when an operation could not be completed because a
+ /// call to `write` returned `Ok(0)`.
+ ///
+ /// This typically means that an operation could only succeed if it wrote a
+ /// particular number of bytes but only a smaller number of bytes could be
+ /// written.
+ WriteZero,
+ /// This operation was interrupted.
+ ///
+ /// Interrupted operations can typically be retried.
+ Interrupted,
+ /// Any I/O error not part of this list.
+ Other,
+
+ /// An error returned when an operation could not be completed because an
+ /// "end of file" was reached prematurely.
+ ///
+ /// This typically means that an operation could only succeed if it read a
+ /// particular number of bytes but only a smaller number of bytes could be
+ /// read.
+ UnexpectedEof,
+
+ /// Any I/O error not part of this list.
+ #[doc(hidden)]
+ __Nonexhaustive,
+}
+
+impl Error {
+ /// Creates a new I/O error from a known kind of error as well as an
+ /// arbitrary error payload.
+ ///
+ /// 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`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::{Error, ErrorKind};
+ ///
+ /// // errors can be created from strings
+ /// let custom_error = Error::new(ErrorKind::Other, "oh no!");
+ ///
+ /// // errors can also be created from other errors
+ /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
+ /// ```
+ pub fn new<E>(kind: ErrorKind, error: E) -> Error
+ where E: Into<Box<error::Error+Send+Sync>>
+ {
+ Self::_new(kind, error.into())
+ }
+
+ fn _new(kind: ErrorKind, error: Box<error::Error+Send+Sync>) -> Error {
+ Error {
+ repr: Repr::Custom(Box::new(Custom {
+ kind: kind,
+ error: error,
+ }))
+ }
+ }
+
+ /// Creates a new instance of an `Error` from a particular OS error code.
+ pub fn from_raw_os_error(code: i32) -> Error {
+ Error { repr: Repr::Os(code) }
+ }
+
+ /// Returns the OS error that this error represents (if any).
+ ///
+ /// 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`.
+ pub fn raw_os_error(&self) -> Option<i32> {
+ match self.repr {
+ Repr::Os(i) => Some(i),
+ Repr::Custom(..) => None,
+ }
+ }
+
+ /// 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`.
+ 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`.
+ 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`.
+ 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.
+ pub fn kind(&self) -> ErrorKind {
+ match self.repr {
+ Repr::Os(_code) => ErrorKind::Other,
+ Repr::Custom(ref c) => c.kind,
+ }
+ }
+}
+
+impl fmt::Debug for Repr {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ Repr::Os(ref code) =>
+ fmt.debug_struct("Os").field("code", code).finish(),
+ Repr::Custom(ref c) => fmt.debug_tuple("Custom").field(c).finish(),
+ }
+ }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ match self.repr {
+ Repr::Os(code) => {
+ write!(fmt, "os error {}", code)
+ }
+ Repr::Custom(ref c) => c.error.fmt(fmt),
+ }
+ }
+}
+
+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::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 fmt;
+ use sys::os::error_string;
+
+ #[test]
+ fn test_debug_error() {
+ let code = 6;
+ let msg = error_string(code);
+ let err = Error { repr: super::Repr::Os(code) };
+ let expected = format!("Error {{ repr: Os {{ code: {:?}, message: {:?} }} }}", code, msg);
+ assert_eq!(format!("{:?}", err), expected);
+ }
+
+ #[test]
+ fn test_downcasting() {
+ #[derive(Debug)]
+ struct TestError;
+
+ impl fmt::Display for TestError {
+ fn fmt(&self, _: &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!(err.get_ref().unwrap().is::<TestError>());
+ assert_eq!("asdf", err.get_ref().unwrap().description());
+ assert!(err.get_mut().unwrap().is::<TestError>());
+ let extracted = err.into_inner().unwrap();
+ extracted.downcast::<TestError>().unwrap();
+ }
+}