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"))] 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"))] 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"))] 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"))] 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(unix)] 69 pub use std::os::unix::io::{AsFd, BorrowedFd, OwnedFd}; 70 #[cfg(io_safety_is_in_std)] 71 #[cfg(target_os = "wasi")] 72 pub use std::os::wasi::io::{AsFd, BorrowedFd, OwnedFd}; 73 #[cfg(io_safety_is_in_std)] 74 #[cfg(windows)] 75 pub use std::os::windows::io::{ 76 AsHandle, AsSocket, BorrowedHandle, BorrowedSocket, HandleOrInvalid, InvalidHandleError, 77 NullHandleError, OwnedHandle, OwnedSocket, 78 }; 79 80 // io-lifetimes defined `FromFd`/`IntoFd` traits instead of just using 81 // `From`/`Into` because that allowed it to implement them for foreign types, 82 // including std types like File and TcpStream, and popular third-party types. 83 // 84 // std just uses `From`/`Into`, because it defines those traits itself so it 85 // can implement them for std types itself, and std won't be implementing them 86 // for third-party types. However, this means that until `OwnedFd` et al are 87 // stabilized, there will be no impls for third-party traits. 88 // 89 // So we define `FromFd`/`IntoFd` traits, and implement them in terms of 90 // `From`/`Into`, 91 #[cfg(io_safety_is_in_std)] 92 #[cfg(any(unix, target_os = "wasi"))] 93 #[allow(deprecated)] 94 impl<T: From<OwnedFd>> FromFd for T { 95 #[inline] from_fd(owned_fd: OwnedFd) -> Self96 fn from_fd(owned_fd: OwnedFd) -> Self { 97 owned_fd.into() 98 } 99 } 100 #[cfg(io_safety_is_in_std)] 101 #[cfg(any(unix, target_os = "wasi"))] 102 #[allow(deprecated)] 103 impl<T> IntoFd for T 104 where 105 OwnedFd: From<T>, 106 { 107 #[inline] into_fd(self) -> OwnedFd108 fn into_fd(self) -> OwnedFd { 109 self.into() 110 } 111 } 112 113 #[cfg(io_safety_is_in_std)] 114 #[cfg(windows)] 115 #[allow(deprecated)] 116 impl<T: From<OwnedHandle>> FromHandle for T { 117 #[inline] from_handle(owned_handle: OwnedHandle) -> Self118 fn from_handle(owned_handle: OwnedHandle) -> Self { 119 owned_handle.into() 120 } 121 } 122 #[cfg(io_safety_is_in_std)] 123 #[cfg(windows)] 124 #[allow(deprecated)] 125 impl<T> IntoHandle for T 126 where 127 OwnedHandle: From<T>, 128 { 129 #[inline] into_handle(self) -> OwnedHandle130 fn into_handle(self) -> OwnedHandle { 131 self.into() 132 } 133 } 134 135 #[cfg(io_safety_is_in_std)] 136 #[cfg(windows)] 137 #[allow(deprecated)] 138 impl<T: From<OwnedSocket>> FromSocket for T { 139 #[inline] from_socket(owned_socket: OwnedSocket) -> Self140 fn from_socket(owned_socket: OwnedSocket) -> Self { 141 owned_socket.into() 142 } 143 } 144 #[cfg(io_safety_is_in_std)] 145 #[cfg(windows)] 146 #[allow(deprecated)] 147 impl<T> IntoSocket for T 148 where 149 OwnedSocket: From<T>, 150 { 151 #[inline] into_socket(self) -> OwnedSocket152 fn into_socket(self) -> OwnedSocket { 153 self.into() 154 } 155 } 156 157 pub use portability::{ 158 AsFilelike, AsSocketlike, BorrowedFilelike, BorrowedSocketlike, FromFilelike, FromSocketlike, 159 IntoFilelike, IntoSocketlike, OwnedFilelike, OwnedSocketlike, 160 }; 161 162 #[cfg(feature = "close")] 163 pub mod example_ffi; 164 pub mod raw; 165 pub mod views; 166 167 // Ideally, we'd want crates to implement our traits themselves. But for now, 168 // while we're prototyping, we provide a few impls on foreign types. 169 #[cfg(not(io_safety_is_in_std))] 170 #[cfg(feature = "async-std")] 171 mod impls_async_std; 172 #[cfg(not(io_safety_is_in_std))] 173 #[cfg(feature = "fs-err")] 174 mod impls_fs_err; 175 #[cfg(not(io_safety_is_in_std))] 176 #[cfg(feature = "mio")] 177 mod impls_mio; 178 #[cfg(not(target_os = "wasi"))] 179 #[cfg(not(io_safety_is_in_std))] 180 #[cfg(feature = "os_pipe")] 181 mod impls_os_pipe; 182 #[cfg(not(io_safety_is_in_std))] 183 #[cfg(feature = "socket2")] 184 mod impls_socket2; 185 #[cfg(not(io_safety_is_in_std))] 186 #[cfg(feature = "tokio")] 187 mod impls_tokio; 188