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: i32 = unsafeOwnedFd { 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: i32 = unsafeOwnedFd { 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&mut DebugStruct<'_, '_>.debug_struct("FilelikeView")
196 .field(name:"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&mut DebugStruct<'_, '_>.debug_struct("SocketlikeView")
205 .field(name:"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 {}
278