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