• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::fmt;
2 use std::marker::PhantomData;
3 use std::mem::forget;
4 #[cfg(unix)]
5 use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
6 #[cfg(target_os = "wasi")]
7 use std::os::wasi::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
8 #[cfg(windows)]
9 use std::{
10     convert::TryFrom,
11     os::windows::io::{
12         AsRawHandle, AsRawSocket, FromRawHandle, FromRawSocket, IntoRawHandle, IntoRawSocket,
13         RawHandle, RawSocket,
14     },
15 };
16 #[cfg(all(windows, feature = "close"))]
17 use {
18     windows_sys::Win32::Foundation::{
19         CloseHandle, DuplicateHandle, SetHandleInformation, BOOL, DUPLICATE_HANDLE_OPTIONS,
20         DUPLICATE_SAME_ACCESS, HANDLE, HANDLE_FLAG_INHERIT, INVALID_HANDLE_VALUE,
21     },
22     windows_sys::Win32::Networking::WinSock::{
23         closesocket, WSADuplicateSocketW, WSAGetLastError, WSASocketW, INVALID_SOCKET, SOCKET,
24         SOCKET_ERROR, WSAEINVAL, WSAEPROTOTYPE, WSAPROTOCOL_INFOW, WSA_FLAG_NO_HANDLE_INHERIT,
25         WSA_FLAG_OVERLAPPED,
26     },
27     windows_sys::Win32::System::Threading::{GetCurrentProcess, GetCurrentProcessId},
28 };
29 
30 #[cfg(all(windows, not(feature = "close")))]
31 type HANDLE = isize;
32 #[cfg(all(windows, not(feature = "close")))]
33 const INVALID_HANDLE_VALUE: HANDLE = !0 as _;
34 #[cfg(all(windows, not(feature = "close")))]
35 const INVALID_SOCKET: usize = !0 as _;
36 
37 /// A borrowed file descriptor.
38 ///
39 /// This has a lifetime parameter to tie it to the lifetime of something that
40 /// owns the file descriptor.
41 ///
42 /// This uses `repr(transparent)` and has the representation of a host file
43 /// descriptor, so it can be used in FFI in places where a file descriptor is
44 /// passed as an argument, it is not captured or consumed, and it never has the
45 /// value `-1`.
46 ///
47 /// This type's `.to_owned()` implementation returns another `BorrowedFd`
48 /// rather than an `OwnedFd`. It just makes a trivial copy of the raw file
49 /// descriptor, which is then borrowed under the same lifetime.
50 #[cfg(any(unix, target_os = "wasi"))]
51 #[derive(Copy, Clone)]
52 #[repr(transparent)]
53 pub struct BorrowedFd<'fd> {
54     fd: RawFd,
55     _phantom: PhantomData<&'fd OwnedFd>,
56 }
57 
58 /// A borrowed handle.
59 ///
60 /// This has a lifetime parameter to tie it to the lifetime of something that
61 /// owns the handle.
62 ///
63 /// This uses `repr(transparent)` and has the representation of a host handle,
64 /// so it can be used in FFI in places where a handle is passed as an argument,
65 /// it is not captured or consumed, and it is never null.
66 ///
67 /// Note that it *may* have the value `-1`, which in `BorrowedHandle` always
68 /// represents a valid handle value, such as [the current process handle], and
69 /// not `INVALID_HANDLE_VALUE`, despite the two having the same value. See
70 /// [here] for the full story.
71 ///
72 /// This type's `.to_owned()` implementation returns another `BorrowedHandle`
73 /// rather than an `OwnedHandle`. It just makes a trivial copy of the raw
74 /// handle, which is then borrowed under the same lifetime.
75 ///
76 /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
77 /// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks
78 #[cfg(windows)]
79 #[derive(Copy, Clone)]
80 #[repr(transparent)]
81 pub struct BorrowedHandle<'handle> {
82     handle: RawHandle,
83     _phantom: PhantomData<&'handle OwnedHandle>,
84 }
85 
86 /// A borrowed socket.
87 ///
88 /// This has a lifetime parameter to tie it to the lifetime of something that
89 /// owns the socket.
90 ///
91 /// This uses `repr(transparent)` and has the representation of a host socket,
92 /// so it can be used in FFI in places where a socket is passed as an argument,
93 /// it is not captured or consumed, and it never has the value
94 /// [`INVALID_SOCKET`].
95 ///
96 /// This type's `.to_owned()` implementation returns another `BorrowedSocket`
97 /// rather than an `OwnedSocket`. It just makes a trivial copy of the raw
98 /// socket, which is then borrowed under the same lifetime.
99 #[cfg(windows)]
100 #[derive(Copy, Clone)]
101 #[repr(transparent)]
102 pub struct BorrowedSocket<'socket> {
103     socket: RawSocket,
104     _phantom: PhantomData<&'socket OwnedSocket>,
105 }
106 
107 /// An owned file descriptor.
108 ///
109 /// This closes the file descriptor on drop.
110 ///
111 /// This uses `repr(transparent)` and has the representation of a host file
112 /// descriptor, so it can be used in FFI in places where a file descriptor is
113 /// passed as a consumed argument or returned as an owned value, and it never
114 /// has the value `-1`.
115 #[cfg(any(unix, target_os = "wasi"))]
116 #[repr(transparent)]
117 pub struct OwnedFd {
118     fd: RawFd,
119 }
120 
121 #[cfg(any(unix, target_os = "wasi"))]
122 impl OwnedFd {
123     /// Creates a new `OwnedFd` instance that shares the same underlying file
124     /// description as the existing `OwnedFd` instance.
try_clone(&self) -> std::io::Result<Self>125     pub fn try_clone(&self) -> std::io::Result<Self> {
126         crate::AsFd::as_fd(self).try_clone_to_owned()
127     }
128 }
129 
130 #[cfg(any(unix, target_os = "wasi"))]
131 impl BorrowedFd<'_> {
132     /// Creates a new `OwnedFd` instance that shares the same underlying file
133     /// description as the existing `BorrowedFd` instance.
try_clone_to_owned(&self) -> std::io::Result<OwnedFd>134     pub fn try_clone_to_owned(&self) -> std::io::Result<OwnedFd> {
135         #[cfg(feature = "close")]
136         {
137             #[cfg(unix)]
138             {
139                 // We want to atomically duplicate this file descriptor and set the
140                 // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
141                 // is a POSIX flag that was added to Linux in 2.6.24.
142                 #[cfg(not(target_os = "espidf"))]
143                 let cmd = libc::F_DUPFD_CLOEXEC;
144 
145                 // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics
146                 // will never be supported, as this is a bare metal framework with
147                 // no capabilities for multi-process execution.  While F_DUPFD is also
148                 // not supported yet, it might be (currently it returns ENOSYS).
149                 #[cfg(target_os = "espidf")]
150                 let cmd = libc::F_DUPFD;
151 
152                 let fd = match unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) } {
153                     -1 => return Err(std::io::Error::last_os_error()),
154                     fd => fd,
155                 };
156 
157                 Ok(unsafe { OwnedFd::from_raw_fd(fd) })
158             }
159 
160             #[cfg(target_os = "wasi")]
161             {
162                 unreachable!("try_clone is not yet suppported on wasi");
163             }
164         }
165 
166         // If the `close` feature is disabled, we expect users to avoid cloning
167         // `OwnedFd` instances, so that we don't have to call `fcntl`.
168         #[cfg(not(feature = "close"))]
169         {
170             unreachable!("try_clone called without the \"close\" feature in io-lifetimes");
171         }
172     }
173 }
174 
175 /// An owned handle.
176 ///
177 /// This closes the handle on drop.
178 ///
179 /// Note that it *may* have the value `-1`, which in `OwnedHandle` always
180 /// represents a valid handle value, such as [the current process handle], and
181 /// not `INVALID_HANDLE_VALUE`, despite the two having the same value. See
182 /// [here] for the full story.
183 ///
184 /// And, it *may* have the value `NULL` (0), which can occur when consoles are
185 /// detached from processes, or when `windows_subsystem` is used.
186 ///
187 /// `OwnedHandle` uses [`CloseHandle`] to close its handle on drop. As such,
188 /// it must not be used with handles to open registry keys which need to be
189 /// closed with [`RegCloseKey`] instead.
190 ///
191 /// [`CloseHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
192 /// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey
193 ///
194 /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
195 /// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks
196 #[cfg(windows)]
197 #[repr(transparent)]
198 pub struct OwnedHandle {
199     handle: RawHandle,
200 }
201 
202 #[cfg(windows)]
203 impl OwnedHandle {
204     /// Creates a new `OwnedHandle` instance that shares the same underlying
205     /// object as the existing `OwnedHandle` instance.
try_clone(&self) -> std::io::Result<Self>206     pub fn try_clone(&self) -> std::io::Result<Self> {
207         crate::AsHandle::as_handle(self).try_clone_to_owned()
208     }
209 }
210 
211 #[cfg(windows)]
212 impl BorrowedHandle<'_> {
213     /// Creates a new `OwnedHandle` instance that shares the same underlying
214     /// object as the existing `BorrowedHandle` instance.
try_clone_to_owned(&self) -> std::io::Result<OwnedHandle>215     pub fn try_clone_to_owned(&self) -> std::io::Result<OwnedHandle> {
216         #[cfg(feature = "close")]
217         {
218             self.duplicate(0, false, DUPLICATE_SAME_ACCESS)
219         }
220 
221         // If the `close` feature is disabled, we expect users to avoid cloning
222         // `OwnedHandle` instances, so that we don't have to call `fcntl`.
223         #[cfg(not(feature = "close"))]
224         {
225             unreachable!("try_clone called without the \"close\" feature in io-lifetimes");
226         }
227     }
228 
229     #[cfg(feature = "close")]
duplicate( &self, access: u32, inherit: bool, options: DUPLICATE_HANDLE_OPTIONS, ) -> std::io::Result<OwnedHandle>230     pub(crate) fn duplicate(
231         &self,
232         access: u32,
233         inherit: bool,
234         options: DUPLICATE_HANDLE_OPTIONS,
235     ) -> std::io::Result<OwnedHandle> {
236         let mut ret = 0 as HANDLE;
237         match unsafe {
238             let cur_proc = GetCurrentProcess();
239             DuplicateHandle(
240                 cur_proc,
241                 self.as_raw_handle() as HANDLE,
242                 cur_proc,
243                 &mut ret,
244                 access,
245                 inherit as BOOL,
246                 options,
247             )
248         } {
249             0 => return Err(std::io::Error::last_os_error()),
250             _ => (),
251         }
252         unsafe { Ok(OwnedHandle::from_raw_handle(ret as RawHandle)) }
253     }
254 }
255 
256 /// An owned socket.
257 ///
258 /// This closes the socket on drop.
259 ///
260 /// This uses `repr(transparent)` and has the representation of a host socket,
261 /// so it can be used in FFI in places where a socket is passed as a consumed
262 /// argument or returned as an owned value, and it never has the value
263 /// [`INVALID_SOCKET`].
264 #[cfg(windows)]
265 #[repr(transparent)]
266 pub struct OwnedSocket {
267     socket: RawSocket,
268 }
269 
270 #[cfg(windows)]
271 impl OwnedSocket {
272     /// Creates a new `OwnedSocket` instance that shares the same underlying
273     /// object as the existing `OwnedSocket` instance.
try_clone(&self) -> std::io::Result<Self>274     pub fn try_clone(&self) -> std::io::Result<Self> {
275         crate::AsSocket::as_socket(self).try_clone_to_owned()
276     }
277 
278     #[cfg(feature = "close")]
279     #[cfg(not(target_vendor = "uwp"))]
set_no_inherit(&self) -> std::io::Result<()>280     fn set_no_inherit(&self) -> std::io::Result<()> {
281         match unsafe {
282             SetHandleInformation(self.as_raw_socket() as HANDLE, HANDLE_FLAG_INHERIT, 0)
283         } {
284             0 => return Err(std::io::Error::last_os_error()),
285             _ => Ok(()),
286         }
287     }
288 
289     #[cfg(feature = "close")]
290     #[cfg(target_vendor = "uwp")]
set_no_inherit(&self) -> std::io::Result<()>291     fn set_no_inherit(&self) -> std::io::Result<()> {
292         Err(io::Error::new_const(
293             std::io::ErrorKind::Unsupported,
294             &"Unavailable on UWP",
295         ))
296     }
297 }
298 
299 #[cfg(windows)]
300 impl BorrowedSocket<'_> {
301     /// Creates a new `OwnedSocket` instance that shares the same underlying
302     /// object as the existing `BorrowedSocket` instance.
try_clone_to_owned(&self) -> std::io::Result<OwnedSocket>303     pub fn try_clone_to_owned(&self) -> std::io::Result<OwnedSocket> {
304         #[cfg(feature = "close")]
305         {
306             let mut info = unsafe { std::mem::zeroed::<WSAPROTOCOL_INFOW>() };
307             let result = unsafe {
308                 WSADuplicateSocketW(self.as_raw_socket() as _, GetCurrentProcessId(), &mut info)
309             };
310             match result {
311                 SOCKET_ERROR => return Err(std::io::Error::last_os_error()),
312                 0 => (),
313                 _ => panic!(),
314             }
315             let socket = unsafe {
316                 WSASocketW(
317                     info.iAddressFamily,
318                     info.iSocketType,
319                     info.iProtocol,
320                     &mut info,
321                     0,
322                     WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT,
323                 )
324             };
325 
326             if socket != INVALID_SOCKET {
327                 unsafe { Ok(OwnedSocket::from_raw_socket(socket as _)) }
328             } else {
329                 let error = unsafe { WSAGetLastError() };
330 
331                 if error != WSAEPROTOTYPE && error != WSAEINVAL {
332                     return Err(std::io::Error::from_raw_os_error(error));
333                 }
334 
335                 let socket = unsafe {
336                     WSASocketW(
337                         info.iAddressFamily,
338                         info.iSocketType,
339                         info.iProtocol,
340                         &mut info,
341                         0,
342                         WSA_FLAG_OVERLAPPED,
343                     )
344                 };
345 
346                 if socket == INVALID_SOCKET {
347                     return Err(std::io::Error::last_os_error());
348                 }
349 
350                 unsafe {
351                     let socket = OwnedSocket::from_raw_socket(socket as _);
352                     socket.set_no_inherit()?;
353                     Ok(socket)
354                 }
355             }
356         }
357 
358         // If the `close` feature is disabled, we expect users to avoid cloning
359         // `OwnedSocket` instances, so that we don't have to call `fcntl`.
360         #[cfg(not(feature = "close"))]
361         {
362             unreachable!("try_clone called without the \"close\" feature in io-lifetimes");
363         }
364     }
365 }
366 
367 /// FFI type for handles in return values or out parameters, where `INVALID_HANDLE_VALUE` is used
368 /// as a sentry value to indicate errors, such as in the return value of `CreateFileW`. This uses
369 /// `repr(transparent)` and has the representation of a host handle, so that it can be used in such
370 /// FFI declarations.
371 ///
372 /// The only thing you can usefully do with a `HandleOrInvalid` is to convert it into an
373 /// `OwnedHandle` using its [`TryFrom`] implementation; this conversion takes care of the check for
374 /// `INVALID_HANDLE_VALUE`. This ensures that such FFI calls cannot start using the handle without
375 /// checking for `INVALID_HANDLE_VALUE` first.
376 ///
377 /// This type may hold any handle value that [`OwnedHandle`] may hold, except that when it holds
378 /// `-1`, that value is interpreted to mean `INVALID_HANDLE_VALUE`.
379 ///
380 /// If holds a handle other than `INVALID_HANDLE_VALUE`, it will close the handle on drop.
381 #[cfg(windows)]
382 #[repr(transparent)]
383 #[derive(Debug)]
384 pub struct HandleOrInvalid(RawHandle);
385 
386 /// FFI type for handles in return values or out parameters, where `NULL` is used
387 /// as a sentry value to indicate errors, such as in the return value of `CreateThread`. This uses
388 /// `repr(transparent)` and has the representation of a host handle, so that it can be used in such
389 /// FFI declarations.
390 ///
391 /// The only thing you can usefully do with a `HandleOrNull` is to convert it into an
392 /// `OwnedHandle` using its [`TryFrom`] implementation; this conversion takes care of the check for
393 /// `NULL`. This ensures that such FFI calls cannot start using the handle without
394 /// checking for `NULL` first.
395 ///
396 /// This type may hold any handle value that [`OwnedHandle`] may hold. As with `OwnedHandle`, when
397 /// it holds `-1`, that value is interpreted as a valid handle value, such as
398 /// [the current process handle], and not `INVALID_HANDLE_VALUE`.
399 ///
400 /// If this holds a non-null handle, it will close the handle on drop.
401 ///
402 /// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks
403 #[cfg(windows)]
404 #[repr(transparent)]
405 #[derive(Debug)]
406 pub struct HandleOrNull(RawHandle);
407 
408 // The Windows [`HANDLE`] type may be transferred across and shared between
409 // thread boundaries (despite containing a `*mut void`, which in general isn't
410 // `Send` or `Sync`).
411 //
412 // [`HANDLE`]: std::os::windows::raw::HANDLE
413 #[cfg(windows)]
414 unsafe impl Send for OwnedHandle {}
415 #[cfg(windows)]
416 unsafe impl Send for HandleOrInvalid {}
417 #[cfg(windows)]
418 unsafe impl Send for HandleOrNull {}
419 #[cfg(windows)]
420 unsafe impl Send for BorrowedHandle<'_> {}
421 #[cfg(windows)]
422 unsafe impl Sync for OwnedHandle {}
423 #[cfg(windows)]
424 unsafe impl Sync for HandleOrInvalid {}
425 #[cfg(windows)]
426 unsafe impl Sync for HandleOrNull {}
427 #[cfg(windows)]
428 unsafe impl Sync for BorrowedHandle<'_> {}
429 
430 #[cfg(any(unix, target_os = "wasi"))]
431 impl BorrowedFd<'_> {
432     /// Return a `BorrowedFd` holding the given raw file descriptor.
433     ///
434     /// # Safety
435     ///
436     /// The resource pointed to by `raw` must remain open for the duration of
437     /// the returned `BorrowedFd`, and it must not have the value `-1`.
438     #[inline]
borrow_raw(fd: RawFd) -> Self439     pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
440         #[cfg(panic_in_const_fn)]
441         debug_assert!(fd != -1_i32 as RawFd);
442 
443         Self {
444             fd,
445             _phantom: PhantomData,
446         }
447     }
448 }
449 
450 #[cfg(windows)]
451 impl BorrowedHandle<'_> {
452     /// Return a `BorrowedHandle` holding the given raw handle.
453     ///
454     /// # Safety
455     ///
456     /// The resource pointed to by `handle` must be a valid open handle, it
457     /// must remain open for the duration of the returned `BorrowedHandle`.
458     ///
459     /// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
460     /// sometimes a valid handle value. See [here] for the full story.
461     ///
462     /// And, it *may* have the value `NULL` (0), which can occur when consoles are
463     /// detached from processes, or when `windows_subsystem` is used.
464     ///
465     /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
466     #[inline]
borrow_raw(handle: RawHandle) -> Self467     pub const unsafe fn borrow_raw(handle: RawHandle) -> Self {
468         Self {
469             handle,
470             _phantom: PhantomData,
471         }
472     }
473 }
474 
475 #[cfg(windows)]
476 impl BorrowedSocket<'_> {
477     /// Return a `BorrowedSocket` holding the given raw socket.
478     ///
479     /// # Safety
480     ///
481     /// The resource pointed to by `raw` must remain open for the duration of
482     /// the returned `BorrowedSocket`, and it must not have the value
483     /// [`INVALID_SOCKET`].
484     #[inline]
borrow_raw(socket: RawSocket) -> Self485     pub const unsafe fn borrow_raw(socket: RawSocket) -> Self {
486         #[cfg(panic_in_const_fn)]
487         debug_assert!(socket != INVALID_SOCKET as RawSocket);
488         Self {
489             socket,
490             _phantom: PhantomData,
491         }
492     }
493 }
494 
495 #[cfg(windows)]
496 impl TryFrom<HandleOrInvalid> for OwnedHandle {
497     type Error = InvalidHandleError;
498 
499     #[inline]
try_from(handle_or_invalid: HandleOrInvalid) -> Result<Self, InvalidHandleError>500     fn try_from(handle_or_invalid: HandleOrInvalid) -> Result<Self, InvalidHandleError> {
501         let raw = handle_or_invalid.0;
502         if raw as HANDLE == INVALID_HANDLE_VALUE {
503             // Don't call `CloseHandle`; it'd be harmless, except that it could
504             // overwrite the `GetLastError` error.
505             forget(handle_or_invalid);
506 
507             Err(InvalidHandleError(()))
508         } else {
509             Ok(OwnedHandle { handle: raw })
510         }
511     }
512 }
513 
514 #[cfg(windows)]
515 impl TryFrom<HandleOrNull> for OwnedHandle {
516     type Error = NullHandleError;
517 
518     #[inline]
try_from(handle_or_null: HandleOrNull) -> Result<Self, NullHandleError>519     fn try_from(handle_or_null: HandleOrNull) -> Result<Self, NullHandleError> {
520         let raw = handle_or_null.0;
521         if raw.is_null() {
522             // Don't call `CloseHandle`; it'd be harmless, except that it could
523             // overwrite the `GetLastError` error.
524             forget(handle_or_null);
525 
526             Err(NullHandleError(()))
527         } else {
528             Ok(OwnedHandle { handle: raw })
529         }
530     }
531 }
532 
533 /// This is the error type used by [`HandleOrNull`] when attempting to convert
534 /// into a handle, to indicate that the value is null.
535 #[derive(Debug, Clone, PartialEq, Eq)]
536 pub struct NullHandleError(());
537 
538 impl fmt::Display for NullHandleError {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result539     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
540         "A HandleOrNull could not be converted to a handle because it was null".fmt(fmt)
541     }
542 }
543 
544 impl std::error::Error for NullHandleError {}
545 
546 /// This is the error type used by [`HandleOrInvalid`] when attempting to
547 /// convert into a handle, to indicate that the value is
548 /// `INVALID_HANDLE_VALUE`.
549 #[derive(Debug, Clone, PartialEq, Eq)]
550 pub struct InvalidHandleError(());
551 
552 impl fmt::Display for InvalidHandleError {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result553     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
554         "A HandleOrInvalid could not be converted to a handle because it was INVALID_HANDLE_VALUE"
555             .fmt(fmt)
556     }
557 }
558 
559 impl std::error::Error for InvalidHandleError {}
560 
561 #[cfg(any(unix, target_os = "wasi"))]
562 impl AsRawFd for BorrowedFd<'_> {
563     #[inline]
as_raw_fd(&self) -> RawFd564     fn as_raw_fd(&self) -> RawFd {
565         self.fd
566     }
567 }
568 
569 #[cfg(windows)]
570 impl AsRawHandle for BorrowedHandle<'_> {
571     #[inline]
as_raw_handle(&self) -> RawHandle572     fn as_raw_handle(&self) -> RawHandle {
573         self.handle
574     }
575 }
576 
577 #[cfg(windows)]
578 impl AsRawSocket for BorrowedSocket<'_> {
579     #[inline]
as_raw_socket(&self) -> RawSocket580     fn as_raw_socket(&self) -> RawSocket {
581         self.socket
582     }
583 }
584 
585 #[cfg(any(unix, target_os = "wasi"))]
586 impl AsRawFd for OwnedFd {
587     #[inline]
as_raw_fd(&self) -> RawFd588     fn as_raw_fd(&self) -> RawFd {
589         self.fd
590     }
591 }
592 
593 #[cfg(windows)]
594 impl AsRawHandle for OwnedHandle {
595     #[inline]
as_raw_handle(&self) -> RawHandle596     fn as_raw_handle(&self) -> RawHandle {
597         self.handle
598     }
599 }
600 
601 #[cfg(windows)]
602 impl AsRawSocket for OwnedSocket {
603     #[inline]
as_raw_socket(&self) -> RawSocket604     fn as_raw_socket(&self) -> RawSocket {
605         self.socket
606     }
607 }
608 
609 #[cfg(any(unix, target_os = "wasi"))]
610 impl IntoRawFd for OwnedFd {
611     #[inline]
into_raw_fd(self) -> RawFd612     fn into_raw_fd(self) -> RawFd {
613         let fd = self.fd;
614         forget(self);
615         fd
616     }
617 }
618 
619 #[cfg(windows)]
620 impl IntoRawHandle for OwnedHandle {
621     #[inline]
into_raw_handle(self) -> RawHandle622     fn into_raw_handle(self) -> RawHandle {
623         let handle = self.handle;
624         forget(self);
625         handle
626     }
627 }
628 
629 #[cfg(windows)]
630 impl IntoRawSocket for OwnedSocket {
631     #[inline]
into_raw_socket(self) -> RawSocket632     fn into_raw_socket(self) -> RawSocket {
633         let socket = self.socket;
634         forget(self);
635         socket
636     }
637 }
638 
639 #[cfg(any(unix, target_os = "wasi"))]
640 impl FromRawFd for OwnedFd {
641     /// Constructs a new instance of `Self` from the given raw file descriptor.
642     ///
643     /// # Safety
644     ///
645     /// The resource pointed to by `raw` must be open and suitable for assuming
646     /// ownership.
647     #[inline]
from_raw_fd(fd: RawFd) -> Self648     unsafe fn from_raw_fd(fd: RawFd) -> Self {
649         debug_assert_ne!(fd, -1_i32 as RawFd);
650         Self { fd }
651     }
652 }
653 
654 #[cfg(windows)]
655 impl FromRawHandle for OwnedHandle {
656     #[inline]
from_raw_handle(handle: RawHandle) -> Self657     unsafe fn from_raw_handle(handle: RawHandle) -> Self {
658         Self { handle }
659     }
660 }
661 
662 #[cfg(windows)]
663 impl FromRawSocket for OwnedSocket {
664     #[inline]
from_raw_socket(socket: RawSocket) -> Self665     unsafe fn from_raw_socket(socket: RawSocket) -> Self {
666         debug_assert_ne!(socket, INVALID_SOCKET as RawSocket);
667         Self { socket }
668     }
669 }
670 
671 #[cfg(windows)]
672 impl HandleOrInvalid {
673     /// Constructs a new instance of `Self` from the given `RawHandle` returned
674     /// from a Windows API that uses `INVALID_HANDLE_VALUE` to indicate
675     /// failure, such as `CreateFileW`.
676     ///
677     /// Use `HandleOrNull` instead of `HandleOrInvalid` for APIs that
678     /// use null to indicate failure.
679     ///
680     /// # Safety
681     ///
682     /// The passed `handle` value must either satisfy the safety requirements
683     /// of [`FromRawHandle::from_raw_handle`], or be
684     /// `INVALID_HANDLE_VALUE` (-1). Note that not all Windows APIs use
685     /// `INVALID_HANDLE_VALUE` for errors; see [here] for the full story.
686     ///
687     /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
688     #[inline]
from_raw_handle(handle: RawHandle) -> Self689     pub unsafe fn from_raw_handle(handle: RawHandle) -> Self {
690         Self(handle)
691     }
692 }
693 
694 #[cfg(windows)]
695 impl HandleOrNull {
696     /// Constructs a new instance of `Self` from the given `RawHandle` returned
697     /// from a Windows API that uses null to indicate failure, such as
698     /// `CreateThread`.
699     ///
700     /// Use `HandleOrInvalid` instead of `HandleOrNull` for APIs that
701     /// use `INVALID_HANDLE_VALUE` to indicate failure.
702     ///
703     /// # Safety
704     ///
705     /// The passed `handle` value must either satisfy the safety requirements
706     /// of [`FromRawHandle::from_raw_handle`], or be null. Note that not all
707     /// Windows APIs use null for errors; see [here] for the full story.
708     ///
709     /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
710     #[inline]
from_raw_handle(handle: RawHandle) -> Self711     pub unsafe fn from_raw_handle(handle: RawHandle) -> Self {
712         Self(handle)
713     }
714 }
715 
716 #[cfg(any(unix, target_os = "wasi"))]
717 impl Drop for OwnedFd {
718     #[inline]
drop(&mut self)719     fn drop(&mut self) {
720         #[cfg(feature = "close")]
721         unsafe {
722             let _ = libc::close(self.fd as std::os::raw::c_int);
723         }
724 
725         // If the `close` feature is disabled, we expect users to avoid letting
726         // `OwnedFd` instances drop, so that we don't have to call `close`.
727         #[cfg(not(feature = "close"))]
728         {
729             unreachable!("drop called without the \"close\" feature in io-lifetimes");
730         }
731     }
732 }
733 
734 #[cfg(windows)]
735 impl Drop for OwnedHandle {
736     #[inline]
drop(&mut self)737     fn drop(&mut self) {
738         #[cfg(feature = "close")]
739         unsafe {
740             let _ = CloseHandle(self.handle as HANDLE);
741         }
742 
743         // If the `close` feature is disabled, we expect users to avoid letting
744         // `OwnedHandle` instances drop, so that we don't have to call `close`.
745         #[cfg(not(feature = "close"))]
746         {
747             unreachable!("drop called without the \"close\" feature in io-lifetimes");
748         }
749     }
750 }
751 
752 #[cfg(windows)]
753 impl Drop for HandleOrInvalid {
754     #[inline]
drop(&mut self)755     fn drop(&mut self) {
756         #[cfg(feature = "close")]
757         unsafe {
758             let _ = CloseHandle(self.0 as HANDLE);
759         }
760 
761         // If the `close` feature is disabled, we expect users to avoid letting
762         // `HandleOrInvalid` instances drop, so that we don't have to call `close`.
763         #[cfg(not(feature = "close"))]
764         {
765             unreachable!("drop called without the \"close\" feature in io-lifetimes");
766         }
767     }
768 }
769 
770 #[cfg(windows)]
771 impl Drop for HandleOrNull {
772     #[inline]
drop(&mut self)773     fn drop(&mut self) {
774         #[cfg(feature = "close")]
775         unsafe {
776             let _ = CloseHandle(self.0 as HANDLE);
777         }
778 
779         // If the `close` feature is disabled, we expect users to avoid letting
780         // `HandleOrNull` instances drop, so that we don't have to call `close`.
781         #[cfg(not(feature = "close"))]
782         {
783             unreachable!("drop called without the \"close\" feature in io-lifetimes");
784         }
785     }
786 }
787 
788 #[cfg(windows)]
789 impl Drop for OwnedSocket {
790     #[inline]
drop(&mut self)791     fn drop(&mut self) {
792         #[cfg(feature = "close")]
793         unsafe {
794             let _ = closesocket(self.socket as SOCKET);
795         }
796 
797         // If the `close` feature is disabled, we expect users to avoid letting
798         // `OwnedSocket` instances drop, so that we don't have to call `close`.
799         #[cfg(not(feature = "close"))]
800         {
801             unreachable!("drop called without the \"close\" feature in io-lifetimes");
802         }
803     }
804 }
805 
806 #[cfg(any(unix, target_os = "wasi"))]
807 impl fmt::Debug for BorrowedFd<'_> {
808     #[allow(clippy::missing_inline_in_public_items)]
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result809     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
810         f.debug_struct("BorrowedFd").field("fd", &self.fd).finish()
811     }
812 }
813 
814 #[cfg(windows)]
815 impl fmt::Debug for BorrowedHandle<'_> {
816     #[allow(clippy::missing_inline_in_public_items)]
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result817     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
818         f.debug_struct("BorrowedHandle")
819             .field("handle", &self.handle)
820             .finish()
821     }
822 }
823 
824 #[cfg(windows)]
825 impl fmt::Debug for BorrowedSocket<'_> {
826     #[allow(clippy::missing_inline_in_public_items)]
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result827     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
828         f.debug_struct("BorrowedSocket")
829             .field("socket", &self.socket)
830             .finish()
831     }
832 }
833 
834 #[cfg(any(unix, target_os = "wasi"))]
835 impl fmt::Debug for OwnedFd {
836     #[allow(clippy::missing_inline_in_public_items)]
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result837     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
838         f.debug_struct("OwnedFd").field("fd", &self.fd).finish()
839     }
840 }
841 
842 #[cfg(windows)]
843 impl fmt::Debug for OwnedHandle {
844     #[allow(clippy::missing_inline_in_public_items)]
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result845     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
846         f.debug_struct("OwnedHandle")
847             .field("handle", &self.handle)
848             .finish()
849     }
850 }
851 
852 #[cfg(windows)]
853 impl fmt::Debug for OwnedSocket {
854     #[allow(clippy::missing_inline_in_public_items)]
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result855     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
856         f.debug_struct("OwnedSocket")
857             .field("socket", &self.socket)
858             .finish()
859     }
860 }
861