Skip to main content

relibc/io/
error.rs

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