Chris Wailes | cd1aefd | 2023-07-13 13:36:21 -0700 | [diff] [blame^] | 1 | //! Experimental new types and traits to replace the `Raw` family of types and |
| 2 | //! traits. |
| 3 | //! |
| 4 | //! This API has much conceptual similarity with the `Raw` API, but introduces |
| 5 | //! explicit concepts of ownership and borrowing: |
| 6 | //! |
| 7 | //! | `Raw` API | This experimental API | |
| 8 | //! | ---------- | ------------------------ | |
| 9 | //! | `Raw*` | `Borrowed*` and `Owned*` | |
| 10 | //! | `AsRaw*` | `As*` | |
| 11 | //! | `IntoRaw*` | `Into*` | |
| 12 | //! | `FromRaw*` | `From*` | |
| 13 | //! |
| 14 | //! This gives it several advantages: |
| 15 | //! |
| 16 | //! - Less `unsafe` in user code! |
| 17 | //! |
| 18 | //! - Easier to understand ownership. |
| 19 | //! |
| 20 | //! - It avoids the inconsistency where `AsRawFd` and `IntoRawFd` return |
| 21 | //! `RawFd` values that users ought to be able to trust, but aren't unsafe, |
| 22 | //! so it's possible to fail to uphold this trust in purely safe Rust. |
| 23 | //! |
| 24 | //! - It enables a number of safe and portable convenience features, such as |
| 25 | //! [safe typed views] and [from+into conversions]. |
| 26 | //! |
| 27 | //! [safe typed views]: AsFilelike::as_filelike_view |
| 28 | //! [from+into conversions]: FromFilelike::from_into_filelike |
| 29 | |
| 30 | #![deny(missing_docs)] |
| 31 | // Work around <https://github.com/rust-lang/rust/issues/103306>. |
| 32 | #![cfg_attr(all(wasi_ext, target_os = "wasi"), feature(wasi_ext))] |
| 33 | // Currently supported platforms. |
| 34 | #![cfg(any(unix, windows, target_os = "wasi", target_os = "hermit"))] |
| 35 | |
| 36 | mod portability; |
| 37 | mod traits; |
| 38 | #[cfg(not(io_safety_is_in_std))] |
| 39 | mod types; |
| 40 | |
| 41 | #[cfg(not(io_safety_is_in_std))] |
| 42 | mod impls_std; |
| 43 | |
| 44 | #[cfg(not(io_safety_is_in_std))] |
| 45 | #[cfg(any(unix, target_os = "wasi", target_os = "hermit"))] |
| 46 | pub use traits::AsFd; |
| 47 | #[cfg(not(io_safety_is_in_std))] |
| 48 | #[cfg(windows)] |
| 49 | pub use traits::{AsHandle, AsSocket}; |
| 50 | #[cfg(any(unix, target_os = "wasi", target_os = "hermit"))] |
| 51 | #[allow(deprecated)] |
| 52 | pub use traits::{FromFd, IntoFd}; |
| 53 | #[cfg(windows)] |
| 54 | #[allow(deprecated)] |
| 55 | pub use traits::{FromHandle, FromSocket, IntoHandle, IntoSocket}; |
| 56 | |
| 57 | #[cfg(not(io_safety_is_in_std))] |
| 58 | #[cfg(any(unix, target_os = "wasi", target_os = "hermit"))] |
| 59 | pub use types::{BorrowedFd, OwnedFd}; |
| 60 | #[cfg(not(io_safety_is_in_std))] |
| 61 | #[cfg(windows)] |
| 62 | pub use types::{ |
| 63 | BorrowedHandle, BorrowedSocket, HandleOrInvalid, InvalidHandleError, NullHandleError, |
| 64 | OwnedHandle, OwnedSocket, |
| 65 | }; |
| 66 | |
| 67 | #[cfg(io_safety_is_in_std)] |
| 68 | #[cfg(target_os = "hermit")] |
| 69 | pub use std::os::hermit::io::{AsFd, BorrowedFd, OwnedFd}; |
| 70 | #[cfg(io_safety_is_in_std)] |
| 71 | #[cfg(unix)] |
| 72 | pub use std::os::unix::io::{AsFd, BorrowedFd, OwnedFd}; |
| 73 | #[cfg(io_safety_is_in_std)] |
| 74 | #[cfg(target_os = "wasi")] |
| 75 | pub use std::os::wasi::io::{AsFd, BorrowedFd, OwnedFd}; |
| 76 | #[cfg(io_safety_is_in_std)] |
| 77 | #[cfg(windows)] |
| 78 | pub use std::os::windows::io::{ |
| 79 | AsHandle, AsSocket, BorrowedHandle, BorrowedSocket, HandleOrInvalid, InvalidHandleError, |
| 80 | NullHandleError, OwnedHandle, OwnedSocket, |
| 81 | }; |
| 82 | |
| 83 | // io-lifetimes defined `FromFd`/`IntoFd` traits instead of just using |
| 84 | // `From`/`Into` because that allowed it to implement them for foreign types, |
| 85 | // including std types like File and TcpStream, and popular third-party types. |
| 86 | // |
| 87 | // std just uses `From`/`Into`, because it defines those traits itself so it |
| 88 | // can implement them for std types itself, and std won't be implementing them |
| 89 | // for third-party types. However, this means that until `OwnedFd` et al are |
| 90 | // stabilized, there will be no impls for third-party traits. |
| 91 | // |
| 92 | // So we define `FromFd`/`IntoFd` traits, and implement them in terms of |
| 93 | // `From`/`Into`, |
| 94 | #[cfg(io_safety_is_in_std)] |
| 95 | #[cfg(any(unix, target_os = "wasi", target_os = "hermit"))] |
| 96 | #[allow(deprecated)] |
| 97 | impl<T: From<OwnedFd>> FromFd for T { |
| 98 | #[inline] |
| 99 | fn from_fd(owned_fd: OwnedFd) -> Self { |
| 100 | owned_fd.into() |
| 101 | } |
| 102 | } |
| 103 | #[cfg(io_safety_is_in_std)] |
| 104 | #[cfg(any(unix, target_os = "wasi", target_os = "hermit"))] |
| 105 | #[allow(deprecated)] |
| 106 | impl<T> IntoFd for T |
| 107 | where |
| 108 | OwnedFd: From<T>, |
| 109 | { |
| 110 | #[inline] |
| 111 | fn into_fd(self) -> OwnedFd { |
| 112 | self.into() |
| 113 | } |
| 114 | } |
| 115 | |
| 116 | #[cfg(io_safety_is_in_std)] |
| 117 | #[cfg(windows)] |
| 118 | #[allow(deprecated)] |
| 119 | impl<T: From<OwnedHandle>> FromHandle for T { |
| 120 | #[inline] |
| 121 | fn from_handle(owned_handle: OwnedHandle) -> Self { |
| 122 | owned_handle.into() |
| 123 | } |
| 124 | } |
| 125 | #[cfg(io_safety_is_in_std)] |
| 126 | #[cfg(windows)] |
| 127 | #[allow(deprecated)] |
| 128 | impl<T> IntoHandle for T |
| 129 | where |
| 130 | OwnedHandle: From<T>, |
| 131 | { |
| 132 | #[inline] |
| 133 | fn into_handle(self) -> OwnedHandle { |
| 134 | self.into() |
| 135 | } |
| 136 | } |
| 137 | |
| 138 | #[cfg(io_safety_is_in_std)] |
| 139 | #[cfg(windows)] |
| 140 | #[allow(deprecated)] |
| 141 | impl<T: From<OwnedSocket>> FromSocket for T { |
| 142 | #[inline] |
| 143 | fn from_socket(owned_socket: OwnedSocket) -> Self { |
| 144 | owned_socket.into() |
| 145 | } |
| 146 | } |
| 147 | #[cfg(io_safety_is_in_std)] |
| 148 | #[cfg(windows)] |
| 149 | #[allow(deprecated)] |
| 150 | impl<T> IntoSocket for T |
| 151 | where |
| 152 | OwnedSocket: From<T>, |
| 153 | { |
| 154 | #[inline] |
| 155 | fn into_socket(self) -> OwnedSocket { |
| 156 | self.into() |
| 157 | } |
| 158 | } |
| 159 | |
| 160 | pub use portability::{ |
| 161 | AsFilelike, AsSocketlike, BorrowedFilelike, BorrowedSocketlike, FromFilelike, FromSocketlike, |
| 162 | IntoFilelike, IntoSocketlike, OwnedFilelike, OwnedSocketlike, |
| 163 | }; |
| 164 | |
| 165 | #[cfg(feature = "close")] |
| 166 | pub mod example_ffi; |
| 167 | pub mod raw; |
| 168 | pub mod views; |
| 169 | |
| 170 | // Ideally, we'd want crates to implement our traits themselves. But for now, |
| 171 | // while we're prototyping, we provide a few impls on foreign types. |
| 172 | #[cfg(not(io_safety_is_in_std))] |
| 173 | #[cfg(feature = "async-std")] |
| 174 | mod impls_async_std; |
| 175 | #[cfg(not(io_safety_is_in_std))] |
| 176 | #[cfg(feature = "fs-err")] |
| 177 | mod impls_fs_err; |
| 178 | #[cfg(not(io_safety_is_in_std))] |
| 179 | #[cfg(feature = "mio")] |
| 180 | mod impls_mio; |
| 181 | #[cfg(not(target_os = "wasi"))] |
| 182 | #[cfg(not(io_safety_is_in_std))] |
| 183 | #[cfg(feature = "os_pipe")] |
| 184 | mod impls_os_pipe; |
| 185 | #[cfg(not(io_safety_is_in_std))] |
| 186 | #[cfg(feature = "socket2")] |
| 187 | mod impls_socket2; |
| 188 | #[cfg(not(io_safety_is_in_std))] |
| 189 | #[cfg(feature = "tokio")] |
| 190 | mod impls_tokio; |