ckb_rust_std/io/error.rs
1use alloc::{boxed::Box, fmt};
2use core::result;
3
4pub mod core_error {
5 #[cfg(feature = "rust_before_181")]
6 pub use crate::io::cherry_picking::error::Error;
7 #[cfg(not(feature = "rust_before_181"))]
8 pub use core::error::Error;
9}
10
11/// A specialized [`Result`] type for I/O operations.
12///
13/// This type is broadly used across [`std::io`] for any operation which may
14/// produce an error.
15///
16/// This typedef is generally used to avoid writing out [`io::Error`] directly and
17/// is otherwise a direct mapping to [`Result`].
18///
19/// While usual Rust style is to import types directly, aliases of [`Result`]
20/// often are not, to make it easier to distinguish between them. [`Result`] is
21/// generally assumed to be [`std::result::Result`][`Result`], and so users of this alias
22/// will generally use `io::Result` instead of shadowing the [prelude]'s import
23/// of [`std::result::Result`][`Result`].
24///
25/// [`std::io`]: crate::io
26/// [`io::Error`]: Error
27/// [`Result`]: crate::result::Result
28/// [prelude]: crate::prelude
29///
30/// # Examples
31///
32/// A convenience function that bubbles an `io::Result` to its caller:
33///
34/// ```
35/// use std::io;
36///
37/// fn get_string() -> io::Result<String> {
38/// let mut buffer = String::new();
39///
40/// io::stdin().read_line(&mut buffer)?;
41///
42/// Ok(buffer)
43/// }
44/// ```
45pub type Result<T> = result::Result<T, Error>;
46
47/// The error type for I/O operations of the [`Read`], [`Write`], [`Seek`], and
48/// associated traits.
49///
50/// Errors mostly originate from the underlying OS, but custom instances of
51/// `Error` can be created with crafted error messages and a particular value of
52/// [`ErrorKind`].
53///
54/// [`Read`]: crate::io::Read
55/// [`Write`]: crate::io::Write
56/// [`Seek`]: crate::io::Seek
57
58pub enum Error {
59 Os(i64),
60 Simple(ErrorKind),
61 SimpleMessage(&'static SimpleMessage),
62 Custom(Box<Custom>),
63}
64
65impl Error {
66 pub fn new_simple(kind: ErrorKind) -> Self {
67 Self::Simple(kind)
68 }
69 pub fn new_custom(custom: Box<Custom>) -> Self {
70 Self::Custom(custom)
71 }
72 pub const fn new_simple_message(msg: &'static SimpleMessage) -> Self {
73 Self::SimpleMessage(msg)
74 }
75 pub fn new_os(code: i64) -> Self {
76 Self::Os(code)
77 }
78}
79
80impl fmt::Debug for Error {
81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 fmt::Debug::fmt(&self, f)
83 }
84}
85
86/// Create and return an `io::Error` for a given `ErrorKind` and constant
87/// message. This doesn't allocate.
88#[macro_export]
89macro_rules! const_io_error {
90 ($kind:expr, $message:expr $(,)?) => {
91 $crate::io::error::Error::from_static_message({
92 const MESSAGE_DATA: $crate::io::error::SimpleMessage =
93 $crate::io::error::SimpleMessage::new($kind, $message);
94 &MESSAGE_DATA
95 })
96 };
97}
98
99#[allow(dead_code)]
100impl Error {
101 pub(crate) const INVALID_UTF8: Self =
102 const_io_error!(ErrorKind::InvalidData, "stream did not contain valid UTF-8");
103
104 pub(crate) const READ_EXACT_EOF: Self =
105 const_io_error!(ErrorKind::UnexpectedEof, "failed to fill whole buffer");
106
107 pub(crate) const UNKNOWN_THREAD_COUNT: Self = const_io_error!(
108 ErrorKind::NotFound,
109 "The number of hardware threads is not known for the target platform"
110 );
111
112 pub(crate) const UNSUPPORTED_PLATFORM: Self = const_io_error!(
113 ErrorKind::Unsupported,
114 "operation not supported on this platform"
115 );
116
117 pub(crate) const WRITE_ALL_EOF: Self =
118 const_io_error!(ErrorKind::WriteZero, "failed to write whole buffer");
119
120 pub(crate) const ZERO_TIMEOUT: Self =
121 const_io_error!(ErrorKind::InvalidInput, "cannot set a 0 duration timeout");
122}
123
124impl From<alloc::ffi::NulError> for Error {
125 /// Converts a [`alloc::ffi::NulError`] into a [`Error`].
126 fn from(_: alloc::ffi::NulError) -> Error {
127 const_io_error!(ErrorKind::InvalidInput, "data provided contains a nul byte")
128 }
129}
130
131impl From<alloc::collections::TryReserveError> for Error {
132 /// Converts `TryReserveError` to an error with [`ErrorKind::OutOfMemory`].
133 ///
134 /// `TryReserveError` won't be available as the error `source()`,
135 /// but this may change in the future.
136 fn from(_: alloc::collections::TryReserveError) -> Error {
137 // ErrorData::Custom allocates, which isn't great for handling OOM errors.
138 ErrorKind::OutOfMemory.into()
139 }
140}
141
142// `#[repr(align(4))]` is probably redundant, it should have that value or
143// higher already. We include it just because repr_bitpacked.rs's encoding
144// requires an alignment >= 4 (note that `#[repr(align)]` will not reduce the
145// alignment required by the struct, only increase it).
146//
147// If we add more variants to ErrorData, this can be increased to 8, but it
148// should probably be behind `#[cfg_attr(target_pointer_width = "64", ...)]` or
149// whatever cfg we're using to enable the `repr_bitpacked` code, since only the
150// that version needs the alignment, and 8 is higher than the alignment we'll
151// have on 32 bit platforms.
152//
153// (For the sake of being explicit: the alignment requirement here only matters
154// if `error/repr_bitpacked.rs` is in use — for the unpacked repr it doesn't
155// matter at all)
156#[repr(align(4))]
157#[derive(Debug)]
158pub struct SimpleMessage {
159 kind: ErrorKind,
160 message: &'static str,
161}
162
163impl SimpleMessage {
164 pub(crate) const fn new(kind: ErrorKind, message: &'static str) -> Self {
165 Self { kind, message }
166 }
167}
168
169// As with `SimpleMessage`: `#[repr(align(4))]` here is just because
170// repr_bitpacked's encoding requires it. In practice it almost certainly be
171// already be this high or higher.
172#[derive(Debug)]
173#[repr(align(4))]
174pub struct Custom {
175 kind: ErrorKind,
176 error: Box<dyn core_error::Error + Send + Sync>,
177}
178/// A list specifying general categories of I/O error.
179///
180/// This list is intended to grow over time and it is not recommended to
181/// exhaustively match against it.
182///
183/// It is used with the [`io::Error`] type.
184///
185/// [`io::Error`]: Error
186///
187/// # Handling errors and matching on `ErrorKind`
188///
189/// In application code, use `match` for the `ErrorKind` values you are
190/// expecting; use `_` to match "all other errors".
191///
192/// In comprehensive and thorough tests that want to verify that a test doesn't
193/// return any known incorrect error kind, you may want to cut-and-paste the
194/// current full list of errors from here into your test code, and then match
195/// `_` as the correct case. This seems counterintuitive, but it will make your
196/// tests more robust. In particular, if you want to verify that your code does
197/// produce an unrecognized error kind, the robust solution is to check for all
198/// the recognized error kinds and fail in those cases.
199#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
200#[allow(deprecated)]
201#[non_exhaustive]
202pub enum ErrorKind {
203 /// An entity was not found, often a file.
204 NotFound,
205 /// The operation lacked the necessary privileges to complete.
206 PermissionDenied,
207 /// The connection was refused by the remote server.
208 ConnectionRefused,
209 /// The connection was reset by the remote server.
210 ConnectionReset,
211 /// The remote host is not reachable.
212 HostUnreachable,
213 /// The network containing the remote host is not reachable.
214 NetworkUnreachable,
215 /// The connection was aborted (terminated) by the remote server.
216 ConnectionAborted,
217 /// The network operation failed because it was not connected yet.
218 NotConnected,
219 /// A socket address could not be bound because the address is already in
220 /// use elsewhere.
221 AddrInUse,
222 /// A nonexistent interface was requested or the requested address was not
223 /// local.
224 AddrNotAvailable,
225 /// The system's networking is down.
226 NetworkDown,
227 /// The operation failed because a pipe was closed.
228 BrokenPipe,
229 /// An entity already exists, often a file.
230 AlreadyExists,
231 /// The operation needs to block to complete, but the blocking operation was
232 /// requested to not occur.
233 WouldBlock,
234 /// A filesystem object is, unexpectedly, not a directory.
235 ///
236 /// For example, a filesystem path was specified where one of the intermediate directory
237 /// components was, in fact, a plain file.
238 NotADirectory,
239 /// The filesystem object is, unexpectedly, a directory.
240 ///
241 /// A directory was specified when a non-directory was expected.
242 IsADirectory,
243 /// A non-empty directory was specified where an empty directory was expected.
244 DirectoryNotEmpty,
245 /// The filesystem or storage medium is read-only, but a write operation was attempted.
246 ReadOnlyFilesystem,
247 /// Loop in the filesystem or IO subsystem; often, too many levels of symbolic links.
248 ///
249 /// There was a loop (or excessively long chain) resolving a filesystem object
250 /// or file IO object.
251 ///
252 /// On Unix this is usually the result of a symbolic link loop; or, of exceeding the
253 /// system-specific limit on the depth of symlink traversal.
254 FilesystemLoop,
255 /// Stale network file handle.
256 ///
257 /// With some network filesystems, notably NFS, an open file (or directory) can be invalidated
258 /// by problems with the network or server.
259 StaleNetworkFileHandle,
260 /// A parameter was incorrect.
261 InvalidInput,
262 /// Data not valid for the operation were encountered.
263 ///
264 /// Unlike [`InvalidInput`], this typically means that the operation
265 /// parameters were valid, however the error was caused by malformed
266 /// input data.
267 ///
268 /// For example, a function that reads a file into a string will error with
269 /// `InvalidData` if the file's contents are not valid UTF-8.
270 ///
271 /// [`InvalidInput`]: ErrorKind::InvalidInput
272 InvalidData,
273 /// The I/O operation's timeout expired, causing it to be canceled.
274 TimedOut,
275 /// An error returned when an operation could not be completed because a
276 /// call to [`write`] returned [`Ok(0)`].
277 ///
278 /// This typically means that an operation could only succeed if it wrote a
279 /// particular number of bytes but only a smaller number of bytes could be
280 /// written.
281 ///
282 /// [`write`]: crate::io::Write::write
283 /// [`Ok(0)`]: Ok
284 WriteZero,
285 /// The underlying storage (typically, a filesystem) is full.
286 ///
287 /// This does not include out of quota errors.
288 StorageFull,
289 /// Seek on unseekable file.
290 ///
291 /// Seeking was attempted on an open file handle which is not suitable for seeking - for
292 /// example, on Unix, a named pipe opened with `File::open`.
293 NotSeekable,
294 /// Filesystem quota was exceeded.
295 FilesystemQuotaExceeded,
296 /// File larger than allowed or supported.
297 ///
298 /// This might arise from a hard limit of the underlying filesystem or file access API, or from
299 /// an administratively imposed resource limitation. Simple disk full, and out of quota, have
300 /// their own errors.
301 FileTooLarge,
302 /// Resource is busy.
303 ResourceBusy,
304 /// Executable file is busy.
305 ///
306 /// An attempt was made to write to a file which is also in use as a running program. (Not all
307 /// operating systems detect this situation.)
308 ExecutableFileBusy,
309 /// Deadlock (avoided).
310 ///
311 /// A file locking operation would result in deadlock. This situation is typically detected, if
312 /// at all, on a best-effort basis.
313 Deadlock,
314 /// Cross-device or cross-filesystem (hard) link or rename.
315 CrossesDevices,
316 /// Too many (hard) links to the same filesystem object.
317 ///
318 /// The filesystem does not support making so many hardlinks to the same file.
319 TooManyLinks,
320 /// A filename was invalid.
321 ///
322 /// This error can also cause if it exceeded the filename length limit.
323 InvalidFilename,
324 /// Program argument list too long.
325 ///
326 /// When trying to run an external program, a system or process limit on the size of the
327 /// arguments would have been exceeded.
328 ArgumentListTooLong,
329 /// This operation was interrupted.
330 ///
331 /// Interrupted operations can typically be retried.
332 Interrupted,
333
334 /// This operation is unsupported on this platform.
335 ///
336 /// This means that the operation can never succeed.
337 Unsupported,
338
339 // ErrorKinds which are primarily categorisations for OS error
340 // codes should be added above.
341 //
342 /// An error returned when an operation could not be completed because an
343 /// "end of file" was reached prematurely.
344 ///
345 /// This typically means that an operation could only succeed if it read a
346 /// particular number of bytes but only a smaller number of bytes could be
347 /// read.
348 UnexpectedEof,
349
350 /// An operation could not be completed, because it failed
351 /// to allocate enough memory.
352 OutOfMemory,
353
354 // "Unusual" error kinds which do not correspond simply to (sets
355 // of) OS error codes, should be added just above this comment.
356 // `Other` and `Uncategorized` should remain at the end:
357 //
358 /// A custom error that does not fall under any other I/O error kind.
359 ///
360 /// This can be used to construct your own [`Error`]s that do not match any
361 /// [`ErrorKind`].
362 ///
363 /// This [`ErrorKind`] is not used by the standard library.
364 ///
365 /// Errors from the standard library that do not fall under any of the I/O
366 /// error kinds cannot be `match`ed on, and will only match a wildcard (`_`) pattern.
367 /// New [`ErrorKind`]s might be added in the future for some of those.
368 Other,
369
370 /// Any I/O error from the standard library that's not part of this list.
371 ///
372 /// Errors that are `Uncategorized` now may move to a different or a new
373 /// [`ErrorKind`] variant in the future. It is not recommended to match
374 /// an error against `Uncategorized`; use a wildcard match (`_`) instead.
375 #[doc(hidden)]
376 Uncategorized,
377}
378
379impl ErrorKind {
380 pub(crate) fn as_str(&self) -> &'static str {
381 use ErrorKind::*;
382 // tidy-alphabetical-start
383 match *self {
384 AddrInUse => "address in use",
385 AddrNotAvailable => "address not available",
386 AlreadyExists => "entity already exists",
387 ArgumentListTooLong => "argument list too long",
388 BrokenPipe => "broken pipe",
389 ConnectionAborted => "connection aborted",
390 ConnectionRefused => "connection refused",
391 ConnectionReset => "connection reset",
392 CrossesDevices => "cross-device link or rename",
393 Deadlock => "deadlock",
394 DirectoryNotEmpty => "directory not empty",
395 ExecutableFileBusy => "executable file busy",
396 FileTooLarge => "file too large",
397 FilesystemLoop => "filesystem loop or indirection limit (e.g. symlink loop)",
398 FilesystemQuotaExceeded => "filesystem quota exceeded",
399 HostUnreachable => "host unreachable",
400 Interrupted => "operation interrupted",
401 InvalidData => "invalid data",
402 InvalidFilename => "invalid filename",
403 InvalidInput => "invalid input parameter",
404 IsADirectory => "is a directory",
405 NetworkDown => "network down",
406 NetworkUnreachable => "network unreachable",
407 NotADirectory => "not a directory",
408 NotConnected => "not connected",
409 NotFound => "entity not found",
410 NotSeekable => "seek on unseekable file",
411 Other => "other error",
412 OutOfMemory => "out of memory",
413 PermissionDenied => "permission denied",
414 ReadOnlyFilesystem => "read-only filesystem or storage medium",
415 ResourceBusy => "resource busy",
416 StaleNetworkFileHandle => "stale network file handle",
417 StorageFull => "no storage space",
418 TimedOut => "timed out",
419 TooManyLinks => "too many links",
420 Uncategorized => "uncategorized error",
421 UnexpectedEof => "unexpected end of file",
422 Unsupported => "unsupported",
423 WouldBlock => "operation would block",
424 WriteZero => "write zero",
425 }
426 // tidy-alphabetical-end
427 }
428}
429
430impl fmt::Display for ErrorKind {
431 /// Shows a human-readable description of the `ErrorKind`.
432 ///
433 /// This is similar to `impl Display for Error`, but doesn't require first converting to Error.
434 ///
435 /// # Examples
436 /// ```
437 /// use std::io::ErrorKind;
438 /// assert_eq!("entity not found", ErrorKind::NotFound.to_string());
439 /// ```
440 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
441 fmt.write_str(self.as_str())
442 }
443}
444
445/// Intended for use for errors not exposed to the user, where allocating onto
446/// the heap (for normal construction via Error::new) is too costly.
447impl From<ErrorKind> for Error {
448 /// Converts an [`ErrorKind`] into an [`Error`].
449 ///
450 /// This conversion creates a new error with a simple representation of error kind.
451 ///
452 /// # Examples
453 ///
454 /// ```
455 /// use std::io::{Error, ErrorKind};
456 ///
457 /// let not_found = ErrorKind::NotFound;
458 /// let error = Error::from(not_found);
459 /// assert_eq!("entity not found", format!("{error}"));
460 /// ```
461 #[inline]
462 fn from(kind: ErrorKind) -> Error {
463 Error::new_simple(kind)
464 }
465}
466
467impl Error {
468 /// Creates a new I/O error from a known kind of error as well as an
469 /// arbitrary error payload.
470 ///
471 /// This function is used to generically create I/O errors which do not
472 /// originate from the OS itself. The `error` argument is an arbitrary
473 /// payload which will be contained in this [`Error`].
474 ///
475 /// Note that this function allocates memory on the heap.
476 /// If no extra payload is required, use the `From` conversion from
477 /// `ErrorKind`.
478 ///
479 /// # Examples
480 ///
481 /// ```
482 /// use std::io::{Error, ErrorKind};
483 ///
484 /// // errors can be created from strings
485 /// let custom_error = Error::new(ErrorKind::Other, "oh no!");
486 ///
487 /// // errors can also be created from other errors
488 /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
489 ///
490 /// // creating an error without payload (and without memory allocation)
491 /// let eof_error = Error::from(ErrorKind::UnexpectedEof);
492 /// ```
493 #[inline(never)]
494 pub fn new<E>(kind: ErrorKind, error: E) -> Error
495 where
496 E: Into<Box<dyn core_error::Error + Send + Sync>>,
497 {
498 Self::_new(kind, error.into())
499 }
500
501 /// Creates a new I/O error from an arbitrary error payload.
502 ///
503 /// This function is used to generically create I/O errors which do not
504 /// originate from the OS itself. It is a shortcut for [`Error::new`]
505 /// with [`ErrorKind::Other`].
506 ///
507 /// # Examples
508 ///
509 /// ```
510 /// use std::io::Error;
511 ///
512 /// // errors can be created from strings
513 /// let custom_error = Error::other("oh no!");
514 ///
515 /// // errors can also be created from other errors
516 /// let custom_error2 = Error::other(custom_error);
517 /// ```
518 pub fn other<E>(error: E) -> Error
519 where
520 E: Into<Box<dyn core_error::Error + Send + Sync>>,
521 {
522 Self::_new(ErrorKind::Other, error.into())
523 }
524
525 fn _new(kind: ErrorKind, error: Box<dyn core_error::Error + Send + Sync>) -> Error {
526 Error::new_custom(Box::new(Custom { kind, error }))
527 }
528
529 /// Creates a new I/O error from a known kind of error as well as a constant
530 /// message.
531 ///
532 /// This function does not allocate.
533 ///
534 /// You should not use this directly, and instead use the `const_io_error!`
535 /// macro: `io::const_io_error!(ErrorKind::Something, "some_message")`.
536 ///
537 /// This function should maybe change to `from_static_message<const MSG: &'static
538 /// str>(kind: ErrorKind)` in the future, when const generics allow that.
539 #[inline]
540 pub(crate) const fn from_static_message(msg: &'static SimpleMessage) -> Error {
541 Error::new_simple_message(msg)
542 }
543
544 #[inline]
545 /// Creates a new instance of an [`Error`] from a particular OS error code.
546 ///
547 /// # Examples
548 ///
549 /// On Linux:
550 ///
551 /// ```
552 /// # if cfg!(target_os = "linux") {
553 /// use std::io;
554 ///
555 /// let error = io::Error::from_raw_os_error(22);
556 /// assert_eq!(error.kind(), io::ErrorKind::InvalidInput);
557 /// # }
558 /// ```
559 ///
560 /// On Windows:
561 ///
562 /// ```
563 /// # if cfg!(windows) {
564 /// use std::io;
565 ///
566 /// let error = io::Error::from_raw_os_error(10022);
567 /// assert_eq!(error.kind(), io::ErrorKind::InvalidInput);
568 /// # }
569 /// ```
570 pub fn from_raw_os_error(code: i64) -> Error {
571 Error::new_os(code)
572 }
573
574 /// Returns the OS error that this error represents (if any).
575 ///
576 /// If this [`Error`] was constructed via [`last_os_error`] or
577 /// [`from_raw_os_error`], then this function will return [`Some`], otherwise
578 /// it will return [`None`].
579 ///
580 /// [`last_os_error`]: Error::last_os_error
581 /// [`from_raw_os_error`]: Error::from_raw_os_error
582 ///
583 /// # Examples
584 ///
585 /// ```
586 /// use std::io::{Error, ErrorKind};
587 ///
588 /// fn print_os_error(err: &Error) {
589 /// if let Some(raw_os_err) = err.raw_os_error() {
590 /// println!("raw OS error: {raw_os_err:?}");
591 /// } else {
592 /// println!("Not an OS error");
593 /// }
594 /// }
595 ///
596 /// fn main() {
597 /// // Will print "raw OS error: ...".
598 /// print_os_error(&Error::last_os_error());
599 /// // Will print "Not an OS error".
600 /// print_os_error(&Error::new(ErrorKind::Other, "oh no!"));
601 /// }
602 /// ```
603 #[inline]
604 pub fn raw_os_error(&self) -> Option<i64> {
605 match self {
606 Error::Os(i) => Some(*i),
607 Error::Custom(..) => None,
608 Error::Simple(..) => None,
609 Error::SimpleMessage(..) => None,
610 }
611 }
612 /// Returns a reference to the inner error wrapped by this error (if any).
613 ///
614 /// If this [`Error`] was constructed via [`new`] then this function will
615 /// return [`Some`], otherwise it will return [`None`].
616 ///
617 /// [`new`]: Error::new
618 ///
619 /// # Examples
620 ///
621 /// ```
622 /// use std::io::{Error, ErrorKind};
623 ///
624 /// fn print_error(err: &Error) {
625 /// if let Some(inner_err) = err.get_ref() {
626 /// println!("Inner error: {inner_err:?}");
627 /// } else {
628 /// println!("No inner error");
629 /// }
630 /// }
631 ///
632 /// fn main() {
633 /// // Will print "No inner error".
634 /// print_error(&Error::last_os_error());
635 /// // Will print "Inner error: ...".
636 /// print_error(&Error::new(ErrorKind::Other, "oh no!"));
637 /// }
638 /// ```
639 #[inline]
640 pub fn get_ref(&self) -> Option<&(dyn core_error::Error + Send + Sync + 'static)> {
641 match self {
642 Error::Os(..) => None,
643 Error::Simple(..) => None,
644 Error::SimpleMessage(..) => None,
645 Error::Custom(c) => Some(&*c.error),
646 }
647 }
648
649 /// Returns a mutable reference to the inner error wrapped by this error
650 /// (if any).
651 ///
652 /// If this [`Error`] was constructed via [`new`] then this function will
653 /// return [`Some`], otherwise it will return [`None`].
654 ///
655 /// [`new`]: Error::new
656 ///
657 /// # Examples
658 ///
659 /// ```
660 /// use std::io::{Error, ErrorKind};
661 /// use std::{error, fmt};
662 /// use std::fmt::Display;
663 ///
664 /// #[derive(Debug)]
665 /// struct MyError {
666 /// v: String,
667 /// }
668 ///
669 /// impl MyError {
670 /// fn new() -> MyError {
671 /// MyError {
672 /// v: "oh no!".to_string()
673 /// }
674 /// }
675 ///
676 /// fn change_message(&mut self, new_message: &str) {
677 /// self.v = new_message.to_string();
678 /// }
679 /// }
680 ///
681 /// impl error::Error for MyError {}
682 ///
683 /// impl Display for MyError {
684 /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
685 /// write!(f, "MyError: {}", self.v)
686 /// }
687 /// }
688 ///
689 /// fn change_error(mut err: Error) -> Error {
690 /// if let Some(inner_err) = err.get_mut() {
691 /// inner_err.downcast_mut::<MyError>().unwrap().change_message("I've been changed!");
692 /// }
693 /// err
694 /// }
695 ///
696 /// fn print_error(err: &Error) {
697 /// if let Some(inner_err) = err.get_ref() {
698 /// println!("Inner error: {inner_err}");
699 /// } else {
700 /// println!("No inner error");
701 /// }
702 /// }
703 ///
704 /// fn main() {
705 /// // Will print "No inner error".
706 /// print_error(&change_error(Error::last_os_error()));
707 /// // Will print "Inner error: ...".
708 /// print_error(&change_error(Error::new(ErrorKind::Other, MyError::new())));
709 /// }
710 /// ```
711 #[must_use]
712 #[inline]
713 pub fn get_mut(&mut self) -> Option<&mut (dyn core_error::Error + Send + Sync + 'static)> {
714 match self {
715 Error::Os(..) => None,
716 Error::Simple(..) => None,
717 Error::SimpleMessage(..) => None,
718 Error::Custom(c) => Some(&mut *c.error),
719 }
720 }
721 /// Consumes the `Error`, returning its inner error (if any).
722 ///
723 /// If this [`Error`] was constructed via [`new`] then this function will
724 /// return [`Some`], otherwise it will return [`None`].
725 ///
726 /// [`new`]: Error::new
727 ///
728 /// # Examples
729 ///
730 /// ```
731 /// use std::io::{Error, ErrorKind};
732 ///
733 /// fn print_error(err: Error) {
734 /// if let Some(inner_err) = err.into_inner() {
735 /// println!("Inner error: {inner_err}");
736 /// } else {
737 /// println!("No inner error");
738 /// }
739 /// }
740 ///
741 /// fn main() {
742 /// // Will print "No inner error".
743 /// print_error(Error::last_os_error());
744 /// // Will print "Inner error: ...".
745 /// print_error(Error::new(ErrorKind::Other, "oh no!"));
746 /// }
747 /// ```
748 #[must_use = "`self` will be dropped if the result is not used"]
749 #[inline]
750 pub fn into_inner(self) -> Option<Box<dyn core_error::Error + Send + Sync>> {
751 match self {
752 Error::Os(..) => None,
753 Error::Simple(..) => None,
754 Error::SimpleMessage(..) => None,
755 Error::Custom(c) => Some(c.error),
756 }
757 }
758 /// Attempt to downcast the custom boxed error to `E`.
759 ///
760 /// If this [`Error`] contains a custom boxed error,
761 /// then it would attempt downcasting on the boxed error,
762 /// otherwise it will return [`Err`].
763 ///
764 /// If the custom boxed error has the same type as `E`, it will return [`Ok`],
765 /// otherwise it will also return [`Err`].
766 ///
767 /// This method is meant to be a convenience routine for calling
768 /// `Box<dyn Error + Sync + Send>::downcast` on the custom boxed error, returned by
769 /// [`Error::into_inner`].
770 ///
771 ///
772 /// # Examples
773 ///
774 /// ```
775 /// use std::fmt;
776 /// use std::io;
777 /// use std::error::Error;
778 ///
779 /// #[derive(Debug)]
780 /// enum E {
781 /// Io(io::Error),
782 /// SomeOtherVariant,
783 /// }
784 ///
785 /// impl fmt::Display for E {
786 /// // ...
787 /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
788 /// # todo!()
789 /// # }
790 /// }
791 /// impl Error for E {}
792 ///
793 /// impl From<io::Error> for E {
794 /// fn from(err: io::Error) -> E {
795 /// err.downcast::<E>()
796 /// .unwrap_or_else(E::Io)
797 /// }
798 /// }
799 ///
800 /// impl From<E> for io::Error {
801 /// fn from(err: E) -> io::Error {
802 /// match err {
803 /// E::Io(io_error) => io_error,
804 /// e => io::Error::new(io::ErrorKind::Other, e),
805 /// }
806 /// }
807 /// }
808 ///
809 /// # fn main() {
810 /// let e = E::SomeOtherVariant;
811 /// // Convert it to an io::Error
812 /// let io_error = io::Error::from(e);
813 /// // Cast it back to the original variant
814 /// let e = E::from(io_error);
815 /// assert!(matches!(e, E::SomeOtherVariant));
816 ///
817 /// let io_error = io::Error::from(io::ErrorKind::AlreadyExists);
818 /// // Convert it to E
819 /// let e = E::from(io_error);
820 /// // Cast it back to the original variant
821 /// let io_error = io::Error::from(e);
822 /// assert_eq!(io_error.kind(), io::ErrorKind::AlreadyExists);
823 /// assert!(io_error.get_ref().is_none());
824 /// assert!(io_error.raw_os_error().is_none());
825 /// # }
826 /// ```
827 #[cfg(not(feature = "rust_before_181"))]
828 pub fn downcast<E>(self) -> result::Result<E, Self>
829 where
830 E: core_error::Error + Send + Sync + 'static,
831 {
832 match self {
833 Error::Custom(b) if b.error.is::<E>() => {
834 let res = b.error.downcast::<E>();
835 Ok(*res.unwrap())
836 }
837 err => Err(err),
838 }
839 }
840
841 /// Returns the corresponding [`ErrorKind`] for this error.
842 ///
843 /// This may be a value set by Rust code constructing custom `io::Error`s,
844 /// or if this `io::Error` was sourced from the operating system,
845 /// it will be a value inferred from the system's error encoding.
846 /// See [`last_os_error`] for more details.
847 ///
848 /// [`last_os_error`]: Error::last_os_error
849 ///
850 /// # Examples
851 ///
852 /// ```
853 /// use std::io::{Error, ErrorKind};
854 ///
855 /// fn print_error(err: Error) {
856 /// println!("{:?}", err.kind());
857 /// }
858 ///
859 /// fn main() {
860 /// // As no error has (visibly) occurred, this may print anything!
861 /// // It likely prints a placeholder for unidentified (non-)errors.
862 /// print_error(Error::last_os_error());
863 /// // Will print "AddrInUse".
864 /// print_error(Error::new(ErrorKind::AddrInUse, "oh no!"));
865 /// }
866 /// ```
867 #[must_use]
868 #[inline]
869 pub fn kind(&self) -> ErrorKind {
870 match self {
871 Error::Os(..) => ErrorKind::Other,
872 Error::Custom(c) => c.kind,
873 Error::Simple(kind) => *kind,
874 Error::SimpleMessage(m) => m.kind,
875 }
876 }
877
878 #[inline]
879 pub(crate) fn is_interrupted(&self) -> bool {
880 match self {
881 Error::Os(..) => false,
882 Error::Custom(c) => c.kind == ErrorKind::Interrupted,
883 Error::Simple(kind) => *kind == ErrorKind::Interrupted,
884 Error::SimpleMessage(m) => m.kind == ErrorKind::Interrupted,
885 }
886 }
887}
888
889impl fmt::Display for Error {
890 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
891 match self {
892 Error::Os(code) => {
893 write!(fmt, "os error {code}")
894 }
895 Error::Custom(ref c) => c.error.fmt(fmt),
896 Error::Simple(kind) => write!(fmt, "{}", kind.as_str()),
897 Error::SimpleMessage(msg) => msg.message.fmt(fmt),
898 }
899 }
900}
901
902impl core_error::Error for Error {
903 #[allow(deprecated, deprecated_in_future)]
904 fn description(&self) -> &str {
905 match self {
906 Error::Os(..) | Error::Simple(..) => self.kind().as_str(),
907 Error::SimpleMessage(msg) => msg.message,
908 Error::Custom(c) => c.error.description(),
909 }
910 }
911
912 #[allow(deprecated)]
913 fn cause(&self) -> Option<&dyn core_error::Error> {
914 match self {
915 Error::Os(..) => None,
916 Error::Simple(..) => None,
917 Error::SimpleMessage(..) => None,
918 Error::Custom(c) => c.error.cause(),
919 }
920 }
921
922 fn source(&self) -> Option<&(dyn core_error::Error + 'static)> {
923 match self {
924 Error::Os(..) => None,
925 Error::Simple(..) => None,
926 Error::SimpleMessage(..) => None,
927 Error::Custom(c) => c.error.source(),
928 }
929 }
930}
931
932fn _assert_error_is_sync_send() {
933 fn _is_sync_send<T: Sync + Send>() {}
934 _is_sync_send::<Error>();
935}