@@ -8,6 +8,7 @@ use crate::fs;
8
8
use crate :: io;
9
9
use crate :: marker:: PhantomData ;
10
10
use crate :: mem:: forget;
11
+ use crate :: mem:: ManuallyDrop ;
11
12
use crate :: ptr;
12
13
use crate :: sys;
13
14
use crate :: sys:: cvt;
@@ -91,7 +92,7 @@ pub struct OwnedHandle {
91
92
#[ repr( transparent) ]
92
93
#[ stable( feature = "io_safety" , since = "1.63.0" ) ]
93
94
#[ derive( Debug ) ]
94
- pub struct HandleOrNull ( OwnedHandle ) ;
95
+ pub struct HandleOrNull ( ManuallyDrop < OwnedHandle > ) ;
95
96
96
97
/// FFI type for handles in return values or out parameters, where `INVALID_HANDLE_VALUE` is used
97
98
/// 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);
110
111
#[ repr( transparent) ]
111
112
#[ stable( feature = "io_safety" , since = "1.63.0" ) ]
112
113
#[ derive( Debug ) ]
113
- pub struct HandleOrInvalid ( OwnedHandle ) ;
114
+ pub struct HandleOrInvalid ( ManuallyDrop < OwnedHandle > ) ;
114
115
115
116
// The Windows [`HANDLE`] type may be transferred across and shared between
116
117
// thread boundaries (despite containing a `*mut void`, which in general isn't
@@ -157,24 +158,40 @@ impl BorrowedHandle<'_> {
157
158
}
158
159
}
159
160
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
+ }
163
171
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;
171
175
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
+ }
175
181
}
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
+ } ;
177
192
}
193
+ impl_handle_or ! ( HandleOrNull , ptr:: null_mut( ) , NullHandleError ) ;
194
+ impl_handle_or ! ( HandleOrInvalid , sys:: c:: INVALID_HANDLE_VALUE , InvalidHandleError ) ;
178
195
179
196
impl OwnedHandle {
180
197
/// Creates a new `OwnedHandle` instance that shares the same underlying
@@ -226,25 +243,6 @@ impl BorrowedHandle<'_> {
226
243
}
227
244
}
228
245
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
-
248
246
/// This is the error type used by [`HandleOrNull`] when attempting to convert
249
247
/// into a handle, to indicate that the value is null.
250
248
// The empty field prevents constructing this, and allows extending it in the future.
@@ -333,7 +331,7 @@ impl HandleOrNull {
333
331
#[ stable( feature = "io_safety" , since = "1.63.0" ) ]
334
332
#[ inline]
335
333
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) ) )
337
335
}
338
336
}
339
337
@@ -356,7 +354,7 @@ impl HandleOrInvalid {
356
354
#[ stable( feature = "io_safety" , since = "1.63.0" ) ]
357
355
#[ inline]
358
356
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) ) )
360
358
}
361
359
}
362
360
0 commit comments