Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 1ae1eee

Browse files
Rename OptionFileHandle to HandleOrInvalid and make it just wrap an Option<OwnedHandle>
The name (and updated documentation) make the FFI-only usage clearer, and wrapping Option<OwnedHandle> avoids the need to write a separate Drop or Debug impl. Co-authored-by: Josh Triplett <[email protected]>
1 parent 18a9f46 commit 1ae1eee

File tree

2 files changed

+38
-80
lines changed

2 files changed

+38
-80
lines changed

library/std/src/os/windows/io/handle.rs

Lines changed: 37 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ pub struct BorrowedHandle<'handle> {
4545
/// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
4646
/// sometimes a valid handle value. See [here] for the full story. For APIs
4747
/// like `CreateFileW` which report errors with `INVALID_HANDLE_VALUE` instead
48-
/// of null, use [`OptionFileHandle`] instead of `Option<OwnedHandle>`.
48+
/// of null, use [`HandleOrInvalid`] instead of `Option<OwnedHandle>`.
4949
///
5050
/// `OwnedHandle` uses [`CloseHandle`] to close its handle on drop. As such,
5151
/// it must not be used with handles to open registry keys which need to be
@@ -61,36 +61,32 @@ pub struct OwnedHandle {
6161
handle: NonNull<c_void>,
6262
}
6363

64-
/// Similar to `Option<OwnedHandle>`, but intended for use in FFI interfaces
65-
/// where `INVALID_HANDLE_VALUE` is used as the sentry value, and null values
66-
/// are not used at all, such as in the return value of `CreateFileW`.
64+
/// FFI type for handles in return values or out parameters, where `INVALID_HANDLE_VALUE` is used
65+
/// as a sentry value to indicate errors, such as in the return value of `CreateFileW`. This uses
66+
/// `repr(transparent)` and has the representation of a host handle, so that it can be used in such
67+
/// FFI declarations.
6768
///
68-
/// The main thing you can do with an `OptionFileHandle` is to convert it into
69-
/// an `OwnedHandle` using its [`TryFrom`] implementation, and this conversion
70-
/// takes care of the check for `INVALID_HANDLE_VALUE`.
69+
/// The only thing you can usefully do with a `HandleOrInvalid` is to convert it into an
70+
/// `OwnedHandle` using its [`TryFrom`] implementation; this conversion takes care of the check for
71+
/// `INVALID_HANDLE_VALUE`. This ensures that such FFI calls cannot start using the handle without
72+
/// checking for `INVALID_HANDLE_VALUE` first.
7173
///
72-
/// If this holds an owned handle, it closes the handle on drop.
73-
///
74-
/// This uses `repr(transparent)` and has the representation of a host handle,
75-
/// so it can be used in FFI in places where a non-null handle is passed as a
76-
/// consumed argument or returned as an owned value, or it is
77-
/// `INVALID_HANDLE_VALUE` indicating an error or an otherwise absent value.
74+
/// If this holds a valid handle, it will close the handle on drop.
7875
#[repr(transparent)]
7976
#[unstable(feature = "io_safety", issue = "87074")]
80-
pub struct OptionFileHandle {
81-
handle: RawHandle,
82-
}
77+
#[derive(Debug)]
78+
pub struct HandleOrInvalid(Option<OwnedHandle>);
8379

8480
// The Windows [`HANDLE`] type may be transferred across and shared between
8581
// thread boundaries (despite containing a `*mut void`, which in general isn't
8682
// `Send` or `Sync`).
8783
//
8884
// [`HANDLE`]: std::os::windows::raw::HANDLE
8985
unsafe impl Send for OwnedHandle {}
90-
unsafe impl Send for OptionFileHandle {}
86+
unsafe impl Send for HandleOrInvalid {}
9187
unsafe impl Send for BorrowedHandle<'_> {}
9288
unsafe impl Sync for OwnedHandle {}
93-
unsafe impl Sync for OptionFileHandle {}
89+
unsafe impl Sync for HandleOrInvalid {}
9490
unsafe impl Sync for BorrowedHandle<'_> {}
9591

9692
impl BorrowedHandle<'_> {
@@ -114,54 +110,31 @@ impl BorrowedHandle<'_> {
114110
}
115111
}
116112

