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
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", target_os = "hermit"))]
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", target_os = "hermit"))]
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", target_os = "hermit"))]
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(target_os = "hermit")]
69pub use std::os::hermit::io::{AsFd, BorrowedFd, OwnedFd};
70#[cfg(io_safety_is_in_std)]
71#[cfg(unix)]
72pub use std::os::unix::io::{AsFd, BorrowedFd, OwnedFd};
73#[cfg(io_safety_is_in_std)]
74#[cfg(target_os = "wasi")]
75pub use std::os::wasi::io::{AsFd, BorrowedFd, OwnedFd};
76#[cfg(io_safety_is_in_std)]
77#[cfg(windows)]
78pub 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)]
97impl<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)]
106impl<T> IntoFd for T
107where
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)]
119impl<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)]
128impl<T> IntoHandle for T
129where
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)]
141impl<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)]
150impl<T> IntoSocket for T
151where
152 OwnedSocket: From<T>,
153{
154 #[inline]
155 fn into_socket(self) -> OwnedSocket {
156 self.into()
157 }
158}
159
160pub use portability::{
161 AsFilelike, AsSocketlike, BorrowedFilelike, BorrowedSocketlike, FromFilelike, FromSocketlike,
162 IntoFilelike, IntoSocketlike, OwnedFilelike, OwnedSocketlike,
163};
164
165#[cfg(feature = "close")]
166pub mod example_ffi;
167pub mod raw;
168pub 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")]
174mod impls_async_std;
175#[cfg(not(io_safety_is_in_std))]
176#[cfg(feature = "fs-err")]
177mod impls_fs_err;
178#[cfg(not(io_safety_is_in_std))]
179#[cfg(feature = "mio")]
180mod impls_mio;
181#[cfg(not(target_os = "wasi"))]
182#[cfg(not(io_safety_is_in_std))]
183#[cfg(feature = "os_pipe")]
184mod impls_os_pipe;
185#[cfg(not(io_safety_is_in_std))]
186#[cfg(feature = "socket2")]
187mod impls_socket2;
188#[cfg(not(io_safety_is_in_std))]
189#[cfg(feature = "tokio")]
190mod impls_tokio;
191