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 36mod portability; 37mod traits; 38#[cfg(not(io_safety_is_in_std))] 39mod types; 40 41#[cfg(not(io_safety_is_in_std))] 42mod impls_std; 43 44#[cfg(not(io_safety_is_in_std))] 45#[cfg(any(unix, target_os = "wasi"))] 46pub use traits::AsFd; 47#[cfg(not(io_safety_is_in_std))] 48#[cfg(windows)] 49pub use traits::{AsHandle, AsSocket}; 50#[cfg(any(unix, target_os = "wasi"))] 51#[allow(deprecated)] 52pub use traits::{FromFd, IntoFd}; 53#[cfg(windows)] 54#[allow(deprecated)] 55pub use traits::{FromHandle, FromSocket, IntoHandle, IntoSocket}; 56 57#[cfg(not(io_safety_is_in_std))] 58#[cfg(any(unix, target_os = "wasi"))] 59pub use types::{BorrowedFd, OwnedFd}; 60#[cfg(not(io_safety_is_in_std))] 61#[cfg(windows)] 62pub use types::{ 63 BorrowedHandle, BorrowedSocket, HandleOrInvalid, InvalidHandleError, NullHandleError, 64 OwnedHandle, OwnedSocket, 65}; 66 67#[cfg(io_safety_is_in_std)] 68#[cfg(unix)] 69pub use std::os::unix::io::{AsFd, BorrowedFd, OwnedFd}; 70#[cfg(io_safety_is_in_std)] 71#[cfg(target_os = "wasi")] 72pub use std::os::wasi::io::{AsFd, BorrowedFd, OwnedFd}; 73#[cfg(io_safety_is_in_std)] 74#[cfg(windows)] 75pub 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)] 94impl<T: From<OwnedFd>> FromFd for T { 95 #[inline] 96 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)] 103impl<T> IntoFd for T 104where 105 OwnedFd: From<T>, 106{ 107 #[inline] 108 fn into_fd(self) -> OwnedFd { 109 self.into() 110 } 111} 112 113#[cfg(io_safety_is_in_std)] 114#[cfg(windows)] 115#[allow(deprecated)] 116impl<T: From<OwnedHandle>> FromHandle for T { 117 #[inline] 118 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)] 125impl<T> IntoHandle for T 126where 127 OwnedHandle: From<T>, 128{ 129 #[inline] 130 fn into_handle(self) -> OwnedHandle { 131 self.into() 132 } 133} 134 135#[cfg(io_safety_is_in_std)] 136#[cfg(windows)] 137#[allow(deprecated)] 138impl<T: From<OwnedSocket>> FromSocket for T { 139 #[inline] 140 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)] 147impl<T> IntoSocket for T 148where 149 OwnedSocket: From<T>, 150{ 151 #[inline] 152 fn into_socket(self) -> OwnedSocket { 153 self.into() 154 } 155} 156 157pub use portability::{ 158 AsFilelike, AsSocketlike, BorrowedFilelike, BorrowedSocketlike, FromFilelike, FromSocketlike, 159 IntoFilelike, IntoSocketlike, OwnedFilelike, OwnedSocketlike, 160}; 161 162#[cfg(feature = "close")] 163pub mod example_ffi; 164pub mod raw; 165pub 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")] 171mod impls_async_std; 172#[cfg(not(io_safety_is_in_std))] 173#[cfg(feature = "fs-err")] 174mod impls_fs_err; 175#[cfg(not(io_safety_is_in_std))] 176#[cfg(feature = "mio")] 177mod impls_mio; 178#[cfg(not(target_os = "wasi"))] 179#[cfg(not(io_safety_is_in_std))] 180#[cfg(feature = "os_pipe")] 181mod impls_os_pipe; 182#[cfg(not(io_safety_is_in_std))] 183#[cfg(feature = "socket2")] 184mod impls_socket2; 185#[cfg(not(io_safety_is_in_std))] 186#[cfg(feature = "tokio")] 187mod impls_tokio; 188