Created
August 13, 2025 14:44
-
-
Save samvv/17ecb6263ed8e08ef78ab64c3c885838 to your computer and use it in GitHub Desktop.
Easy way to check for certain IO errors in Rust
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use std::io::ErrorKind; | |
| use std::io::Error; | |
| pub trait IOResultExt<T> : Sized { | |
| fn ok_kind<F: FnOnce(ErrorKind) -> bool>(self, pred: F) -> Result<Option<T>, Error>; | |
| fn ok_not_found(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::NotFound)) | |
| } | |
| fn ok_permission_denied(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::PermissionDenied)) | |
| } | |
| fn ok_connection_refused(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::ConnectionRefused)) | |
| } | |
| fn ok_connection_reset(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::ConnectionRefused)) | |
| } | |
| #[cfg(feature = "io_error_more")] | |
| fn ok_connection_host_unreachable(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::HostUnreachable)) | |
| } | |
| #[cfg(feature = "io_error_more")] | |
| fn ok_network_unreachable(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::NetworkUnreachable)) | |
| } | |
| fn ok_connection_aborted(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::ConnectionAborted)) | |
| } | |
| fn ok_not_connected(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::NotConnected)) | |
| } | |
| fn ok_addr_in_use(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::AddrInUse)) | |
| } | |
| fn ok_addr_not_available(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::AddrNotAvailable)) | |
| } | |
| #[cfg(feature = "io_error_more")] | |
| fn ok_network_down(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::NetworkDown)) | |
| } | |
| fn ok_broken_pipe(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::BrokenPipe)) | |
| } | |
| fn ok_already_exists(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::AlreadyExists)) | |
| } | |
| fn ok_would_block(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::WouldBlock)) | |
| } | |
| #[cfg(feature = "io_error_more")] | |
| fn ok_not_a_directory(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::NotADirectory)) | |
| } | |
| #[cfg(feature = "io_error_more")] | |
| fn ok_is_a_directory(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::IsADirectory)) | |
| } | |
| #[cfg(feature = "io_error_more")] | |
| fn ok_read_only_filesystem(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::ReadOnlyFilesystem)) | |
| } | |
| #[cfg(feature = "io_error_more")] | |
| fn ok_filesystem_loop(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::FilesystemLoop)) | |
| } | |
| #[cfg(feature = "io_error_more")] | |
| fn ok_stale_network_file_handle(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::StaleNetworkFileHandle)) | |
| } | |
| fn ok_invalid_input(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::InvalidInput)) | |
| } | |
| fn ok_invalid_data(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::InvalidData)) | |
| } | |
| fn ok_timed_out(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::TimedOut)) | |
| } | |
| fn ok_write_zero(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::WriteZero)) | |
| } | |
| #[cfg(feature = "io_error_more")] | |
| fn ok_storage_full(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::StorageFull)) | |
| } | |
| #[cfg(feature = "io_error_more")] | |
| fn ok_not_seekable(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::NotSeekable)) | |
| } | |
| #[cfg(feature = "io_error_more")] | |
| fn ok_filesystem_quota_exceeded(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::FilesystemQuotaExceeded)) | |
| } | |
| #[cfg(feature = "io_error_more")] | |
| fn ok_file_too_large(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::FileTooLarge)) | |
| } | |
| #[cfg(feature = "io_error_more")] | |
| fn ok_resource_busy(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::ResourceBusy)) | |
| } | |
| #[cfg(feature = "io_error_more")] | |
| fn ok_executable_file_busy(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::ExecutableFileBusy)) | |
| } | |
| #[cfg(feature = "io_error_more")] | |
| fn ok_deadlock(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::Deadlock)) | |
| } | |
| #[cfg(feature = "io_error_more")] | |
| fn ok_crosses_devices(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::CrossesDevices)) | |
| } | |
| #[cfg(feature = "io_error_more")] | |
| fn ok_too_many_links(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::TooManyLinks)) | |
| } | |
| #[cfg(feature = "io_error_more")] | |
| fn ok_invalid_filename(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::InvalidFilename)) | |
| } | |
| #[cfg(feature = "io_error_more")] | |
| fn ok_argument_list_too_long(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::ArgumentListTooLong)) | |
| } | |
| fn ok_interrupted(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::Interrupted)) | |
| } | |
| fn ok_unsupported(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::Unsupported)) | |
| } | |
| fn ok_unexpected_eof(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::UnexpectedEof)) | |
| } | |
| fn ok_out_of_memory(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::OutOfMemory)) | |
| } | |
| fn ok_other(self) -> Result<Option<T>, Error> { | |
| self.ok_kind(|kind| matches!(kind, ErrorKind::Other)) | |
| } | |
| } | |
| impl <T> IOResultExt<T> for std::result::Result<T, Error> { | |
| fn ok_kind<F: FnOnce(ErrorKind) -> bool>(self, pred: F) -> Result<Option<T>, Error> { | |
| match self { | |
| Ok(value) => Ok(Some(value)), | |
| Err(err) => | |
| if pred(err.kind()) { | |
| Ok(None) | |
| } else { | |
| Err(err) | |
| } | |
| } | |
| } | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment