core2/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 core2::io;
28///
29/// #[cfg(feature = "std")]
30/// fn get_string() -> io::Result<String> {
31///     let mut buffer = String::new();
32///
33///     std::io::stdin().read_line(&mut buffer).map_err(|e| io::Error::from(e))?;
34///
35///     Ok(buffer)
36/// }
37/// ```
38pub type Result<T> = result::Result<T, Error>;
39
40/// The error type for I/O operations of the [`Read`], [`Write`], [`Seek`], and
41/// associated traits.
42///
43/// Errors mostly originate from the underlying OS, but custom instances of
44/// `Error` can be created with crafted error messages and a particular value of
45/// [`ErrorKind`].
46///
47/// [`Read`]: crate::io::Read
48/// [`Write`]: crate::io::Write
49/// [`Seek`]: crate::io::Seek
50pub struct Error {
51    repr: Repr,
52}
53
54impl crate::error::Error for Error {}
55
56impl fmt::Debug for Error {
57    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58        fmt::Debug::fmt(&self.repr, f)
59    }
60}
61
62enum Repr {
63    Simple(ErrorKind),
64    Custom(Custom),
65}
66
67#[derive(Debug)]
68struct Custom {
69    kind: ErrorKind,
70    error: &'static str,
71}
72
73/// A list specifying general categories of I/O error.
74///
75/// This list is intended to grow over time and it is not recommended to
76/// exhaustively match against it.
77///
78/// It is used with the [`io::Error`] type.
79///
80/// [`io::Error`]: Error
81#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
82// #[allow(deprecated)]
83#[non_exhaustive]
84pub enum ErrorKind {
85    /// An entity was not found, often a file.
86    NotFound,
87    /// The operation lacked the necessary privileges to complete.
88    PermissionDenied,
89    /// The connection was refused by the remote server.
90    ConnectionRefused,
91    /// The connection was reset by the remote server.
92    ConnectionReset,
93    /// The connection was aborted (terminated) by the remote server.
94    ConnectionAborted,
95    /// The network operation failed because it was not connected yet.
96    NotConnected,
97    /// A socket address could not be bound because the address is already in
98    /// use elsewhere.
99    AddrInUse,
100    /// A nonexistent interface was requested or the requested address was not
101    /// local.
102    AddrNotAvailable,
103    /// The operation failed because a pipe was closed.
104    BrokenPipe,
105    /// An entity already exists, often a file.
106    AlreadyExists,
107    /// The operation needs to block to complete, but the blocking operation was
108    /// requested to not occur.
109    WouldBlock,
110    /// A parameter was incorrect.
111    InvalidInput,
112    /// Data not valid for the operation were encountered.
113    ///
114    /// Unlike [`InvalidInput`], this typically means that the operation
115    /// parameters were valid, however the error was caused by malformed
116    /// input data.
117    ///
118    /// For example, a function that reads a file into a string will error with
119    /// `InvalidData` if the file's contents are not valid UTF-8.
120    ///
121    /// [`InvalidInput`]: ErrorKind::InvalidInput
122    InvalidData,
123    /// The I/O operation's timeout expired, causing it to be canceled.
124    TimedOut,
125    /// An error returned when an operation could not be completed because a
126    /// call to [`write`] returned [`Ok(0)`].
127    ///
128    /// This typically means that an operation could only succeed if it wrote a
129    /// particular number of bytes but only a smaller number of bytes could be
130    /// written.
131    ///
132    /// [`write`]: crate::io::Write::write
133    /// [`Ok(0)`]: Ok
134    WriteZero,
135    /// This operation was interrupted.
136    ///
137    /// Interrupted operations can typically be retried.
138    Interrupted,
139    /// Any I/O error not part of this list.
140    ///
141    /// Errors that are `Other` now may move to a different or a new
142    /// [`ErrorKind`] variant in the future. It is not recommended to match
143    /// an error against `Other` and to expect any additional characteristics,
144    /// e.g., a specific [`Error::raw_os_error`] return value.
145    Other,
146
147    /// An error returned when an operation could not be completed because an
148    /// "end of file" was reached prematurely.
149    ///
150    /// This typically means that an operation could only succeed if it read a
151    /// particular number of bytes but only a smaller number of bytes could be
152    /// read.
153    UnexpectedEof,
154
155    /// Any I/O error from the standard library that's not part of this list.
156    ///
157    /// Errors that are `Uncategorized` now may move to a different or a new
158    /// [`ErrorKind`] variant in the future. It is not recommended to match
159    /// an error against `Uncategorized`; use a wildcard match (`_`) instead.
160    #[doc(hidden)]
161    Uncategorized,
162}
163
164impl ErrorKind {
165    pub(crate) fn as_str(&self) -> &'static str {
166        match *self {
167            ErrorKind::NotFound => "entity not found",
168            ErrorKind::PermissionDenied => "permission denied",
169            ErrorKind::ConnectionRefused => "connection refused",
170            ErrorKind::ConnectionReset => "connection reset",
171            ErrorKind::ConnectionAborted => "connection aborted",
172            ErrorKind::NotConnected => "not connected",
173            ErrorKind::AddrInUse => "address in use",
174            ErrorKind::AddrNotAvailable => "address not available",
175            ErrorKind::BrokenPipe => "broken pipe",
176            ErrorKind::AlreadyExists => "entity already exists",
177            ErrorKind::WouldBlock => "operation would block",
178            ErrorKind::InvalidInput => "invalid input parameter",
179            ErrorKind::InvalidData => "invalid data",
180            ErrorKind::TimedOut => "timed out",
181            ErrorKind::WriteZero => "write zero",
182            ErrorKind::Interrupted => "operation interrupted",
183            ErrorKind::Other => "other os error",
184            ErrorKind::UnexpectedEof => "unexpected end of file",
185            ErrorKind::Uncategorized => "uncategorized",
186        }
187    }
188}
189
190#[cfg(feature = "std")]
191impl From<std::io::ErrorKind> for ErrorKind {
192    /// Converts an [`std::io::ErrorKind`] into an [`ErrorKind`].
193    ///
194    /// This conversion allocates a new error with a simple representation of error kind.
195    ///
196    /// # Examples
197    ///
198    /// ```
199    /// use core2::io::{Error, ErrorKind};
200    ///
201    /// let not_found = ErrorKind::from(std::io::ErrorKind::NotFound);
202    /// let err: Error = not_found.into();
203    /// assert_eq!("entity not found", format!("{}", err));
204    /// ```
205    fn from(k: std::io::ErrorKind) -> Self {
206        match k {
207            std::io::ErrorKind::NotFound => ErrorKind::NotFound,
208            std::io::ErrorKind::PermissionDenied => ErrorKind::PermissionDenied,
209            std::io::ErrorKind::ConnectionRefused => ErrorKind::ConnectionRefused,
210            std::io::ErrorKind::ConnectionReset => ErrorKind::ConnectionReset,
211            std::io::ErrorKind::ConnectionAborted => ErrorKind::ConnectionAborted,
212            std::io::ErrorKind::NotConnected => ErrorKind::NotConnected,
213            std::io::ErrorKind::AddrInUse => ErrorKind::AddrInUse,
214            std::io::ErrorKind::AddrNotAvailable => ErrorKind::AddrNotAvailable,
215            std::io::ErrorKind::BrokenPipe => ErrorKind::BrokenPipe,
216            std::io::ErrorKind::AlreadyExists => ErrorKind::AlreadyExists,
217            std::io::ErrorKind::WouldBlock => ErrorKind::WouldBlock,
218            std::io::ErrorKind::InvalidInput => ErrorKind::InvalidInput,
219            std::io::ErrorKind::InvalidData => ErrorKind::InvalidData,
220            std::io::ErrorKind::TimedOut => ErrorKind::TimedOut,
221            std::io::ErrorKind::WriteZero => ErrorKind::WriteZero,
222            std::io::ErrorKind::Interrupted => ErrorKind::Interrupted,
223            std::io::ErrorKind::Other => ErrorKind::Other,
224            std::io::ErrorKind::UnexpectedEof => ErrorKind::UnexpectedEof,
225            _ => ErrorKind::Uncategorized,
226        }
227    }
228}
229
230/// Intended for use for errors not exposed to the user, where allocating onto
231/// the heap (for normal construction via Error::new) is too costly.
232impl From<ErrorKind> for Error {
233    /// Converts an [`ErrorKind`] into an [`Error`].
234    ///
235    /// This conversion allocates a new error with a simple representation of error kind.
236    ///
237    /// # Examples
238    ///
239    /// ```
240    /// use core2::io::{Error, ErrorKind};
241    ///
242    /// let not_found = ErrorKind::NotFound;
243    /// let error = Error::from(not_found);
244    /// assert_eq!("entity not found", format!("{}", error));
245    /// ```
246    #[inline]
247    fn from(kind: ErrorKind) -> Error {
248        Error {
249            repr: Repr::Simple(kind),
250        }
251    }
252}
253
254#[cfg(feature = "std")]
255impl From<std::io::Error> for Error {
256    /// Converts an [`std::io::ErrorKind`] into an [`Error`].
257    ///
258    /// This conversion allocates a new error with a simple representation of error kind.
259    ///
260    /// # Examples
261    ///
262    /// ```
263    /// use core2::io::{Error, ErrorKind};
264    ///
265    /// let not_found = std::io::Error::from(std::io::ErrorKind::NotFound);
266    /// let error = Error::from(not_found);
267    /// assert_eq!("entity not found", format!("{}", error));
268    /// ```
269    #[inline]
270    fn from(err: std::io::Error) -> Self {
271        Self::from(ErrorKind::from(err.kind()))
272    }
273}
274
275impl Error {
276    /// Creates a new I/O error from a known kind of error as well as an
277    /// arbitrary error payload.
278    ///
279    /// This function is used to generically create I/O errors which do not
280    /// originate from the OS itself. The `error` argument is an arbitrary
281    /// payload which will be contained in this [`Error`].
282    ///
283    /// # Examples
284    ///
285    /// ```
286    /// use core2::io::{Error, ErrorKind};
287    ///
288    /// // errors can be created from strings
289    /// let custom_error = Error::new(ErrorKind::Other, "oh no!");
290    ///
291    /// // errors can also be created from other errors
292    /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error.into_inner().unwrap());
293    /// ```
294    pub fn new(kind: ErrorKind, error: &'static str) -> Error {
295        Self::_new(kind, error.into())
296    }
297
298    fn _new(kind: ErrorKind, error: &'static str) -> Error {
299        Error {
300            repr: Repr::Custom(Custom { kind, error }),
301        }
302    }
303
304    /// Returns a reference to the inner error wrapped by this error (if any).
305    ///
306    /// If this [`Error`] was constructed via [`new`] then this function will
307    /// return [`Some`], otherwise it will return [`None`].
308    ///
309    /// [`new`]: Error::new
310    ///
311    /// # Examples
312    ///
313    /// ```
314    /// use core2::io::{Error, ErrorKind};
315    ///
316    /// fn print_error(err: &Error) {
317    ///     if let Some(inner_err) = err.get_ref() {
318    ///         println!("Inner error: {:?}", inner_err);
319    ///     } else {
320    ///         println!("No inner error");
321    ///     }
322    /// }
323    ///
324    /// #[cfg(feature = "std")]
325    /// fn emit_error() {
326    ///     // Will print "No inner error".
327    ///     print_error(&Error::from(std::io::Error::last_os_error()));
328    ///     // Will print "Inner error: ...".
329    ///     print_error(&Error::new(ErrorKind::Other, "oh no!"));
330    /// }
331    ///
332    /// #[cfg(not(feature = "std"))]
333    /// fn emit_error() {
334    ///     // Will print "No inner error".
335    ///     print_error(&ErrorKind::Other.into());
336    ///     // Will print "Inner error: ...".
337    ///     print_error(&Error::new(ErrorKind::Other, "oh no!"));
338    /// }
339    ///
340    /// fn main() {
341    ///     emit_error();
342    /// }
343    /// ```
344    pub fn get_ref(&self) -> Option<&&'static str> {
345        match self.repr {
346            Repr::Simple(..) => None,
347            Repr::Custom(ref c) => Some(&c.error),
348        }
349    }
350
351    /// Consumes the `Error`, returning its inner error (if any).
352    ///
353    /// If this [`Error`] was constructed via [`new`] then this function will
354    /// return [`Some`], otherwise it will return [`None`].
355    ///
356    /// [`new`]: Error::new
357    ///
358    /// # Examples
359    ///
360    /// ```
361    /// use core2::io::{Error, ErrorKind};
362    ///
363    /// fn print_error(err: Error) {
364    ///     if let Some(inner_err) = err.into_inner() {
365    ///         println!("Inner error: {}", inner_err);
366    ///     } else {
367    ///         println!("No inner error");
368    ///     }
369    /// }
370    ///
371    /// #[cfg(feature = "std")]
372    /// fn emit_error() {
373    ///     // Will print "No inner error".
374    ///     print_error(std::io::Error::last_os_error().into());
375    ///     // Will print "Inner error: ...".
376    ///     print_error(Error::new(ErrorKind::Other, "oh no!"));
377    /// }
378    ///
379    /// #[cfg(not(feature = "std"))]
380    /// fn emit_error() {
381    ///     // Will print "No inner error".
382    ///     print_error(ErrorKind::Other.into());
383    ///     // Will print "Inner error: ...".
384    ///     print_error(Error::new(ErrorKind::Other, "oh no!"));
385    /// }
386    ///
387    /// fn main() {
388    ///     emit_error();
389    /// }
390    /// ```
391    pub fn into_inner(self) -> Option<&'static str> {
392        match self.repr {
393            Repr::Simple(..) => None,
394            Repr::Custom(c) => Some(c.error),
395        }
396    }
397
398    /// Returns the corresponding [`ErrorKind`] for this error.
399    ///
400    /// # Examples
401    ///
402    /// ```
403    /// use core2::io::{Error, ErrorKind};
404    ///
405    /// fn print_error(err: Error) {
406    ///     println!("{:?}", err.kind());
407    /// }
408    ///
409    /// #[cfg(feature = "std")]
410    /// fn emit_error() {
411    ///     // Will print "Other".
412    ///     print_error(std::io::Error::last_os_error().into());
413    ///     // Will print "AddrInUse".
414    ///     print_error(Error::new(ErrorKind::AddrInUse, "oh no!"));
415    /// }
416    ///
417    /// #[cfg(not(feature = "std"))]
418    /// fn emit_error() {
419    ///     // Will print "Other".
420    ///     print_error(ErrorKind::Other.into());
421    ///     // Will print "AddrInUse".
422    ///     print_error(Error::new(ErrorKind::AddrInUse, "oh no!"));
423    /// }
424    ///
425    /// fn main() {
426    ///     emit_error();
427    /// }
428    /// ```
429    pub fn kind(&self) -> ErrorKind {
430        match self.repr {
431            Repr::Custom(ref c) => c.kind,
432            Repr::Simple(kind) => kind,
433        }
434    }
435}
436
437impl fmt::Debug for Repr {
438    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
439        match *self {
440            Repr::Custom(ref c) => fmt::Debug::fmt(&c, fmt),
441            Repr::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
442        }
443    }
444}
445
446impl fmt::Display for Error {
447    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
448        match self.repr {
449            Repr::Custom(ref c) => c.error.fmt(fmt),
450            Repr::Simple(kind) => write!(fmt, "{}", kind.as_str()),
451        }
452    }
453}
454
455fn _assert_error_is_sync_send() {
456    fn _is_sync_send<T: Sync + Send>() {}
457    _is_sync_send::<Error>();
458}