diff --git a/examples/hello.rs b/examples/hello.rs index c486926..a50b402 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -16,7 +16,7 @@ use std::{ use io_lifetimes::{AsFd, FromFd, OwnedFd}; #[cfg(windows)] -use io_lifetimes::{AsHandle, FromHandle, OwnedHandle}; +use io_lifetimes::{AsHandle, FromHandle, InvalidHandleError, OwnedHandle}; #[cfg(windows)] use std::{convert::TryInto, ptr::null_mut}; @@ -74,7 +74,7 @@ fn main() -> io::Result<()> { null_mut(), ) .try_into() - .map_err(|()| io::Error::last_os_error())?; + .map_err(|_err| io::Error::last_os_error())?; // Borrow the handle to write to it. let mut number_of_bytes_written = 0; diff --git a/src/example_ffi.rs b/src/example_ffi.rs index 44d4c76..b22f3be 100644 --- a/src/example_ffi.rs +++ b/src/example_ffi.rs @@ -6,7 +6,7 @@ #[cfg(any(unix, target_os = "wasi"))] use crate::{BorrowedFd, OwnedFd}; #[cfg(windows)] -use crate::{BorrowedHandle, HandleOrInvalid, OwnedHandle}; +use crate::{BorrowedHandle, HandleOrInvalid}; #[cfg(any(unix, target_os = "wasi"))] use libc::{c_char, c_int, c_void, size_t, ssize_t}; @@ -30,9 +30,9 @@ extern "C" { #[cfg(any(unix, target_os = "wasi"))] pub use libc::{O_CLOEXEC, O_CREAT, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY}; -/// The Windows analogs of the above. Note the use of [`HandleOrInvalid`] as -/// the return type for `CreateFileW`, since that function is defined to return -/// [`INVALID_HANDLE_VALUE`] on error instead of null. +// The Windows analogs of the above. Note the use of [`HandleOrInvalid`] as +// the return type for `CreateFileW`, since that function is defined to return +// [`INVALID_HANDLE_VALUE`] on error instead of null. #[cfg(windows)] extern "system" { pub fn CreateFileW( diff --git a/src/lib.rs b/src/lib.rs index 4783839..1094a5b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,7 +56,10 @@ pub use traits::{FromHandle, FromSocket, IntoHandle, IntoSocket}; pub use types::{BorrowedFd, OwnedFd}; #[cfg(not(io_lifetimes_use_std))] #[cfg(windows)] -pub use types::{BorrowedHandle, BorrowedSocket, HandleOrInvalid, OwnedHandle, OwnedSocket}; +pub use types::{ + BorrowedHandle, BorrowedSocket, HandleOrInvalid, InvalidHandleError, NullHandleError, + OwnedHandle, OwnedSocket, +}; #[cfg(io_lifetimes_use_std)] #[cfg(unix)] @@ -67,7 +70,8 @@ pub use std::os::wasi::io::{AsFd, BorrowedFd, OwnedFd}; #[cfg(io_lifetimes_use_std)] #[cfg(windows)] pub use std::os::windows::io::{ - AsHandle, AsSocket, BorrowedHandle, BorrowedSocket, HandleOrInvalid, OwnedHandle, OwnedSocket, + AsHandle, AsSocket, BorrowedHandle, BorrowedSocket, HandleOrInvalid, InvalidHandleError, + NullHandleError, OwnedHandle, OwnedSocket, }; // io-lifetimes defined `FromFd`/`IntoFd` traits instead of just using diff --git a/src/types.rs b/src/types.rs index 676f498..6eebd82 100644 --- a/src/types.rs +++ b/src/types.rs @@ -491,17 +491,17 @@ impl BorrowedSocket<'_> { #[cfg(windows)] impl TryFrom for OwnedHandle { - type Error = (); + type Error = InvalidHandleError; #[inline] - fn try_from(handle_or_invalid: HandleOrInvalid) -> Result { + fn try_from(handle_or_invalid: HandleOrInvalid) -> Result { let raw = handle_or_invalid.0; if raw == INVALID_HANDLE_VALUE { // Don't call `CloseHandle`; it'd be harmless, except that it could // overwrite the `GetLastError` error. forget(handle_or_invalid); - Err(()) + Err(InvalidHandleError(())) } else { Ok(OwnedHandle { handle: raw }) } @@ -510,23 +510,51 @@ impl TryFrom for OwnedHandle { #[cfg(windows)] impl TryFrom for OwnedHandle { - type Error = (); + type Error = NullHandleError; #[inline] - fn try_from(handle_or_null: HandleOrNull) -> Result { + fn try_from(handle_or_null: HandleOrNull) -> Result { let raw = handle_or_null.0; if raw.is_null() { // Don't call `CloseHandle`; it'd be harmless, except that it could // overwrite the `GetLastError` error. forget(handle_or_null); - Err(()) + Err(NullHandleError(())) } else { Ok(OwnedHandle { handle: raw }) } } } +/// This is the error type used by [`HandleOrNull`] when attempting to convert +/// into a handle, to indicate that the value is null. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct NullHandleError(()); + +impl fmt::Display for NullHandleError { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + "A HandleOrNull could not be converted to a handle because it was null".fmt(fmt) + } +} + +impl std::error::Error for NullHandleError {} + +/// This is the error type used by [`HandleOrInvalid`] when attempting to +/// convert into a handle, to indicate that the value is +/// `INVALID_HANDLE_VALUE`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct InvalidHandleError(()); + +impl fmt::Display for InvalidHandleError { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + "A HandleOrInvalid could not be converted to a handle because it was INVALID_HANDLE_VALUE" + .fmt(fmt) + } +} + +impl std::error::Error for InvalidHandleError {} + #[cfg(any(unix, target_os = "wasi"))] impl AsRawFd for BorrowedFd<'_> { #[inline] diff --git a/tests/ffi.rs b/tests/ffi.rs index ccc6ac8..d37149f 100644 --- a/tests/ffi.rs +++ b/tests/ffi.rs @@ -5,7 +5,7 @@ #[cfg(any(unix, windows))] use io_lifetimes::example_ffi::*; #[cfg(windows)] -use io_lifetimes::OwnedHandle; +use io_lifetimes::{InvalidHandleError, OwnedHandle}; #[cfg(windows)] use std::{convert::TryInto, ptr::null_mut}; #[cfg(windows)] @@ -29,7 +29,7 @@ fn test_file_not_found() { #[cfg(windows)] #[test] fn test_file_not_found() { - let handle: Result = unsafe { + let handle: Result = unsafe { CreateFileW( [ 'C' as u16, ':' as _, '/' as _, 'n' as _, 'o' as _, '/' as _, 's' as _, 'u' as _, @@ -61,7 +61,7 @@ fn test_file_found() { #[cfg(windows)] #[test] fn test_file_found() { - let handle: Result = unsafe { + let handle: Result = unsafe { CreateFileW( [ 'C' as u16, 'a' as _, 'r' as _, 'g' as _, 'o' as _, '.' as _, 't' as _, 'o' as _, diff --git a/tests/niche-optimizations.rs b/tests/niche-optimizations.rs index b5c4098..21663f1 100644 --- a/tests/niche-optimizations.rs +++ b/tests/niche-optimizations.rs @@ -7,14 +7,14 @@ use std::mem::size_of; #[cfg(any(unix, target_os = "wasi"))] use io_lifetimes::{BorrowedFd, OwnedFd}; #[cfg(windows)] -use io_lifetimes::{BorrowedHandle, BorrowedSocket, OwnedHandle, OwnedSocket}; +use io_lifetimes::{BorrowedSocket, OwnedSocket}; #[cfg(unix)] use std::os::unix::io::RawFd; #[cfg(target_os = "wasi")] use std::os::wasi::io::RawFd; #[cfg(windows)] -use std::os::windows::io::{RawHandle, RawSocket}; +use std::os::windows::io::RawSocket; #[cfg(all(rustc_attrs, any(unix, target_os = "wasi")))] #[test]