io_lifetimes/
views.rs

1//! Typed views using temporary objects.
2//!
3//! This module defines the return types for [`AsFilelike::as_filelike_view`]
4//! and [`AsSocketlike::as_socketlike_view`].
5//!
6//! [`AsSocketlike::as_socketlike_view`]: crate::AsSocketlike::as_socketlike_view
7
8use crate::raw::{
9    AsRawFilelike, AsRawSocketlike, FromRawFilelike, FromRawSocketlike, IntoRawFilelike,
10    IntoRawSocketlike, RawFilelike, RawSocketlike,
11};
12#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
13use crate::OwnedFd;
14use crate::{
15    AsFilelike, AsSocketlike, FromFilelike, FromSocketlike, IntoFilelike, IntoSocketlike,
16    OwnedFilelike, OwnedSocketlike,
17};
18#[cfg(windows)]
19use crate::{OwnedHandle, OwnedSocket};
20use std::fmt;
21use std::marker::PhantomData;
22use std::mem::ManuallyDrop;
23use std::ops::Deref;
24
25/// Declare that a type is safe to use in a [`FilelikeView`].
26///
27/// # Safety
28///
29/// Types implementing this trait declare that if they are constructed with
30/// [`FromFilelike`] and consumed with [`IntoFilelike`], their `IntoFilelike`
31/// will return the same `OwnedFd` value that was passed to their
32/// `FromFilelike`.
33pub unsafe trait FilelikeViewType: FromFilelike + IntoFilelike {}
34
35/// Declare that a type is safe to use in a [`SocketlikeView`].
36///
37/// # Safety
38///
39/// Types implementing this trait declare that if they are constructed with
40/// [`FromSocketlike`] and consumed with [`IntoSocketlike`], their
41/// `IntoSocketlike` will return the same `OwnedFd` value that was passed to
42/// their `FromSocketlike`.
43pub unsafe trait SocketlikeViewType: FromSocketlike + IntoSocketlike {}
44
45/// A non-owning view of a resource which dereferences to a `&Target` or
46/// `&mut Target`. These are returned by [`AsFilelike::as_filelike_view`].
47pub struct FilelikeView<'filelike, Target: FilelikeViewType> {
48    /// The value to dereference to. This is a `ManuallyDrop` so that we can
49    /// consume it in our `Drop` impl.
50    target: ManuallyDrop<Target>,
51
52    /// `FilelikeViewType` implementors guarantee that their `Into<OwnedFd>`
53    /// returns the same fd as their `From<OwnedFd>` gave them. This field
54    /// allows us to verify this.
55    #[cfg(debug_assertions)]
56    orig: RawFilelike,
57
58    /// This field exists because we don't otherwise explicitly use
59    /// `'filelike`.
60    _phantom: PhantomData<&'filelike OwnedFilelike>,
61}
62
63/// A non-owning view of a resource which dereferences to a `&Target` or
64/// `&mut Target`. These are returned by [`AsSocketlike::as_socketlike_view`].
65pub struct SocketlikeView<'socketlike, Target: SocketlikeViewType> {
66    /// The value to dereference to. This is a `ManuallyDrop` so that we can
67    /// consume it in our `Drop` impl.
68    target: ManuallyDrop<Target>,
69
70    /// `SocketlikeViewType` implementors guarantee that their `Into<OwnedFd>`
71    /// returns the same fd as their `From<OwnedFd>` gave them. This field
72    /// allows us to verify this.
73    #[cfg(debug_assertions)]
74    orig: RawSocketlike,
75
76    /// This field exists because we don't otherwise explicitly use
77    /// `'socketlike`.
78    _phantom: PhantomData<&'socketlike OwnedSocketlike>,
79}
80
81impl<Target: FilelikeViewType> FilelikeView<'_, Target> {
82    /// Construct a temporary `Target` and wrap it in a `FilelikeView` object.
83    #[inline]
84    pub(crate) fn new<T: AsFilelike>(filelike: &T) -> Self {
85        // Safety: The returned `FilelikeView` is scoped to the lifetime of
86        // `filelike`, which we've borrowed here, so the view won't outlive
87        // the object it's borrowed from.
88        unsafe { Self::view_raw(filelike.as_filelike().as_raw_filelike()) }
89    }
90
91    /// Construct a temporary `Target` from raw and wrap it in a `FilelikeView`
92    /// object.
93    ///
94    /// # Safety
95    ///
96    /// `raw` must be a valid raw filelike referencing a resource that outlives
97    /// the resulting view.
98    #[inline]
99    pub unsafe fn view_raw(raw: RawFilelike) -> Self {
100        let owned = OwnedFilelike::from_raw_filelike(raw);
101        Self {
102            target: ManuallyDrop::new(Target::from_filelike(owned)),
103            #[cfg(debug_assertions)]
104            orig: raw,
105            _phantom: PhantomData,
106        }
107    }
108}
109
110impl<Target: SocketlikeViewType> SocketlikeView<'_, Target> {
111    /// Construct a temporary `Target` and wrap it in a `SocketlikeView`
112    /// object.
113    #[inline]
114    pub(crate) fn new<T: AsSocketlike>(socketlike: &T) -> Self {
115        // Safety: The returned `SocketlikeView` is scoped to the lifetime of
116        // `socketlike`, which we've borrowed here, so the view won't outlive
117        // the object it's borrowed from.
118        unsafe { Self::view_raw(socketlike.as_socketlike().as_raw_socketlike()) }
119    }
120
121    /// Construct a temporary `Target` from raw and wrap it in a
122    /// `SocketlikeView` object.
123    ///
124    /// # Safety
125    ///
126    /// `raw` must be a valid raw socketlike referencing a resource that
127    /// outlives the resulting view.
128    #[inline]
129    pub unsafe fn view_raw(raw: RawSocketlike) -> Self {
130        let owned = OwnedSocketlike::from_raw_socketlike(raw);
131        Self {
132            target: ManuallyDrop::new(Target::from_socketlike(owned)),
133            #[cfg(debug_assertions)]
134            orig: raw,
135            _phantom: PhantomData,
136        }
137    }
138}
139
140impl<Target: FilelikeViewType> Deref for FilelikeView<'_, Target> {
141    type Target = Target;
142
143    #[inline]
144    fn deref(&self) -> &Self::Target {
145        &self.target
146    }
147}
148
149impl<Target: SocketlikeViewType> Deref for SocketlikeView<'_, Target> {
150    type Target = Target;
151
152    #[inline]
153    fn deref(&self) -> &Self::Target {
154        &self.target
155    }
156}
157
158impl<Target: FilelikeViewType> Drop for FilelikeView<'_, Target> {
159    #[inline]
160    fn drop(&mut self) {
161        // Use `Into*` to consume `self.target` without freeing its resource.
162        //
163        // Safety: Using `ManuallyDrop::take` requires us to ensure that
164        // `self.target` is not used again. We don't use it again here, and
165        // this is the `drop` function, so we know it's not used afterward.
166        let _raw = unsafe { ManuallyDrop::take(&mut self.target) }
167            .into_filelike()
168            .into_raw_filelike();
169
170        #[cfg(debug_assertions)]
171        debug_assert_eq!(self.orig, _raw);
172    }
173}
174
175impl<Target: SocketlikeViewType> Drop for SocketlikeView<'_, Target> {
176    #[inline]
177    fn drop(&mut self) {
178        // Use `Into*` to consume `self.target` without freeing its resource.
179        //
180        // Safety: Using `ManuallyDrop::take` requires us to ensure that
181        // `self.target` is not used again. We don't use it again here, and
182        // this is the `drop` function, so we know it's not used afterward.
183        let _raw = unsafe { ManuallyDrop::take(&mut self.target) }
184            .into_socketlike()
185            .into_raw_socketlike();
186
187        #[cfg(debug_assertions)]
188        debug_assert_eq!(self.orig, _raw);
189    }
190}
191
192impl<Target: FilelikeViewType> fmt::Debug for FilelikeView<'_, Target> {
193    #[allow(clippy::missing_inline_in_public_items)]
194    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195        f.debug_struct("FilelikeView")
196            .field("target", &*self)
197            .finish()
198    }
199}
200
201impl<Target: SocketlikeViewType> fmt::Debug for SocketlikeView<'_, Target> {
202    #[allow(clippy::missing_inline_in_public_items)]
203    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204        f.debug_struct("SocketlikeView")
205            .field("target", &*self)
206            .finish()
207    }
208}
209
210#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
211unsafe impl FilelikeViewType for OwnedFd {}
212#[cfg(windows)]
213unsafe impl FilelikeViewType for OwnedHandle {}
214#[cfg(windows)]
215unsafe impl SocketlikeViewType for OwnedSocket {}
216unsafe impl FilelikeViewType for std::fs::File {}
217unsafe impl SocketlikeViewType for std::net::TcpStream {}
218unsafe impl SocketlikeViewType for std::net::TcpListener {}
219unsafe impl SocketlikeViewType for std::net::UdpSocket {}
220#[cfg(unix)]
221unsafe impl SocketlikeViewType for std::os::unix::net::UnixStream {}
222#[cfg(unix)]
223unsafe impl SocketlikeViewType for std::os::unix::net::UnixListener {}
224
225#[cfg(unix)]
226unsafe impl SocketlikeViewType for std::os::unix::net::UnixDatagram {}
227#[cfg(not(any(target_os = "wasi", target_os = "hermit")))]
228#[cfg(feature = "os_pipe")]
229unsafe impl FilelikeViewType for os_pipe::PipeWriter {}
230#[cfg(not(any(target_os = "wasi", target_os = "hermit")))]
231#[cfg(feature = "os_pipe")]
232unsafe impl FilelikeViewType for os_pipe::PipeReader {}
233
234#[cfg(not(any(target_os = "wasi", target_os = "hermit")))]
235#[cfg(feature = "socket2")]
236unsafe impl SocketlikeViewType for socket2::Socket {}
237
238#[cfg(not(any(target_os = "wasi", target_os = "hermit")))]
239#[cfg(feature = "async-std")]
240unsafe impl SocketlikeViewType for async_std::net::TcpStream {}
241#[cfg(not(any(target_os = "wasi", target_os = "hermit")))]
242#[cfg(feature = "async-std")]
243unsafe impl SocketlikeViewType for async_std::net::TcpListener {}
244#[cfg(not(any(target_os = "wasi", target_os = "hermit")))]
245#[cfg(feature = "async-std")]
246unsafe impl SocketlikeViewType for async_std::net::UdpSocket {}
247#[cfg(unix)]
248#[cfg(feature = "async-std")]
249unsafe impl SocketlikeViewType for async_std::os::unix::net::UnixStream {}
250#[cfg(unix)]
251#[cfg(feature = "async-std")]
252unsafe impl SocketlikeViewType for async_std::os::unix::net::UnixListener {}
253#[cfg(unix)]
254#[cfg(feature = "async-std")]
255unsafe impl SocketlikeViewType for async_std::os::unix::net::UnixDatagram {}
256
257#[cfg(feature = "mio")]
258unsafe impl SocketlikeViewType for mio::net::TcpStream {}
259#[cfg(feature = "mio")]
260unsafe impl SocketlikeViewType for mio::net::TcpListener {}
261#[cfg(feature = "mio")]
262unsafe impl SocketlikeViewType for mio::net::UdpSocket {}
263#[cfg(unix)]
264#[cfg(feature = "mio")]
265unsafe impl SocketlikeViewType for mio::net::UnixDatagram {}
266#[cfg(unix)]
267#[cfg(feature = "mio")]
268unsafe impl SocketlikeViewType for mio::net::UnixListener {}
269#[cfg(unix)]
270#[cfg(feature = "mio")]
271unsafe impl SocketlikeViewType for mio::net::UnixStream {}
272#[cfg(unix)]
273#[cfg(feature = "mio")]
274unsafe impl FilelikeViewType for mio::unix::pipe::Receiver {}
275#[cfg(unix)]
276#[cfg(feature = "mio")]
277unsafe impl FilelikeViewType for mio::unix::pipe::Sender {}