Skip to main content

bare_io/
error.rs

1use core::{convert::From, fmt, result};
2
3/// A specialized [`Result`] type for I/O operations.
4///
5/// This type is broadly used across [`std::io`] for any operation which may
6/// produce an error.
7///
8/// This typedef is generally used to avoid writing out [`io::Error`] directly and
9/// is otherwise a direct mapping to [`Result`].
10///
11/// While usual Rust style is to import types directly, aliases of [`Result`]
12/// often are not, to make it easier to distinguish between them. [`Result`] is
13/// generally assumed to be [`std::result::Result`][`Result`], and so users of this alias
14/// will generally use `io::Result` instead of shadowing the [prelude]'s import
15/// of [`std::result::Result`][`Result`].
16///
17/// [`std::io`]: crate::io
18/// [`io::Error`]: Error
19/// [`Result`]: crate::result::Result
20/// [prelude]: crate::prelude
21///
22/// # Examples
23///
24/// A convenience function that bubbles an `io::Result` to its caller:
25///
26/// ```
27/// use std::io;
28///
29/// fn get_string() -> io::Result<String> {
30///     let mut buffer = String::new();
31///
32///     io::stdin().read_line(&mut buffer)?;
33///
34///     Ok(buffer)
35/// }
36/// ```
37pub type Result<T> = result::Result<T, Error>;
38
39/// The error type for I/O operations of the [`Read`], [`Write`], [`Seek`], and
40/// associated traits.
41///
42/// Errors mostly originate from the underlying OS, but custom instances of
43/// `Error` can be created with crafted error messages and a particular value of
44/// [`ErrorKind`].
45///
46/// [`Read`]: crate::io::Read
47/// [`Write`]: crate::io::Write
48/// [`Seek`]: crate::io::Seek
49pub struct Error {
50    repr: Repr,
51}
52
53impl fmt::Debug for Error {
54    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55        fmt::Debug::fmt(&self.repr, f)
56    }
57}
58
59enum Repr {
60    Simple(ErrorKind),
61    Custom(Custom),
62}
63
64#[derive(Debug)]
65struct Custom {
66    kind: ErrorKind,
67    error: &'static str,
68}
69
70/// A list specifying general categories of I/O error.
71///
72/// This list is intended to grow over time and it is not recommended to
73/// exhaustively match against it.
74///
75/// It is used with the [`io::Error`] type.
76///
77/// [`io::Error`]: Error
78#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
79// #[allow(deprecated)]
80#[non_exhaustive]
81pub enum ErrorKind {
82    /// An entity was not found, often a file.
83    NotFound,
84    /// The operation lacked the necessary privileges to complete.
85    PermissionDenied,
86    /// The connection was refused by the remote server.
87    ConnectionRefused,
88    /// The connection was reset by the remote server.
89    ConnectionReset,
90    /// The connection was aborted (terminated) by the remote server.
91    ConnectionAborted,
92    /// The network operation failed because it was not connected yet.
93    NotConnected,
94    /// A socket address could not be bound because the address is already in
95    /// use elsewhere.
96    AddrInUse,
97    /// A nonexistent interface was requested or the requested address was not
98    /// local.
99    AddrNotAvailable,
100    /// The operation failed because a pipe was closed.
101    BrokenPipe,
102    /// An entity already exists, often a file.
103    AlreadyExists,
104    /// The operation needs to block to complete, but the blocking operation was
105    /// requested to not occur.
106    WouldBlock,
107    /// A parameter was incorrect.
108    InvalidInput,
109    /// Data not valid for the operation were encountered.
110    ///
111    /// Unlike [`InvalidInput`], this typically means that the operation
112    /// parameters were valid, however the error was caused by malformed
113    /// input data.
114    ///
115    /// For example, a function that reads a file into a string will error with
116    /// `InvalidData` if the file's contents are not valid UTF-8.
117    ///
118    /// [`InvalidInput`]: ErrorKind::InvalidInput
119    InvalidData,
120    /// The I/O operation's timeout expired, causing it to be canceled.
121    TimedOut,
122    /// An error returned when an operation could not be completed because a
123    /// call to [`write`] returned [`Ok(0)`].
124    ///
125    /// This typically means that an operation could only succeed if it wrote a
126    /// particular number of bytes but only a smaller number of bytes could be
127    /// written.
128    ///
129    /// [`write`]: crate::io::Write::write
130    /// [`Ok(0)`]: Ok
131    WriteZero,
132    /// This operation was interrupted.
133    ///
134    /// Interrupted operations can typically be retried.
135    Interrupted,
136    /// Any I/O error not part of this list.
137    ///
138    /// Errors that are `Other` now may move to a different or a new
139    /// [`ErrorKind`] variant in the future. It is not recommended to match
140    /// an error against `Other` and to expect any additional characteristics,
141    /// e.g., a specific [`Error::raw_os_error`] return value.
142    Other,
143
144    /// An error returned when an operation could not be completed because an
145    /// "end of file" was reached prematurely.
146    ///
147    /// This typically means that an operation could only succeed if it read a
148    /// particular number of bytes but only a smaller number of bytes could be
149    /// read.
150    UnexpectedEof,
151}
152
153impl ErrorKind {
154    pub(crate) fn as_str(&self) -> &'static str {
155        match *self {
156            ErrorKind::NotFound => "entity not found",
157            ErrorKind::PermissionDenied => "permission denied",
158            ErrorKind::ConnectionRefused => "connection refused",
159            ErrorKind::ConnectionReset => "connection reset",
160            ErrorKind::ConnectionAborted => "connection aborted",
161            ErrorKind::NotConnected => "not connected",
162            ErrorKind::AddrInUse => "address in use",
163            ErrorKind::AddrNotAvailable => "address not available",
164            ErrorKind::BrokenPipe => "broken pipe",
165            ErrorKind::AlreadyExists => "entity already exists",
166            ErrorKind::WouldBlock => "operation would block",
167            ErrorKind::InvalidInput => "invalid input parameter",
168            ErrorKind::InvalidData => "invalid data",
169            ErrorKind::TimedOut => "timed out",
170            ErrorKind::WriteZero => "write zero",
171            ErrorKind::Interrupted => "operation interrupted",
172            ErrorKind::Other => "other os error",
173            ErrorKind::UnexpectedEof => "unexpected end of file",
174        }
175    }
176}
177
178/// Intended for use for errors not exposed to the user, where allocating onto
179/// the heap (for normal construction via Error::new) is too costly.
180impl From<ErrorKind> for Error {
181    /// Converts an [`ErrorKind`] into an [`Error`].
182    ///
183    /// This conversion allocates a new error with a simple representation of error kind.
184    ///
185    /// # Examples
186    ///
187    /// ```
188    /// use std::io::{Error, ErrorKind};
189    ///
190    /// let not_found = ErrorKind::NotFound;
191    /// let error = Error::from(not_found);
192    /// assert_eq!("entity not found", format!("{}", error));
193    /// ```
194    #[inline]
195    fn from(kind: ErrorKind) -> Error {
196        Error {
197            repr: Repr::Simple(kind),
198        }
199    }
200}
201
202impl Error {
203    /// Creates a new I/O error from a known kind of error as well as an
204    /// arbitrary error payload.
205    ///
206    /// This function is used to generically create I/O errors which do not
207    /// originate from the OS itself. The `error` argument is an arbitrary
208    /// payload which will be contained in this [`Error`].
209    ///
210    /// # Examples
211    ///
212    /// ```
213    /// use std::io::{Error, ErrorKind};
214    ///
215    /// // errors can be created from strings
216    /// let custom_error = Error::new(ErrorKind::Other, "oh no!");
217    ///
218    /// // errors can also be created from other errors
219    /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
220    /// ```
221    pub fn new(kind: ErrorKind, error: &'static str) -> Error {
222        Self::_new(kind, error.into())
223    }
224
225    fn _new(kind: ErrorKind, error: &'static str) -> Error {
226        Error {
227            repr: Repr::Custom(Custom { kind, error }),
228        }
229    }
230
231    /// Returns a reference to the inner error wrapped by this error (if any).
232    ///
233    /// If this [`Error`] was constructed via [`new`] then this function will
234    /// return [`Some`], otherwise it will return [`None`].
235    ///
236    /// [`new`]: Error::new
237    ///
238    /// # Examples
239    ///
240    /// ```
241    /// use std::io::{Error, ErrorKind};
242    ///
243    /// fn print_error(err: &Error) {
244    ///     if let Some(inner_err) = err.get_ref() {
245    ///         println!("Inner error: {:?}", inner_err);
246    ///     } else {
247    ///         println!("No inner error");
248    ///     }
249    /// }
250    ///
251    /// fn main() {
252    ///     // Will print "No inner error".
253    ///     print_error(&Error::last_os_error());
254    ///     // Will print "Inner error: ...".
255    ///     print_error(&Error::new(ErrorKind::Other, "oh no!"));
256    /// }
257    /// ```
258    pub fn get_ref(&self) -> Option<&&'static str> {
259        match self.repr {
260            Repr::Simple(..) => None,
261            Repr::Custom(ref c) => Some(&c.error),
262        }
263    }
264
265    /// Consumes the `Error`, returning its inner error (if any).
266    ///
267    /// If this [`Error`] was constructed via [`new`] then this function will
268    /// return [`Some`], otherwise it will return [`None`].
269    ///
270    /// [`new`]: Error::new
271    ///
272    /// # Examples
273    ///
274    /// ```
275    /// use std::io::{Error, ErrorKind};
276    ///
277    /// fn print_error(err: Error) {
278    ///     if let Some(inner_err) = err.into_inner() {
279    ///         println!("Inner error: {}", inner_err);
280    ///     } else {
281    ///         println!("No inner error");
282    ///     }
283    /// }
284    ///
285    /// fn main() {
286    ///     // Will print "No inner error".
287    ///     print_error(Error::last_os_error());
288    ///     // Will print "Inner error: ...".
289    ///     print_error(Error::new(ErrorKind::Other, "oh no!"));
290    /// }
291    /// ```
292    pub fn into_inner(self) -> Option<&'static str> {
293        match self.repr {
294            Repr::Simple(..) => None,
295            Repr::Custom(c) => Some(c.error),
296        }
297    }
298
299    /// Returns the corresponding [`ErrorKind`] for this error.
300    ///
301    /// # Examples
302    ///
303    /// ```
304    /// use std::io::{Error, ErrorKind};
305    ///
306    /// fn print_error(err: Error) {
307    ///     println!("{:?}", err.kind());
308    /// }
309    ///
310    /// fn main() {
311    ///     // Will print "Other".
312    ///     print_error(Error::last_os_error());
313    ///     // Will print "AddrInUse".
314    ///     print_error(Error::new(ErrorKind::AddrInUse, "oh no!"));
315    /// }
316    /// ```
317    pub fn kind(&self) -> ErrorKind {
318        match self.repr {
319            Repr::Custom(ref c) => c.kind,
320            Repr::Simple(kind) => kind,
321        }
322    }
323}
324
325impl fmt::Debug for Repr {
326    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
327        match *self {
328            Repr::Custom(ref c) => fmt::Debug::fmt(&c, fmt),
329            Repr::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
330        }
331    }
332}
333
334impl fmt::Display for Error {
335    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
336        match self.repr {
337            Repr::Custom(ref c) => c.error.fmt(fmt),
338            Repr::Simple(kind) => write!(fmt, "{}", kind.as_str()),
339        }
340    }
341}
342
343fn _assert_error_is_sync_send() {
344    fn _is_sync_send<T: Sync + Send>() {}
345    _is_sync_send::<Error>();
346}