117-
impl OptionFileHandle {
118-
/// Return an empty `OptionFileHandle` with no resource.
119-
#[inline]
120-
#[unstable(feature = "io_safety", issue = "87074")]
121-
pub const fn none() -> Self {
122-
Self { handle: c::INVALID_HANDLE_VALUE }
123-
}
124-
}
125-
126-
impl TryFrom<OptionFileHandle> for OwnedHandle {
113+
impl TryFrom<HandleOrInvalid> for OwnedHandle {
127114
type Error = ();
128115

129116
#[inline]
130-
fn try_from(option: OptionFileHandle) -> Result<Self, ()> {
131-
let handle = option.handle;
132-
forget(option);
133-
if let Some(non_null) = NonNull::new(handle) {
134-
if non_null.as_ptr() != c::INVALID_HANDLE_VALUE {
135-
Ok(Self { handle: non_null })
136-
} else {
137-
Err(())
138-
}
117+
fn try_from(handle_or_invalid: HandleOrInvalid) -> Result<Self, ()> {
118+
// In theory, we ought to be able to assume that the pointer here is
119+
// never null, use `OwnedHandle` rather than `Option<OwnedHandle>`, and
120+
// obviate the the panic path here. Unfortunately, Win32 documentation
121+
// doesn't explicitly guarantee this anywhere.
122+
//
123+
// APIs like [`CreateFileW`] itself have `HANDLE` arguments where a
124+
// null handle indicates an absent value, which wouldn't work if null
125+
// were a valid handle value, so it seems very unlikely that it could
126+
// ever return null. But who knows?
127+
//
128+
// [`CreateFileW`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
129+
let owned_handle = handle_or_invalid.0.expect("A `HandleOrInvalid` was null!");
130+
if owned_handle.handle.as_ptr() == c::INVALID_HANDLE_VALUE {
131+
Err(())
139132
} else {
140-
// In theory, we ought to be able to assume that the pointer here
141-
// is never null, change `option.handle` to `NonNull`, and obviate
142-
// the the panic path here. Unfortunately, Win32 documentation
143-
// doesn't explicitly guarantee this anywhere.
144-
//
145-
// APIs like [`CreateFileW`] itself have `HANDLE` arguments where a
146-
// null handle indicates an absent value, which wouldn't work if
147-
// null were a valid handle value, so it seems very unlikely that
148-
// it could ever return null. But who knows?
149-
//
150-
// [`CreateFileW`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
151-
panic!("An `OptionFileHandle` was null!");
133+
Ok(owned_handle)
152134
}
153135
}
154136
}
155137

156-
impl From<OwnedHandle> for OptionFileHandle {
157-
#[inline]
158-
fn from(owned: OwnedHandle) -> Self {
159-
let handle = owned.handle;
160-
forget(owned);
161-
Self { handle: handle.as_ptr() }
162-
}
163-
}
164-
165138
impl AsRawHandle for BorrowedHandle<'_> {
166139
#[inline]
167140
fn as_raw_handle(&self) -> RawHandle {
@@ -188,7 +161,7 @@ impl IntoRawHandle for OwnedHandle {
188161
impl FromRawHandle for OwnedHandle {
189162
/// Constructs a new instance of `Self` from the given raw handle.
190163
///
191-
/// Use `OptionFileHandle` instead of `Option<OwnedHandle>` for APIs that
164+
/// Use `HandleOrInvalid` instead of `Option<OwnedHandle>` for APIs that
192165
/// use `INVALID_HANDLE_VALUE` to indicate failure.
193166
///
194167
/// # Safety
@@ -212,12 +185,12 @@ impl FromRawHandle for OwnedHandle {
212185
}
213186
}
214187

215-
impl FromRawHandle for OptionFileHandle {
216-
/// Constructs a new instance of `Self` from the given raw handle returned
188+
impl FromRawHandle for HandleOrInvalid {
189+
/// Constructs a new instance of `Self` from the given `RawHandle` returned
217190
/// from a Windows API that uses `INVALID_HANDLE_VALUE` to indicate
218191
/// failure, such as `CreateFileW`.
219192
///
220-
/// Use `Option<OwnedHandle>` instead of `OptionFileHandle` for APIs that
193+
/// Use `Option<OwnedHandle>` instead of `HandleOrInvalid` for APIs that
221194
/// use null to indicate failure.
222195
///
223196
/// # Safety
@@ -230,8 +203,8 @@ impl FromRawHandle for OptionFileHandle {
230203
/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
231204
#[inline]
232205
unsafe fn from_raw_handle(handle: RawHandle) -> Self {
233-
assert!(!handle.is_null());
234-
Self { handle }
206+
// We require non-null here to catch errors earlier.
207+
Self(Some(OwnedHandle::from_raw_handle(handle)))
235208
}
236209
}
237210

@@ -244,15 +217,6 @@ impl Drop for OwnedHandle {
244217
}
245218
}
246219

247-
impl Drop for OptionFileHandle {
248-
#[inline]
249-
fn drop(&mut self) {
250-
unsafe {
251-
let _ = c::CloseHandle(self.handle);
252-
}
253-
}
254-
}
255-
256220
impl fmt::Debug for BorrowedHandle<'_> {
257221
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
258222
f.debug_struct("BorrowedHandle").field("handle", &self.handle).finish()
@@ -265,12 +229,6 @@ impl fmt::Debug for OwnedHandle {
265229
}
266230
}
267231

268-
impl fmt::Debug for OptionFileHandle {
269-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
270-
f.debug_struct("OptionFileHandle").field("handle", &self.handle).finish()
271-
}
272-
}
273-
274232
/// A trait to borrow the handle from an underlying object.
275233
#[unstable(feature = "io_safety", issue = "87074")]
276234
pub trait AsHandle {

library/std/src/os/windows/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub mod prelude {
3434
#[stable(feature = "rust1", since = "1.0.0")]
3535
pub use super::io::{
3636
AsHandle, AsSocket, BorrowedHandle, BorrowedSocket, FromRawHandle, FromRawSocket,
37-
IntoRawHandle, IntoRawSocket, OptionFileHandle, OwnedHandle, OwnedSocket,
37+
HandleOrInvalid, IntoRawHandle, IntoRawSocket, OwnedHandle, OwnedSocket,
3838
};
3939
#[doc(no_inline)]
4040
#[stable(feature = "rust1", since = "1.0.0")]

0 commit comments

Comments
 (0)