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}