@@ -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,41 @@ 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
166+ // the invalid value.
167+ Some ( & mut self . 0 )
168+ . filter( |handle| handle. handle != $invalid_handle)
169+ . map( |handle| unsafe { ManuallyDrop :: take( handle) } )
170+ }
171+ }
163172
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) ;
173+ #[ stable( feature = "io_safety" , since = "1.63.0" ) ]
174+ impl TryFrom <$name> for OwnedHandle {
175+ type Error = $error;
171176
172- Err ( NullHandleError ( ( ) ) )
173- } else {
174- Ok ( owned_handle)
177+ #[ inline]
178+ fn try_from( handle_or: $name) -> Result <Self , $error> {
179+ // SAFETY: `ManuallyDrop` prevents calling `Drop`.
180+ unsafe { ManuallyDrop :: new( handle_or) . take_owned_handle( ) } . ok_or( $error( ( ) ) )
181+ }
175182 }
176- }
183+
184+ #[ stable( feature = "handle_or_drop" , since = "1.75.0" ) ]
185+ impl Drop for $name {
186+ #[ inline]
187+ fn drop( & mut self ) {
188+ // SAFETY: `Drop` has already been called (and is running).
189+ let _ = unsafe { self . take_owned_handle( ) } ;
190+ }
191+ }
192+ } ;
177193}
194+ impl_handle_or ! ( HandleOrNull , ptr:: null_mut( ) , NullHandleError ) ;
195+ impl_handle_or ! ( HandleOrInvalid , sys:: c:: INVALID_HANDLE_VALUE , InvalidHandleError ) ;
178196
179197impl OwnedHandle {
180198 /// Creates a new `OwnedHandle` instance that shares the same underlying
@@ -226,25 +244,6 @@ impl BorrowedHandle<'_> {
226244 }
227245}
228246
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-
248247/// This is the error type used by [`HandleOrNull`] when attempting to convert
249248/// into a handle, to indicate that the value is null.
250249// The empty field prevents constructing this, and allows extending it in the future.
@@ -333,7 +332,7 @@ impl HandleOrNull {
333332 #[ stable( feature = "io_safety" , since = "1.63.0" ) ]
334333 #[ inline]
335334 pub unsafe fn from_raw_handle ( handle : RawHandle ) -> Self {
336- Self ( OwnedHandle :: from_raw_handle ( handle) )
335+ Self ( ManuallyDrop :: new ( OwnedHandle :: from_raw_handle ( handle) ) )
337336 }
338337}
339338
@@ -356,7 +355,7 @@ impl HandleOrInvalid {
356355 #[ stable( feature = "io_safety" , since = "1.63.0" ) ]
357356 #[ inline]
358357 pub unsafe fn from_raw_handle ( handle : RawHandle ) -> Self {
359- Self ( OwnedHandle :: from_raw_handle ( handle) )
358+ Self ( ManuallyDrop :: new ( OwnedHandle :: from_raw_handle ( handle) ) )
360359 }
361360}
362361
0 commit comments