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}