Skip to content

Commit

Permalink
Rollup merge of rust-lang#78880 - CDirkx:not_supported, r=joshtriplett
Browse files Browse the repository at this point in the history
Add `Unsupported` to `std::io::ErrorKind`

I noticed a significant portion of the uses of `ErrorKind::Other` in std is for unsupported operations.
The notion that a specific operation is not available on a target (and will thus never succeed) seems semantically distinct enough from just "an unspecified error occurred", which is why I am proposing to add the variant `Unsupported` to `std::io::ErrorKind`.

**Implementation**:

The following variant will be added to `std::io::ErrorKind`:

```rust
/// This operation is unsupported on this platform.
Unsupported
```
`std::io::ErrorKind::Unsupported` is an error returned when a given operation is not supported on a platform, and will thus never succeed; there is no way for the software to recover. It will be used instead of `Other` where appropriate, e.g. on wasm for file and network operations.

`decode_error_kind` will be updated  to decode operating system errors to `Unsupported`:
- Unix and VxWorks: `libc::ENOSYS`
- Windows: `c::ERROR_CALL_NOT_IMPLEMENTED`
- WASI: `wasi::ERRNO_NOSYS`

**Stability**:
This changes the kind of error returned by some functions on some platforms, which I think is not covered by the stability guarantees of the std? User code could depend on this behavior, expecting `ErrorKind::Other`, however the docs already mention:

> Errors that are `Other` now may move to a different or a new `ErrorKind` variant in the future. It is not recommended to match an error against `Other` and to expect any additional characteristics, e.g., a specific `Error::raw_os_error` return value.

The most recent variant added to `ErrorKind` was `UnexpectedEof` in `1.6.0` (almost 5 years ago), but `ErrorKind` is marked as `#[non_exhaustive]` and the docs warn about exhaustively matching on it, so adding a new variant per se should not be a breaking change.

The variant `Unsupported` itself could be marked as `#[unstable]`, however, because this PR also immediately uses this new variant and changes the errors returned by functions I'm inclined to agree with the others in this thread that the variant should be insta-stabilized.
  • Loading branch information
GuillaumeGomez committed Apr 18, 2021
2 parents b021bee + 5b5afae commit b774b88
Show file tree
Hide file tree
Showing 20 changed files with 81 additions and 56 deletions.
4 changes: 3 additions & 1 deletion library/std/src/fs/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1329,7 +1329,9 @@ fn metadata_access_times() {
match (a.created(), b.created()) {
(Ok(t1), Ok(t2)) => assert!(t1 <= t2),
(Err(e1), Err(e2))
if e1.kind() == ErrorKind::Other && e2.kind() == ErrorKind::Other => {}
if e1.kind() == ErrorKind::Other && e2.kind() == ErrorKind::Other
|| e1.kind() == ErrorKind::Unsupported
&& e2.kind() == ErrorKind::Unsupported => {}
(a, b) => {
panic!("creation time must be always supported or not supported: {:?} {:?}", a, b,)
}
Expand Down
7 changes: 7 additions & 0 deletions library/std/src/io/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,12 @@ pub enum ErrorKind {
/// read.
#[stable(feature = "read_exact", since = "1.6.0")]
UnexpectedEof,

/// This operation is unsupported on this platform.
///
/// This means that the operation can never succeed.
#[stable(feature = "unsupported_error", since = "1.53.0")]
Unsupported,
}

impl ErrorKind {
Expand All @@ -203,6 +209,7 @@ impl ErrorKind {
ErrorKind::Interrupted => "operation interrupted",
ErrorKind::Other => "other os error",
ErrorKind::UnexpectedEof => "unexpected end of file",
ErrorKind::Unsupported => "unsupported",
}
}
}
Expand Down
9 changes: 5 additions & 4 deletions library/std/src/sys/hermit/fd.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#![unstable(reason = "not public", issue = "none", feature = "fd")]

use crate::io::{self, ErrorKind, Read};
use crate::io::{self, Read};
use crate::mem;
use crate::sys::cvt;
use crate::sys::hermit::abi;
use crate::sys::unsupported;
use crate::sys_common::AsInner;

#[derive(Debug)]
Expand Down Expand Up @@ -46,19 +47,19 @@ impl FileDesc {
self.duplicate_path(&[])
}
pub fn duplicate_path(&self, _path: &[u8]) -> io::Result<FileDesc> {
Err(io::Error::new_const(ErrorKind::Other, &"duplicate isn't supported"))
unsupported()
}

pub fn nonblocking(&self) -> io::Result<bool> {
Ok(false)
}

pub fn set_cloexec(&self) -> io::Result<()> {
Err(io::Error::new_const(ErrorKind::Other, &"cloexec isn't supported"))
unsupported()
}

pub fn set_nonblocking(&self, _nonblocking: bool) -> io::Result<()> {
Err(io::Error::new_const(ErrorKind::Other, &"nonblocking isn't supported"))
unsupported()
}
}

