@@ -8,6 +8,7 @@ use crate::fs;
88use crate :: io;
99use crate :: marker:: PhantomData ;
1010use crate :: mem:: forget;
11+ use crate :: mem:: ManuallyDrop ;
1112use crate :: ptr;
1213use crate :: sys;
1314use crate :: sys:: cvt;
@@ -91,7 +92,7 @@ pub struct OwnedHandle {
9192#[ repr( transparent) ]
9293#[ stable( feature = "io_safety" , since = "1.63.0" ) ]
9394#[ derive( Debug ) ]
94- pub struct HandleOrNull ( OwnedHandle ) ;
95+ pub struct HandleOrNull ( ManuallyDrop < OwnedHandle > ) ;
9596
9697/// FFI type for handles in return values or out parameters, where `INVALID_HANDLE_VALUE` is used
9798/// as a sentry value to indicate errors, such as in the return value of `CreateFileW`. This uses
@@ -110,7 +111,7 @@ pub struct HandleOrNull(OwnedHandle);
110111#[ repr( transparent) ]
111112#[ stable( feature = "io_safety" , since = "1.63.0" ) ]
112113#[ derive( Debug ) ]
113- pub struct HandleOrInvalid ( OwnedHandle ) ;
114+ pub struct HandleOrInvalid ( ManuallyDrop < OwnedHandle > ) ;
114115
115116// The Windows [`HANDLE`] type may be transferred across and shared between
116117// thread boundaries (despite containing a `*mut void`, which in general isn't
@@ -157,24 +158,40 @@ impl BorrowedHandle<'_> {
157158 }
158159}
159160
160- #[ stable( feature = "io_safety" , since = "1.63.0" ) ]
161- impl TryFrom < HandleOrNull > for OwnedHandle {
162- type Error = NullHandleError ;
161+ macro_rules! impl_handle_or {
162+ ( $name: ident, $invalid_handle: expr, $error: ident ) => {
163+ impl $name {
164+ unsafe fn take_owned_handle( & mut self ) -> Option <OwnedHandle > {
165+ // Filter before taking the value, to avoid calling `Drop` on the invalid value.
166+ Some ( & mut self . 0 )
167+ . filter( |handle| handle. handle != $invalid_handle)
168+ . map( |handle| unsafe { ManuallyDrop :: take( handle) } )
169+ }
170+ }
163171
164- #[ inline]
165- fn try_from ( handle_or_null : HandleOrNull ) -> Result < Self , NullHandleError > {
166- let owned_handle = handle_or_null. 0 ;
167- if owned_handle. handle . is_null ( ) {
168- // Don't call `CloseHandle`; it'd be harmless, except that it could
169- // overwrite the `GetLastError` error.
170- forget ( owned_handle) ;
172+ #[ stable( feature = "io_safety" , since = "1.63.0" ) ]
173+ impl TryFrom <$name> for OwnedHandle {
174+ type Error = $error;
171175
172- Err ( NullHandleError ( ( ) ) )
173- } else {
174- Ok ( owned_handle)
176+ #[ inline]
177+ fn try_from( handle_or: $name) -> Result <Self , $error> {
178+ // SAFETY: `ManuallyDrop` prevents calling `Drop`.
179+ unsafe { ManuallyDrop :: new( handle_or) . take_owned_handle( ) } . ok_or( $error( ( ) ) )
180+ }
175181 }
176- }
182+
183+ #[ stable( feature = "handle_or_drop" , since = "1.75.0" ) ]
184+ impl Drop for $name {
185+ #[ inline]
186+ fn drop( & mut self ) {
187+ // SAFETY: `Drop` has already been called (and is running).
188+ let _ = unsafe { self . take_owned_handle( ) } ;
189+ }
190+ }
191+ } ;
177192}
193+ impl_handle_or ! ( HandleOrNull , ptr:: null_mut( ) , NullHandleError ) ;
194+ impl_handle_or ! ( HandleOrInvalid , sys:: c:: INVALID_HANDLE_VALUE , InvalidHandleError ) ;
178195
179196impl OwnedHandle {
180197 /// Creates a new `OwnedHandle` instance that shares the same underlying
@@ -226,25 +243,6 @@ impl BorrowedHandle<'_> {
226243 }
227244}
228245
229- #[ stable( feature = "io_safety" , since = "1.63.0" ) ]
230- impl TryFrom < HandleOrInvalid > for OwnedHandle {
231- type Error = InvalidHandleError ;
232-
233- #[ inline]
234- fn try_from ( handle_or_invalid : HandleOrInvalid ) -> Result < Self , InvalidHandleError > {
235- let owned_handle = handle_or_invalid. 0 ;
236- if owned_handle. handle == sys:: c:: INVALID_HANDLE_VALUE {
237- // Don't call `CloseHandle`; it'd be harmless, except that it could
238- // overwrite the `GetLastError` error.
239- forget ( owned_handle) ;
240-
241- Err ( InvalidHandleError ( ( ) ) )
242- } else {
243- Ok ( owned_handle)
244- }
245- }
246- }
247-
248246/// This is the error type used by [`HandleOrNull`] when attempting to convert
249247/// into a handle, to indicate that the value is null.
250248// The empty field prevents constructing this, and allows extending it in the future.
@@ -333,7 +331,7 @@ impl HandleOrNull {
333331 #[ stable( feature = "io_safety" , since = "1.63.0" ) ]
334332 #[ inline]
335333 pub unsafe fn from_raw_handle ( handle : RawHandle ) -> Self {
336- Self ( OwnedHandle :: from_raw_handle ( handle) )
334+ Self ( ManuallyDrop :: new ( OwnedHandle :: from_raw_handle ( handle) ) )
337335 }
338336}
339337
@@ -356,7 +354,7 @@ impl HandleOrInvalid {
356354 #[ stable( feature = "io_safety" , since = "1.63.0" ) ]
357355 #[ inline]
358356 pub unsafe fn from_raw_handle ( handle : RawHandle ) -> Self {
359- Self ( OwnedHandle :: from_raw_handle ( handle) )
357+ Self ( ManuallyDrop :: new ( OwnedHandle :: from_raw_handle ( handle) ) )
360358 }
361359}
362360
0 commit comments