@@ -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,41 @@ 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
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
+ }
163
172
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;
171
176
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
+ }
175
182
}
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
+ } ;
177
193
}
194
+ impl_handle_or ! ( HandleOrNull , ptr:: null_mut( ) , NullHandleError ) ;
195
+ impl_handle_or ! ( HandleOrInvalid , sys:: c:: INVALID_HANDLE_VALUE , InvalidHandleError ) ;
178
196
179
197
impl OwnedHandle {
180
198
/// Creates a new `OwnedHandle` instance that shares the same underlying
@@ -226,25 +244,6 @@ impl BorrowedHandle<'_> {
226
244
}
227
245
}
228
246
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
247
/// This is the error type used by [`HandleOrNull`] when attempting to convert
249
248
/// into a handle, to indicate that the value is null.
250
249
// The empty field prevents constructing this, and allows extending it in the future.
@@ -333,7 +332,7 @@ impl HandleOrNull {
333
332
#[ stable( feature = "io_safety" , since = "1.63.0" ) ]
334
333
#[ inline]
335
334
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) ) )
337
336
}
338
337
}
339
338
@@ -356,7 +355,7 @@ impl HandleOrInvalid {
356
355
#[ stable( feature = "io_safety" , since = "1.63.0" ) ]
357
356
#[ inline]
358
357
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) ) )
360
359
}
361
360
}
362
361
0 commit comments