diff --git a/library/core/src/io/error.rs b/library/core/src/io/error.rs new file mode 100644 index 0000000000000..fe12de2952f0a --- /dev/null +++ b/library/core/src/io/error.rs @@ -0,0 +1,372 @@ +#![unstable(feature = "core_io", issue = "154046")] + +use crate::fmt; + +/// A list specifying general categories of I/O error. +/// +/// This list is intended to grow over time and it is not recommended to +/// exhaustively match against it. +/// +/// # Handling errors and matching on `ErrorKind` +/// +/// In application code, use `match` for the `ErrorKind` values you are +/// expecting; use `_` to match "all other errors". +/// +/// In comprehensive and thorough tests that want to verify that a test doesn't +/// return any known incorrect error kind, you may want to cut-and-paste the +/// current full list of errors from here into your test code, and then match +/// `_` as the correct case. This seems counterintuitive, but it will make your +/// tests more robust. In particular, if you want to verify that your code does +/// produce an unrecognized error kind, the robust solution is to check for all +/// the recognized error kinds and fail in those cases. +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "io_errorkind")] +#[allow(deprecated)] +#[non_exhaustive] +pub enum ErrorKind { + /// An entity was not found, often a file. + #[stable(feature = "rust1", since = "1.0.0")] + NotFound, + /// The operation lacked the necessary privileges to complete. + #[stable(feature = "rust1", since = "1.0.0")] + PermissionDenied, + /// The connection was refused by the remote server. + #[stable(feature = "rust1", since = "1.0.0")] + ConnectionRefused, + /// The connection was reset by the remote server. + #[stable(feature = "rust1", since = "1.0.0")] + ConnectionReset, + /// The remote host is not reachable. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + HostUnreachable, + /// The network containing the remote host is not reachable. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + NetworkUnreachable, + /// The connection was aborted (terminated) by the remote server. + #[stable(feature = "rust1", since = "1.0.0")] + ConnectionAborted, + /// The network operation failed because it was not connected yet. + #[stable(feature = "rust1", since = "1.0.0")] + NotConnected, + /// A socket address could not be bound because the address is already in + /// use elsewhere. + #[stable(feature = "rust1", since = "1.0.0")] + AddrInUse, + /// A nonexistent interface was requested or the requested address was not + /// local. + #[stable(feature = "rust1", since = "1.0.0")] + AddrNotAvailable, + /// The system's networking is down. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + NetworkDown, + /// The operation failed because a pipe was closed. + #[stable(feature = "rust1", since = "1.0.0")] + BrokenPipe, + /// An entity already exists, often a file. + #[stable(feature = "rust1", since = "1.0.0")] + AlreadyExists, + /// The operation needs to block to complete, but the blocking operation was + /// requested to not occur. + #[stable(feature = "rust1", since = "1.0.0")] + WouldBlock, + /// A filesystem object is, unexpectedly, not a directory. + /// + /// For example, a filesystem path was specified where one of the intermediate directory + /// components was, in fact, a plain file. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + NotADirectory, + /// The filesystem object is, unexpectedly, a directory. + /// + /// A directory was specified when a non-directory was expected. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + IsADirectory, + /// A non-empty directory was specified where an empty directory was expected. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + DirectoryNotEmpty, + /// The filesystem or storage medium is read-only, but a write operation was attempted. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + ReadOnlyFilesystem, + /// Loop in the filesystem or IO subsystem; often, too many levels of symbolic links. + /// + /// There was a loop (or excessively long chain) resolving a filesystem object + /// or file IO object. + /// + /// On Unix this is usually the result of a symbolic link loop; or, of exceeding the + /// system-specific limit on the depth of symlink traversal. + #[unstable(feature = "io_error_more", issue = "86442")] + FilesystemLoop, + /// Stale network file handle. + /// + /// With some network filesystems, notably NFS, an open file (or directory) can be invalidated + /// by problems with the network or server. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + StaleNetworkFileHandle, + /// A parameter was incorrect. + #[stable(feature = "rust1", since = "1.0.0")] + InvalidInput, + /// Data not valid for the operation were encountered. + /// + /// Unlike [`InvalidInput`], this typically means that the operation + /// parameters were valid, however the error was caused by malformed + /// input data. + /// + /// For example, a function that reads a file into a string will error with + /// `InvalidData` if the file's contents are not valid UTF-8. + /// + /// [`InvalidInput`]: ErrorKind::InvalidInput + #[stable(feature = "io_invalid_data", since = "1.2.0")] + InvalidData, + /// The I/O operation's timeout expired, causing it to be canceled. + #[stable(feature = "rust1", since = "1.0.0")] + TimedOut, + /// An error returned when an operation could not be completed because a + /// call to an underlying writer returned [`Ok(0)`]. + /// + /// This typically means that an operation could only succeed if it wrote a + /// particular number of bytes but only a smaller number of bytes could be + /// written. + /// + /// [`Ok(0)`]: Ok + #[stable(feature = "rust1", since = "1.0.0")] + WriteZero, + /// The underlying storage (typically, a filesystem) is full. + /// + /// This does not include out of quota errors. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + StorageFull, + /// Seek on unseekable file. + /// + /// Seeking was attempted on an open file handle which is not suitable for seeking - for + /// example, on Unix, a named pipe opened with `File::open`. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + NotSeekable, + /// Filesystem quota or some other kind of quota was exceeded. + #[stable(feature = "io_error_quota_exceeded", since = "1.85.0")] + QuotaExceeded, + /// File larger than allowed or supported. + /// + /// This might arise from a hard limit of the underlying filesystem or file access API, or from + /// an administratively imposed resource limitation. Simple disk full, and out of quota, have + /// their own errors. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + FileTooLarge, + /// Resource is busy. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + ResourceBusy, + /// Executable file is busy. + /// + /// An attempt was made to write to a file which is also in use as a running program. (Not all + /// operating systems detect this situation.) + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + ExecutableFileBusy, + /// Deadlock (avoided). + /// + /// A file locking operation would result in deadlock. This situation is typically detected, if + /// at all, on a best-effort basis. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + Deadlock, + /// Cross-device or cross-filesystem (hard) link or rename. + #[stable(feature = "io_error_crosses_devices", since = "1.85.0")] + CrossesDevices, + /// Too many (hard) links to the same filesystem object. + /// + /// The filesystem does not support making so many hardlinks to the same file. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + TooManyLinks, + /// A filename was invalid. + /// + /// This error can also occur if a length limit for a name was exceeded. + #[stable(feature = "io_error_invalid_filename", since = "1.87.0")] + InvalidFilename, + /// Program argument list too long. + /// + /// When trying to run an external program, a system or process limit on the size of the + /// arguments would have been exceeded. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + ArgumentListTooLong, + /// This operation was interrupted. + /// + /// Interrupted operations can typically be retried. + #[stable(feature = "rust1", since = "1.0.0")] + Interrupted, + + /// This operation is unsupported on this platform. + /// + /// This means that the operation can never succeed. + #[stable(feature = "unsupported_error", since = "1.53.0")] + Unsupported, + + // ErrorKinds which are primarily categorisations for OS error + // codes should be added above. + // + /// An error returned when an operation could not be completed because an + /// "end of file" was reached prematurely. + /// + /// This typically means that an operation could only succeed if it read a + /// particular number of bytes but only a smaller number of bytes could be + /// read. + #[stable(feature = "read_exact", since = "1.6.0")] + UnexpectedEof, + + /// An operation could not be completed, because it failed + /// to allocate enough memory. + #[stable(feature = "out_of_memory_error", since = "1.54.0")] + OutOfMemory, + + /// The operation was partially successful and needs to be checked + /// later on due to not blocking. + #[unstable(feature = "io_error_inprogress", issue = "130840")] + InProgress, + + // "Unusual" error kinds which do not correspond simply to (sets + // of) OS error codes, should be added just above this comment. + // `Other` and `Uncategorized` should remain at the end: + // + /// A custom error that does not fall under any other I/O error kind. + /// + /// This can be used to construct your own errors that do not match any + /// [`ErrorKind`]. + /// + /// This [`ErrorKind`] is not used by the standard library. + /// + /// Errors from the standard library that do not fall under any of the I/O + /// error kinds cannot be `match`ed on, and will only match a wildcard (`_`) pattern. + /// New [`ErrorKind`]s might be added in the future for some of those. + #[stable(feature = "rust1", since = "1.0.0")] + Other, + + /// Any I/O error from the standard library that's not part of this list. + /// + /// Errors that are `Uncategorized` now may move to a different or a new + /// [`ErrorKind`] variant in the future. It is not recommended to match + /// an error against `Uncategorized`; use a wildcard match (`_`) instead. + #[unstable(feature = "io_error_uncategorized", issue = "none")] + #[doc(hidden)] + Uncategorized, +} + +impl ErrorKind { + pub(crate) const fn as_str(&self) -> &'static str { + use ErrorKind::*; + match *self { + // tidy-alphabetical-start + AddrInUse => "address in use", + AddrNotAvailable => "address not available", + AlreadyExists => "entity already exists", + ArgumentListTooLong => "argument list too long", + BrokenPipe => "broken pipe", + ConnectionAborted => "connection aborted", + ConnectionRefused => "connection refused", + ConnectionReset => "connection reset", + CrossesDevices => "cross-device link or rename", + Deadlock => "deadlock", + DirectoryNotEmpty => "directory not empty", + ExecutableFileBusy => "executable file busy", + FileTooLarge => "file too large", + FilesystemLoop => "filesystem loop or indirection limit (e.g. symlink loop)", + HostUnreachable => "host unreachable", + InProgress => "in progress", + Interrupted => "operation interrupted", + InvalidData => "invalid data", + InvalidFilename => "invalid filename", + InvalidInput => "invalid input parameter", + IsADirectory => "is a directory", + NetworkDown => "network down", + NetworkUnreachable => "network unreachable", + NotADirectory => "not a directory", + NotConnected => "not connected", + NotFound => "entity not found", + NotSeekable => "seek on unseekable file", + Other => "other error", + OutOfMemory => "out of memory", + PermissionDenied => "permission denied", + QuotaExceeded => "quota exceeded", + ReadOnlyFilesystem => "read-only filesystem or storage medium", + ResourceBusy => "resource busy", + StaleNetworkFileHandle => "stale network file handle", + StorageFull => "no storage space", + TimedOut => "timed out", + TooManyLinks => "too many links", + Uncategorized => "uncategorized error", + UnexpectedEof => "unexpected end of file", + Unsupported => "unsupported", + WouldBlock => "operation would block", + WriteZero => "write zero", + // tidy-alphabetical-end + } + } + + // This compiles to the same code as the check+transmute, but doesn't require + // unsafe, or to hard-code max ErrorKind or its size in a way the compiler + // couldn't verify. + #[inline] + #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] + #[doc(hidden)] + pub const fn from_prim(ek: u32) -> Option { + macro_rules! from_prim { + ($prim:expr => $Enum:ident { $($Variant:ident),* $(,)? }) => {{ + // Force a compile error if the list gets out of date. + const _: fn(e: $Enum) = |e: $Enum| match e { + $($Enum::$Variant => (),)* + }; + match $prim { + $(v if v == ($Enum::$Variant as _) => Some($Enum::$Variant),)* + _ => None, + } + }} + } + from_prim!(ek => ErrorKind { + NotFound, + PermissionDenied, + ConnectionRefused, + ConnectionReset, + HostUnreachable, + NetworkUnreachable, + ConnectionAborted, + NotConnected, + AddrInUse, + AddrNotAvailable, + NetworkDown, + BrokenPipe, + AlreadyExists, + WouldBlock, + NotADirectory, + IsADirectory, + DirectoryNotEmpty, + ReadOnlyFilesystem, + FilesystemLoop, + StaleNetworkFileHandle, + InvalidInput, + InvalidData, + TimedOut, + WriteZero, + StorageFull, + NotSeekable, + QuotaExceeded, + FileTooLarge, + ResourceBusy, + ExecutableFileBusy, + Deadlock, + CrossesDevices, + TooManyLinks, + InvalidFilename, + ArgumentListTooLong, + Interrupted, + Other, + UnexpectedEof, + Unsupported, + OutOfMemory, + InProgress, + Uncategorized, + }) + } +} + +#[stable(feature = "io_errorkind_display", since = "1.60.0")] +impl fmt::Display for ErrorKind { + /// Shows a human-readable description of the `ErrorKind`. + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.write_str(self.as_str()) + } +} diff --git a/library/core/src/io/mod.rs b/library/core/src/io/mod.rs index 2f20180cdc9a2..c34421523b643 100644 --- a/library/core/src/io/mod.rs +++ b/library/core/src/io/mod.rs @@ -1,6 +1,9 @@ //! Traits, helpers, and type definitions for core I/O functionality. mod borrowed_buf; +mod error; #[unstable(feature = "core_io_borrowed_buf", issue = "117693")] pub use self::borrowed_buf::{BorrowedBuf, BorrowedCursor}; +#[unstable(feature = "core_io", issue = "154046")] +pub use self::error::ErrorKind; diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 3b72752cee9a1..bdc1c48f70dfe 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -305,7 +305,7 @@ pub mod bstr; pub mod cell; pub mod char; pub mod ffi; -#[unstable(feature = "core_io_borrowed_buf", issue = "117693")] +#[unstable(feature = "core_io", issue = "154046")] pub mod io; pub mod iter; pub mod net; diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index ed18f5a34fd28..c4292c2a421b1 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -36,6 +36,7 @@ #![feature(const_unsigned_bigint_helpers)] #![feature(core_intrinsics)] #![feature(core_intrinsics_fallbacks)] +#![feature(core_io)] #![feature(core_io_borrowed_buf)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index e6c6f7d766c02..6f565bb37c53b 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -1,6 +1,9 @@ #[cfg(test)] mod tests; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::io::ErrorKind; + // On 64-bit platforms, `io::Error` may use a bit-packed representation to // reduce size. However, this representation assumes that error codes are // always 32-bit wide. @@ -206,323 +209,6 @@ struct Custom { error: Box, } -/// A list specifying general categories of I/O error. -/// -/// This list is intended to grow over time and it is not recommended to -/// exhaustively match against it. -/// -/// It is used with the [`io::Error`] type. -/// -/// [`io::Error`]: Error -/// -/// # Handling errors and matching on `ErrorKind` -/// -/// In application code, use `match` for the `ErrorKind` values you are -/// expecting; use `_` to match "all other errors". -/// -/// In comprehensive and thorough tests that want to verify that a test doesn't -/// return any known incorrect error kind, you may want to cut-and-paste the -/// current full list of errors from here into your test code, and then match -/// `_` as the correct case. This seems counterintuitive, but it will make your -/// tests more robust. In particular, if you want to verify that your code does -/// produce an unrecognized error kind, the robust solution is to check for all -/// the recognized error kinds and fail in those cases. -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -#[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "io_errorkind")] -#[allow(deprecated)] -#[non_exhaustive] -pub enum ErrorKind { - /// An entity was not found, often a file. - #[stable(feature = "rust1", since = "1.0.0")] - NotFound, - /// The operation lacked the necessary privileges to complete. - #[stable(feature = "rust1", since = "1.0.0")] - PermissionDenied, - /// The connection was refused by the remote server. - #[stable(feature = "rust1", since = "1.0.0")] - ConnectionRefused, - /// The connection was reset by the remote server. - #[stable(feature = "rust1", since = "1.0.0")] - ConnectionReset, - /// The remote host is not reachable. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - HostUnreachable, - /// The network containing the remote host is not reachable. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - NetworkUnreachable, - /// The connection was aborted (terminated) by the remote server. - #[stable(feature = "rust1", since = "1.0.0")] - ConnectionAborted, - /// The network operation failed because it was not connected yet. - #[stable(feature = "rust1", since = "1.0.0")] - NotConnected, - /// A socket address could not be bound because the address is already in - /// use elsewhere. - #[stable(feature = "rust1", since = "1.0.0")] - AddrInUse, - /// A nonexistent interface was requested or the requested address was not - /// local. - #[stable(feature = "rust1", since = "1.0.0")] - AddrNotAvailable, - /// The system's networking is down. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - NetworkDown, - /// The operation failed because a pipe was closed. - #[stable(feature = "rust1", since = "1.0.0")] - BrokenPipe, - /// An entity already exists, often a file. - #[stable(feature = "rust1", since = "1.0.0")] - AlreadyExists, - /// The operation needs to block to complete, but the blocking operation was - /// requested to not occur. - #[stable(feature = "rust1", since = "1.0.0")] - WouldBlock, - /// A filesystem object is, unexpectedly, not a directory. - /// - /// For example, a filesystem path was specified where one of the intermediate directory - /// components was, in fact, a plain file. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - NotADirectory, - /// The filesystem object is, unexpectedly, a directory. - /// - /// A directory was specified when a non-directory was expected. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - IsADirectory, - /// A non-empty directory was specified where an empty directory was expected. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - DirectoryNotEmpty, - /// The filesystem or storage medium is read-only, but a write operation was attempted. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - ReadOnlyFilesystem, - /// Loop in the filesystem or IO subsystem; often, too many levels of symbolic links. - /// - /// There was a loop (or excessively long chain) resolving a filesystem object - /// or file IO object. - /// - /// On Unix this is usually the result of a symbolic link loop; or, of exceeding the - /// system-specific limit on the depth of symlink traversal. - #[unstable(feature = "io_error_more", issue = "86442")] - FilesystemLoop, - /// Stale network file handle. - /// - /// With some network filesystems, notably NFS, an open file (or directory) can be invalidated - /// by problems with the network or server. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - StaleNetworkFileHandle, - /// A parameter was incorrect. - #[stable(feature = "rust1", since = "1.0.0")] - InvalidInput, - /// Data not valid for the operation were encountered. - /// - /// Unlike [`InvalidInput`], this typically means that the operation - /// parameters were valid, however the error was caused by malformed - /// input data. - /// - /// For example, a function that reads a file into a string will error with - /// `InvalidData` if the file's contents are not valid UTF-8. - /// - /// [`InvalidInput`]: ErrorKind::InvalidInput - #[stable(feature = "io_invalid_data", since = "1.2.0")] - InvalidData, - /// The I/O operation's timeout expired, causing it to be canceled. - #[stable(feature = "rust1", since = "1.0.0")] - TimedOut, - /// An error returned when an operation could not be completed because a - /// call to [`write`] returned [`Ok(0)`]. - /// - /// This typically means that an operation could only succeed if it wrote a - /// particular number of bytes but only a smaller number of bytes could be - /// written. - /// - /// [`write`]: crate::io::Write::write - /// [`Ok(0)`]: Ok - #[stable(feature = "rust1", since = "1.0.0")] - WriteZero, - /// The underlying storage (typically, a filesystem) is full. - /// - /// This does not include out of quota errors. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - StorageFull, - /// Seek on unseekable file. - /// - /// Seeking was attempted on an open file handle which is not suitable for seeking - for - /// example, on Unix, a named pipe opened with `File::open`. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - NotSeekable, - /// Filesystem quota or some other kind of quota was exceeded. - #[stable(feature = "io_error_quota_exceeded", since = "1.85.0")] - QuotaExceeded, - /// File larger than allowed or supported. - /// - /// This might arise from a hard limit of the underlying filesystem or file access API, or from - /// an administratively imposed resource limitation. Simple disk full, and out of quota, have - /// their own errors. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - FileTooLarge, - /// Resource is busy. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - ResourceBusy, - /// Executable file is busy. - /// - /// An attempt was made to write to a file which is also in use as a running program. (Not all - /// operating systems detect this situation.) - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - ExecutableFileBusy, - /// Deadlock (avoided). - /// - /// A file locking operation would result in deadlock. This situation is typically detected, if - /// at all, on a best-effort basis. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - Deadlock, - /// Cross-device or cross-filesystem (hard) link or rename. - #[stable(feature = "io_error_crosses_devices", since = "1.85.0")] - CrossesDevices, - /// Too many (hard) links to the same filesystem object. - /// - /// The filesystem does not support making so many hardlinks to the same file. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - TooManyLinks, - /// A filename was invalid. - /// - /// This error can also occur if a length limit for a name was exceeded. - #[stable(feature = "io_error_invalid_filename", since = "1.87.0")] - InvalidFilename, - /// Program argument list too long. - /// - /// When trying to run an external program, a system or process limit on the size of the - /// arguments would have been exceeded. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - ArgumentListTooLong, - /// This operation was interrupted. - /// - /// Interrupted operations can typically be retried. - #[stable(feature = "rust1", since = "1.0.0")] - Interrupted, - - /// This operation is unsupported on this platform. - /// - /// This means that the operation can never succeed. - #[stable(feature = "unsupported_error", since = "1.53.0")] - Unsupported, - - // ErrorKinds which are primarily categorisations for OS error - // codes should be added above. - // - /// An error returned when an operation could not be completed because an - /// "end of file" was reached prematurely. - /// - /// This typically means that an operation could only succeed if it read a - /// particular number of bytes but only a smaller number of bytes could be - /// read. - #[stable(feature = "read_exact", since = "1.6.0")] - UnexpectedEof, - - /// An operation could not be completed, because it failed - /// to allocate enough memory. - #[stable(feature = "out_of_memory_error", since = "1.54.0")] - OutOfMemory, - - /// The operation was partially successful and needs to be checked - /// later on due to not blocking. - #[unstable(feature = "io_error_inprogress", issue = "130840")] - InProgress, - - // "Unusual" error kinds which do not correspond simply to (sets - // of) OS error codes, should be added just above this comment. - // `Other` and `Uncategorized` should remain at the end: - // - /// A custom error that does not fall under any other I/O error kind. - /// - /// This can be used to construct your own [`Error`]s that do not match any - /// [`ErrorKind`]. - /// - /// This [`ErrorKind`] is not used by the standard library. - /// - /// Errors from the standard library that do not fall under any of the I/O - /// error kinds cannot be `match`ed on, and will only match a wildcard (`_`) pattern. - /// New [`ErrorKind`]s might be added in the future for some of those. - #[stable(feature = "rust1", since = "1.0.0")] - Other, - - /// Any I/O error from the standard library that's not part of this list. - /// - /// Errors that are `Uncategorized` now may move to a different or a new - /// [`ErrorKind`] variant in the future. It is not recommended to match - /// an error against `Uncategorized`; use a wildcard match (`_`) instead. - #[unstable(feature = "io_error_uncategorized", issue = "none")] - #[doc(hidden)] - Uncategorized, -} - -impl ErrorKind { - pub(crate) fn as_str(&self) -> &'static str { - use ErrorKind::*; - match *self { - // tidy-alphabetical-start - AddrInUse => "address in use", - AddrNotAvailable => "address not available", - AlreadyExists => "entity already exists", - ArgumentListTooLong => "argument list too long", - BrokenPipe => "broken pipe", - ConnectionAborted => "connection aborted", - ConnectionRefused => "connection refused", - ConnectionReset => "connection reset", - CrossesDevices => "cross-device link or rename", - Deadlock => "deadlock", - DirectoryNotEmpty => "directory not empty", - ExecutableFileBusy => "executable file busy", - FileTooLarge => "file too large", - FilesystemLoop => "filesystem loop or indirection limit (e.g. symlink loop)", - HostUnreachable => "host unreachable", - InProgress => "in progress", - Interrupted => "operation interrupted", - InvalidData => "invalid data", - InvalidFilename => "invalid filename", - InvalidInput => "invalid input parameter", - IsADirectory => "is a directory", - NetworkDown => "network down", - NetworkUnreachable => "network unreachable", - NotADirectory => "not a directory", - NotConnected => "not connected", - NotFound => "entity not found", - NotSeekable => "seek on unseekable file", - Other => "other error", - OutOfMemory => "out of memory", - PermissionDenied => "permission denied", - QuotaExceeded => "quota exceeded", - ReadOnlyFilesystem => "read-only filesystem or storage medium", - ResourceBusy => "resource busy", - StaleNetworkFileHandle => "stale network file handle", - StorageFull => "no storage space", - TimedOut => "timed out", - TooManyLinks => "too many links", - Uncategorized => "uncategorized error", - UnexpectedEof => "unexpected end of file", - Unsupported => "unsupported", - WouldBlock => "operation would block", - WriteZero => "write zero", - // tidy-alphabetical-end - } - } -} - -#[stable(feature = "io_errorkind_display", since = "1.60.0")] -impl fmt::Display for ErrorKind { - /// Shows a human-readable description of the `ErrorKind`. - /// - /// This is similar to `impl Display for Error`, but doesn't require first converting to Error. - /// - /// # Examples - /// ``` - /// use std::io::ErrorKind; - /// assert_eq!("entity not found", ErrorKind::NotFound.to_string()); - /// ``` - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.write_str(self.as_str()) - } -} - /// Intended for use for errors not exposed to the user, where allocating onto /// the heap (for normal construction via Error::new) is too costly. #[stable(feature = "io_error_from_errorkind", since = "1.14.0")] @@ -1051,7 +737,7 @@ impl fmt::Display for Error { write!(fmt, "{detail} (os error {code})") } ErrorData::Custom(ref c) => c.error.fmt(fmt), - ErrorData::Simple(kind) => write!(fmt, "{}", kind.as_str()), + ErrorData::Simple(kind) => kind.fmt(fmt), ErrorData::SimpleMessage(msg) => msg.message.fmt(fmt), } } diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs index 7353816a8171b..7c237825459af 100644 --- a/library/std/src/io/error/repr_bitpacked.rs +++ b/library/std/src/io/error/repr_bitpacked.rs @@ -253,7 +253,7 @@ where } TAG_SIMPLE => { let kind_bits = (bits >> 32) as u32; - let kind = kind_from_prim(kind_bits).unwrap_or_else(|| { + let kind = ErrorKind::from_prim(kind_bits).unwrap_or_else(|| { debug_assert!(false, "Invalid io::error::Repr bits: `Repr({:#018x})`", bits); // This means the `ptr` passed in was not valid, which violates // the unsafe contract of `decode_repr`. @@ -283,69 +283,6 @@ where } } -// This compiles to the same code as the check+transmute, but doesn't require -// unsafe, or to hard-code max ErrorKind or its size in a way the compiler -// couldn't verify. -#[inline] -fn kind_from_prim(ek: u32) -> Option { - macro_rules! from_prim { - ($prim:expr => $Enum:ident { $($Variant:ident),* $(,)? }) => {{ - // Force a compile error if the list gets out of date. - const _: fn(e: $Enum) = |e: $Enum| match e { - $($Enum::$Variant => ()),* - }; - match $prim { - $(v if v == ($Enum::$Variant as _) => Some($Enum::$Variant),)* - _ => None, - } - }} - } - from_prim!(ek => ErrorKind { - NotFound, - PermissionDenied, - ConnectionRefused, - ConnectionReset, - HostUnreachable, - NetworkUnreachable, - ConnectionAborted, - NotConnected, - AddrInUse, - AddrNotAvailable, - NetworkDown, - BrokenPipe, - AlreadyExists, - WouldBlock, - NotADirectory, - IsADirectory, - DirectoryNotEmpty, - ReadOnlyFilesystem, - FilesystemLoop, - StaleNetworkFileHandle, - InvalidInput, - InvalidData, - TimedOut, - WriteZero, - StorageFull, - NotSeekable, - QuotaExceeded, - FileTooLarge, - ResourceBusy, - ExecutableFileBusy, - Deadlock, - CrossesDevices, - TooManyLinks, - InvalidFilename, - ArgumentListTooLong, - Interrupted, - Other, - UnexpectedEof, - Unsupported, - OutOfMemory, - InProgress, - Uncategorized, - }) -} - // Some static checking to alert us if a change breaks any of the assumptions // that our encoding relies on for correctness and soundness. (Some of these are // a bit overly thorough/cautious, admittedly) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index faac8d9e51fd2..807befec1ad11 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -321,7 +321,9 @@ #![feature(const_default)] #![feature(core_float_math)] #![feature(core_intrinsics)] +#![feature(core_io)] #![feature(core_io_borrowed_buf)] +#![feature(core_io_internals)] #![feature(cstr_display)] #![feature(drop_guard)] #![feature(duration_constants)] @@ -344,6 +346,9 @@ #![feature(hashmap_internals)] #![feature(hint_must_use)] #![feature(int_from_ascii)] +#![feature(io_error_inprogress)] +#![feature(io_error_more)] +#![feature(io_error_uncategorized)] #![feature(ip)] #![feature(iter_advance_by)] #![feature(iter_next_chunk)] diff --git a/library/std/src/sys/io/error/sgx.rs b/library/std/src/sys/io/error/sgx.rs index 8b3e08b0b661b..b7b4030422e12 100644 --- a/library/std/src/sys/io/error/sgx.rs +++ b/library/std/src/sys/io/error/sgx.rs @@ -60,6 +60,6 @@ pub fn error_string(errno: i32) -> String { } else if ((Error::UserRangeStart as _)..=(Error::UserRangeEnd as _)).contains(&errno) { format!("user-specified error {errno:08x}") } else { - decode_error_kind(errno).as_str().into() + format!("{}", decode_error_kind(errno)) } } diff --git a/tests/rustdoc-html/intra-doc/deprecated.rs b/tests/rustdoc-html/intra-doc/deprecated.rs index 6f8639593a2d4..1705fe8fc7abe 100644 --- a/tests/rustdoc-html/intra-doc/deprecated.rs +++ b/tests/rustdoc-html/intra-doc/deprecated.rs @@ -1,6 +1,6 @@ //@ has deprecated/struct.A.html '//a[@href="{{channel}}/core/ops/range/struct.Range.html#structfield.start"]' 'start' -//@ has deprecated/struct.B1.html '//a[@href="{{channel}}/std/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found' -//@ has deprecated/struct.B2.html '//a[@href="{{channel}}/std/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found' +//@ has deprecated/struct.B1.html '//a[@href="{{channel}}/core/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found' +//@ has deprecated/struct.B2.html '//a[@href="{{channel}}/core/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found' #[deprecated = "[start][std::ops::Range::start]"] pub struct A; diff --git a/tests/rustdoc-html/intra-doc/field.rs b/tests/rustdoc-html/intra-doc/field.rs index e98419618e23f..610eb1ec1bf65 100644 --- a/tests/rustdoc-html/intra-doc/field.rs +++ b/tests/rustdoc-html/intra-doc/field.rs @@ -1,9 +1,9 @@ //@ has field/index.html '//a[@href="{{channel}}/core/ops/range/struct.Range.html#structfield.start"]' 'start' -//@ has field/index.html '//a[@href="{{channel}}/std/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found' +//@ has field/index.html '//a[@href="{{channel}}/core/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found' //@ has field/index.html '//a[@href="struct.FieldAndMethod.html#structfield.x"]' 'x' //@ has field/index.html '//a[@href="enum.VariantAndMethod.html#variant.X"]' 'X' //! [start][std::ops::Range::start] -//! [not_found][std::io::ErrorKind::NotFound] +//! [not_found][core::io::ErrorKind::NotFound] //! [x][field@crate::FieldAndMethod::x] //! [X][variant@crate::VariantAndMethod::X] diff --git a/tests/ui/feature-gates/feature-gate-io_error_kind_in_core.rs b/tests/ui/feature-gates/feature-gate-io_error_kind_in_core.rs new file mode 100644 index 0000000000000..514e4e1277afa --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-io_error_kind_in_core.rs @@ -0,0 +1,12 @@ +// Ensure `ErrorKind` from `core` is gated behind `core_io` +//@ edition:2024 + +use std::io::ErrorKind as ErrorKindFromStd; + +use core::io::ErrorKind as ErrorKindFromCore; +//~^ ERROR use of unstable library feature `core_io` + +// Asserting both ErrorKinds are the same. +const _: [ErrorKindFromCore; 1] = [ErrorKindFromStd::Other]; + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-io_error_kind_in_core.stderr b/tests/ui/feature-gates/feature-gate-io_error_kind_in_core.stderr new file mode 100644 index 0000000000000..499b603761dce --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-io_error_kind_in_core.stderr @@ -0,0 +1,13 @@ +error[E0658]: use of unstable library feature `core_io` + --> $DIR/feature-gate-io_error_kind_in_core.rs:6:5 + | +LL | use core::io::ErrorKind as ErrorKindFromCore; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #154046 for more information + = help: add `#![feature(core_io)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`.