Skip to content

Commit 6acf3fc

Browse files
committed
Move std::io::ErrorKind to core::io::ErrorKind
* Contributing to #154046 * Generally useful for `no_std` interop since `std::io::Error` implements `From<ErrorKind>` * Low friction as `ErrorKind` is not platform dependent or otherwise dependent on `std`
1 parent 48cc71e commit 6acf3fc

File tree

6 files changed

+320
-321
lines changed

6 files changed

+320
-321
lines changed

library/core/src/io/error_kind.rs

Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
#![unstable(feature = "core_io_error_kind", issue = "154046")]
2+
3+
use crate::fmt;
4+
5+
/// A list specifying general categories of I/O error.
6+
///
7+
/// This list is intended to grow over time and it is not recommended to
8+
/// exhaustively match against it.
9+
///
10+
/// # Handling errors and matching on `ErrorKind`
11+
///
12+
/// In application code, use `match` for the `ErrorKind` values you are
13+
/// expecting; use `_` to match "all other errors".
14+
///
15+
/// In comprehensive and thorough tests that want to verify that a test doesn't
16+
/// return any known incorrect error kind, you may want to cut-and-paste the
17+
/// current full list of errors from here into your test code, and then match
18+
/// `_` as the correct case. This seems counterintuitive, but it will make your
19+
/// tests more robust. In particular, if you want to verify that your code does
20+
/// produce an unrecognized error kind, the robust solution is to check for all
21+
/// the recognized error kinds and fail in those cases.
22+
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
23+
#[stable(feature = "rust1", since = "1.0.0")]
24+
#[cfg_attr(not(test), rustc_diagnostic_item = "io_errorkind")]
25+
#[allow(deprecated)]
26+
#[non_exhaustive]
27+
pub enum ErrorKind {
28+
/// An entity was not found, often a file.
29+
#[stable(feature = "rust1", since = "1.0.0")]
30+
NotFound,
31+
/// The operation lacked the necessary privileges to complete.
32+
#[stable(feature = "rust1", since = "1.0.0")]
33+
PermissionDenied,
34+
/// The connection was refused by the remote server.
35+
#[stable(feature = "rust1", since = "1.0.0")]
36+
ConnectionRefused,
37+
/// The connection was reset by the remote server.
38+
#[stable(feature = "rust1", since = "1.0.0")]
39+
ConnectionReset,
40+
/// The remote host is not reachable.
41+
#[stable(feature = "io_error_a_bit_more", since = "1.83.0")]
42+
HostUnreachable,
43+
/// The network containing the remote host is not reachable.
44+
#[stable(feature = "io_error_a_bit_more", since = "1.83.0")]
45+
NetworkUnreachable,
46+
/// The connection was aborted (terminated) by the remote server.
47+
#[stable(feature = "rust1", since = "1.0.0")]
48+
ConnectionAborted,
49+
/// The network operation failed because it was not connected yet.
50+
#[stable(feature = "rust1", since = "1.0.0")]
51+
NotConnected,
52+
/// A socket address could not be bound because the address is already in
53+
/// use elsewhere.
54+
#[stable(feature = "rust1", since = "1.0.0")]
55+
AddrInUse,
56+
/// A nonexistent interface was requested or the requested address was not
57+
/// local.
58+
#[stable(feature = "rust1", since = "1.0.0")]
59+
AddrNotAvailable,
60+
/// The system's networking is down.
61+
#[stable(feature = "io_error_a_bit_more", since = "1.83.0")]
62+
NetworkDown,
63+
/// The operation failed because a pipe was closed.
64+
#[stable(feature = "rust1", since = "1.0.0")]
65+
BrokenPipe,
66+
/// An entity already exists, often a file.
67+
#[stable(feature = "rust1", since = "1.0.0")]
68+
AlreadyExists,
69+
/// The operation needs to block to complete, but the blocking operation was
70+
/// requested to not occur.
71+
#[stable(feature = "rust1", since = "1.0.0")]
72+
WouldBlock,
73+
/// A filesystem object is, unexpectedly, not a directory.
74+
///
75+
/// For example, a filesystem path was specified where one of the intermediate directory
76+
/// components was, in fact, a plain file.
77+
#[stable(feature = "io_error_a_bit_more", since = "1.83.0")]
78+
NotADirectory,
79+
/// The filesystem object is, unexpectedly, a directory.
80+
///
81+
/// A directory was specified when a non-directory was expected.
82+
#[stable(feature = "io_error_a_bit_more", since = "1.83.0")]
83+
IsADirectory,
84+
/// A non-empty directory was specified where an empty directory was expected.
85+
#[stable(feature = "io_error_a_bit_more", since = "1.83.0")]
86+
DirectoryNotEmpty,
87+
/// The filesystem or storage medium is read-only, but a write operation was attempted.
88+
#[stable(feature = "io_error_a_bit_more", since = "1.83.0")]
89+
ReadOnlyFilesystem,
90+
/// Loop in the filesystem or IO subsystem; often, too many levels of symbolic links.
91+
///
92+
/// There was a loop (or excessively long chain) resolving a filesystem object
93+
/// or file IO object.
94+
///
95+
/// On Unix this is usually the result of a symbolic link loop; or, of exceeding the
96+
/// system-specific limit on the depth of symlink traversal.
97+
#[unstable(feature = "io_error_more", issue = "86442")]
98+
FilesystemLoop,
99+
/// Stale network file handle.
100+
///
101+
/// With some network filesystems, notably NFS, an open file (or directory) can be invalidated
102+
/// by problems with the network or server.
103+
#[stable(feature = "io_error_a_bit_more", since = "1.83.0")]
104+
StaleNetworkFileHandle,
105+
/// A parameter was incorrect.
106+
#[stable(feature = "rust1", since = "1.0.0")]
107+
InvalidInput,
108+
/// Data not valid for the operation were encountered.
109+
///
110+
/// Unlike [`InvalidInput`], this typically means that the operation
111+
/// parameters were valid, however the error was caused by malformed
112+
/// input data.
113+
///
114+
/// For example, a function that reads a file into a string will error with
115+
/// `InvalidData` if the file's contents are not valid UTF-8.
116+
///
117+
/// [`InvalidInput`]: ErrorKind::InvalidInput
118+
#[stable(feature = "io_invalid_data", since = "1.2.0")]
119+
InvalidData,
120+
/// The I/O operation's timeout expired, causing it to be canceled.
121+
#[stable(feature = "rust1", since = "1.0.0")]
122+
TimedOut,
123+
/// An error returned when an operation could not be completed because a
124+
/// call to an underlying writer returned [`Ok(0)`].
125+
///
126+
/// This typically means that an operation could only succeed if it wrote a
127+
/// particular number of bytes but only a smaller number of bytes could be
128+
/// written.
129+
///
130+
/// [`Ok(0)`]: Ok
131+
#[stable(feature = "rust1", since = "1.0.0")]
132+
WriteZero,
133+
/// The underlying storage (typically, a filesystem) is full.
134+
///
135+
/// This does not include out of quota errors.
136+
#[stable(feature = "io_error_a_bit_more", since = "1.83.0")]
137+
StorageFull,
138+
/// Seek on unseekable file.
139+
///
140+
/// Seeking was attempted on an open file handle which is not suitable for seeking - for
141+
/// example, on Unix, a named pipe opened with `File::open`.
142+
#[stable(feature = "io_error_a_bit_more", since = "1.83.0")]
143+
NotSeekable,
144+
/// Filesystem quota or some other kind of quota was exceeded.
145+
#[stable(feature = "io_error_quota_exceeded", since = "1.85.0")]
146+
QuotaExceeded,
147+
/// File larger than allowed or supported.
148+
///
149+
/// This might arise from a hard limit of the underlying filesystem or file access API, or from
150+
/// an administratively imposed resource limitation. Simple disk full, and out of quota, have
151+
/// their own errors.
152+
#[stable(feature = "io_error_a_bit_more", since = "1.83.0")]
153+
FileTooLarge,
154+
/// Resource is busy.
155+
#[stable(feature = "io_error_a_bit_more", since = "1.83.0")]
156+
ResourceBusy,
157+
/// Executable file is busy.
158+
///
159+
/// An attempt was made to write to a file which is also in use as a running program. (Not all
160+
/// operating systems detect this situation.)
161+
#[stable(feature = "io_error_a_bit_more", since = "1.83.0")]
162+
ExecutableFileBusy,
163+
/// Deadlock (avoided).
164+
///
165+
/// A file locking operation would result in deadlock. This situation is typically detected, if
166+
/// at all, on a best-effort basis.
167+
#[stable(feature = "io_error_a_bit_more", since = "1.83.0")]
168+
Deadlock,
169+
/// Cross-device or cross-filesystem (hard) link or rename.
170+
#[stable(feature = "io_error_crosses_devices", since = "1.85.0")]
171+
CrossesDevices,
172+
/// Too many (hard) links to the same filesystem object.
173+
///
174+
/// The filesystem does not support making so many hardlinks to the same file.
175+
#[stable(feature = "io_error_a_bit_more", since = "1.83.0")]
176+
TooManyLinks,
177+
/// A filename was invalid.
178+
///
179+
/// This error can also occur if a length limit for a name was exceeded.
180+
#[stable(feature = "io_error_invalid_filename", since = "1.87.0")]
181+
InvalidFilename,
182+
/// Program argument list too long.
183+
///
184+
/// When trying to run an external program, a system or process limit on the size of the
185+
/// arguments would have been exceeded.
186+
#[stable(feature = "io_error_a_bit_more", since = "1.83.0")]
187+
ArgumentListTooLong,
188+
/// This operation was interrupted.
189+
///
190+
/// Interrupted operations can typically be retried.
191+
#[stable(feature = "rust1", since = "1.0.0")]
192+
Interrupted,
193+
194+
/// This operation is unsupported on this platform.
195+
///
196+
/// This means that the operation can never succeed.
197+
#[stable(feature = "unsupported_error", since = "1.53.0")]
198+
Unsupported,
199+
200+
// ErrorKinds which are primarily categorisations for OS error
201+
// codes should be added above.
202+
//
203+
/// An error returned when an operation could not be completed because an
204+
/// "end of file" was reached prematurely.
205+
///
206+
/// This typically means that an operation could only succeed if it read a
207+
/// particular number of bytes but only a smaller number of bytes could be
208+
/// read.
209+
#[stable(feature = "read_exact", since = "1.6.0")]
210+
UnexpectedEof,
211+
212+
/// An operation could not be completed, because it failed
213+
/// to allocate enough memory.
214+
#[stable(feature = "out_of_memory_error", since = "1.54.0")]
215+
OutOfMemory,
216+
217+
/// The operation was partially successful and needs to be checked
218+
/// later on due to not blocking.
219+
#[unstable(feature = "io_error_inprogress", issue = "130840")]
220+
InProgress,
221+
222+
// "Unusual" error kinds which do not correspond simply to (sets
223+
// of) OS error codes, should be added just above this comment.
224+
// `Other` and `Uncategorized` should remain at the end:
225+
//
226+
/// A custom error that does not fall under any other I/O error kind.
227+
///
228+
/// This can be used to construct your own errors that do not match any
229+
/// [`ErrorKind`].
230+
///
231+
/// This [`ErrorKind`] is not used by the standard library.
232+
///
233+
/// Errors from the standard library that do not fall under any of the I/O
234+
/// error kinds cannot be `match`ed on, and will only match a wildcard (`_`) pattern.
235+
/// New [`ErrorKind`]s might be added in the future for some of those.
236+
#[stable(feature = "rust1", since = "1.0.0")]
237+
Other,
238+
239+
/// Any I/O error from the standard library that's not part of this list.
240+
///
241+
/// Errors that are `Uncategorized` now may move to a different or a new
242+
/// [`ErrorKind`] variant in the future. It is not recommended to match
243+
/// an error against `Uncategorized`; use a wildcard match (`_`) instead.
244+
#[unstable(feature = "io_error_uncategorized", issue = "none")]
245+
#[doc(hidden)]
246+
Uncategorized,
247+
}
248+
249+
impl ErrorKind {
250+
pub(crate) const fn as_str(&self) -> &'static str {
251+
use ErrorKind::*;
252+
match *self {
253+
// tidy-alphabetical-start
254+
AddrInUse => "address in use",
255+
AddrNotAvailable => "address not available",
256+
AlreadyExists => "entity already exists",
257+
ArgumentListTooLong => "argument list too long",
258+
BrokenPipe => "broken pipe",
259+
ConnectionAborted => "connection aborted",
260+
ConnectionRefused => "connection refused",
261+
ConnectionReset => "connection reset",
262+
CrossesDevices => "cross-device link or rename",
263+
Deadlock => "deadlock",
264+
DirectoryNotEmpty => "directory not empty",
265+
ExecutableFileBusy => "executable file busy",
266+
FileTooLarge => "file too large",
267+
FilesystemLoop => "filesystem loop or indirection limit (e.g. symlink loop)",
268+
HostUnreachable => "host unreachable",
269+
InProgress => "in progress",
270+
Interrupted => "operation interrupted",
271+
InvalidData => "invalid data",
272+
InvalidFilename => "invalid filename",
273+
InvalidInput => "invalid input parameter",
274+
IsADirectory => "is a directory",
275+
NetworkDown => "network down",
276+
NetworkUnreachable => "network unreachable",
277+
NotADirectory => "not a directory",
278+
NotConnected => "not connected",
279+
NotFound => "entity not found",
280+
NotSeekable => "seek on unseekable file",
281+
Other => "other error",
282+
OutOfMemory => "out of memory",
283+
PermissionDenied => "permission denied",
284+
QuotaExceeded => "quota exceeded",
285+
ReadOnlyFilesystem => "read-only filesystem or storage medium",
286+
ResourceBusy => "resource busy",
287+
StaleNetworkFileHandle => "stale network file handle",
288+
StorageFull => "no storage space",
289+
TimedOut => "timed out",
290+
TooManyLinks => "too many links",
291+
Uncategorized => "uncategorized error",
292+
UnexpectedEof => "unexpected end of file",
293+
Unsupported => "unsupported",
294+
WouldBlock => "operation would block",
295+
WriteZero => "write zero",
296+
// tidy-alphabetical-end
297+
}
298+
}
299+
}
300+
301+
#[stable(feature = "io_errorkind_display", since = "1.60.0")]
302+
impl fmt::Display for ErrorKind {
303+
/// Shows a human-readable description of the `ErrorKind`.
304+
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
305+
fmt.write_str(self.as_str())
306+
}
307+
}

library/core/src/io/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
//! Traits, helpers, and type definitions for core I/O functionality.
22
3+
use crate::fmt;
4+
35
mod borrowed_buf;
6+
mod error_kind;
47

58
#[unstable(feature = "core_io_borrowed_buf", issue = "117693")]
69
pub use self::borrowed_buf::{BorrowedBuf, BorrowedCursor};
10+
#[unstable(feature = "core_io_error_kind", issue = "154046")]
11+
pub use self::error_kind::ErrorKind;

0 commit comments

Comments
 (0)