Expand Down
2 changes: 1 addition & 1 deletion library/std/src/sys/hermit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ pub fn unsupported<T>() -> crate::io::Result<T> {

pub fn unsupported_err() -> crate::io::Error {
crate::io::Error::new_const(
crate::io::ErrorKind::Other,
crate::io::ErrorKind::Unsupported,
&"operation not supported on HermitCore yet",
)
}
Expand Down
78 changes: 39 additions & 39 deletions library/std/src/sys/hermit/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ impl TcpStream {
}

pub fn socket_addr(&self) -> io::Result<SocketAddr> {
Err(io::Error::new_const(ErrorKind::Other, &"socket_addr isn't supported"))
unsupported()
}

pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
Expand Down Expand Up @@ -199,7 +199,7 @@ impl TcpStream {
}

pub fn take_error(&self) -> io::Result<Option<io::Error>> {
Err(io::Error::new_const(ErrorKind::Other, &"take_error isn't supported"))
unsupported()
}

pub fn set_nonblocking(&self, mode: bool) -> io::Result<()> {
Expand Down Expand Up @@ -247,27 +247,27 @@ impl TcpListener {
}

pub fn set_ttl(&self, _: u32) -> io::Result<()> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn ttl(&self) -> io::Result<u32> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn only_v6(&self) -> io::Result<bool> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn take_error(&self) -> io::Result<Option<io::Error>> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}
}

Expand All @@ -281,127 +281,127 @@ pub struct UdpSocket(abi::Handle);

impl UdpSocket {
pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn peer_addr(&self) -> io::Result<SocketAddr> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn socket_addr(&self) -> io::Result<SocketAddr> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn duplicate(&self) -> io::Result<UdpSocket> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn broadcast(&self) -> io::Result<bool> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn multicast_loop_v4(&self) -> io::Result<bool> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn multicast_loop_v6(&self) -> io::Result<bool> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn set_ttl(&self, _: u32) -> io::Result<()> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn ttl(&self) -> io::Result<u32> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn take_error(&self) -> io::Result<Option<io::Error>> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn send(&self, _: &[u8]) -> io::Result<usize> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}

pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
Err(io::Error::new_const(ErrorKind::Other, &"not supported"))
unsupported()
}
}

Expand Down
2 changes: 1 addition & 1 deletion library/std/src/sys/sgx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub fn unsupported<T>() -> crate::io::Result<T> {
}

pub fn unsupported_err() -> crate::io::Error {
crate::io::Error::new_const(ErrorKind::Other, &"operation not supported on SGX yet")
crate::io::Error::new_const(ErrorKind::Unsupported, &"operation not supported on SGX yet")
}

/// This function is used to implement various functions that doesn't exist,
Expand Down
2 changes: 1 addition & 1 deletion library/std/src/sys/unix/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ impl FileAttr {
}

Err(io::Error::new_const(
io::ErrorKind::Other,
io::ErrorKind::Unsupported,
&"creation time is not available on this platform \
currently",
))
Expand Down
5 changes: 4 additions & 1 deletion library/std/src/sys/unix/l4re.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
macro_rules! unimpl {
() => {
return Err(io::Error::new_const(io::ErrorKind::Other, &"No networking available on L4Re."));
return Err(io::Error::new_const(
io::ErrorKind::Unsupported,
&"No networking available on L4Re.",
));
};
}

Expand Down
1 change: 1 addition & 0 deletions library/std/src/sys/unix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
libc::EINVAL => ErrorKind::InvalidInput,
libc::ETIMEDOUT => ErrorKind::TimedOut,
libc::EEXIST => ErrorKind::AlreadyExists,
libc::ENOSYS => ErrorKind::Unsupported,

// These two constants can have the same value on some systems,
// but different values on others, so we can't use a match
Expand Down
2 changes: 1 addition & 1 deletion library/std/src/sys/unix/os.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ pub fn current_exe() -> io::Result<PathBuf> {
#[cfg(any(target_os = "fuchsia", target_os = "l4re"))]
pub fn current_exe() -> io::Result<PathBuf> {
use crate::io::ErrorKind;
Err(io::Error::new_const(ErrorKind::Other, &"Not yet implemented!"))
Err(io::Error::new_const(ErrorKind::Unsupported, &"Not yet implemented!"))
}

#[cfg(target_os = "vxworks")]
Expand Down
5 changes: 4 additions & 1 deletion library/std/src/sys/unsupported/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ pub fn unsupported<T>() -> std_io::Result<T> {
}

pub fn unsupported_err() -> std_io::Error {
std_io::Error::new_const(std_io::ErrorKind::Other, &"operation not supported on this platform")
std_io::Error::new_const(
std_io::ErrorKind::Unsupported,
&"operation not supported on this platform",
)
}

pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind {
Expand Down
4 changes: 2 additions & 2 deletions library/std/src/sys/unsupported/os.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@ pub fn getenv(_: &OsStr) -> io::Result<Option<OsString>> {
}

pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
Err(io::Error::new_const(io::ErrorKind::Other, &"cannot set env vars on this platform"))
Err(io::Error::new_const(io::ErrorKind::Unsupported, &"cannot set env vars on this platform"))
}

pub fn unsetenv(_: &OsStr) -> io::Result<()> {
Err(io::Error::new_const(io::ErrorKind::Other, &"cannot unset env vars on this platform"))
Err(io::Error::new_const(io::ErrorKind::Unsupported, &"cannot unset env vars on this platform"))
}

pub fn temp_dir() -> PathBuf {
Expand Down
1 change: 1 addition & 0 deletions library/std/src/sys/vxworks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
libc::EINVAL => ErrorKind::InvalidInput,
libc::ETIMEDOUT => ErrorKind::TimedOut,
libc::EEXIST => ErrorKind::AlreadyExists,
libc::ENOSYS => ErrorKind::Unsupported,

// These two constants can have the same value on some systems,
// but different values on others, so we can't use a match
Expand Down
1 change: 1 addition & 0 deletions library/std/src/sys/wasi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind {
wasi::ERRNO_TIMEDOUT => TimedOut,
wasi::ERRNO_EXIST => AlreadyExists,
wasi::ERRNO_AGAIN => WouldBlock,
wasi::ERRNO_NOSYS => Unsupported,
_ => Other,
}
}
Expand Down
5 changes: 4 additions & 1 deletion library/std/src/sys/windows/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -802,7 +802,10 @@ pub fn link(original: &Path, link: &Path) -> io::Result<()> {

#[cfg(target_vendor = "uwp")]
pub fn link(_original: &Path, _link: &Path) -> io::Result<()> {
return Err(io::Error::new_const(io::ErrorKind::Other, &"hard link are not supported on UWP"));
return Err(io::Error::new_const(
io::ErrorKind::Unsupported,
&"hard link are not supported on UWP",
));
}

pub fn stat(path: &Path) -> io::Result<FileAttr> {
Expand Down
1 change: 1 addition & 0 deletions library/std/src/sys/windows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
| c::ERROR_IPSEC_IKE_TIMED_OUT
| c::ERROR_RUNLEVEL_SWITCH_TIMEOUT
| c::ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT => return ErrorKind::TimedOut,
c::ERROR_CALL_NOT_IMPLEMENTED => return ErrorKind::Unsupported,
_ => {}
}

Expand Down
Loading

0 comments on commit b774b88

Please sign in to comment.