]>
Commit | Line | Data |
---|---|---|
064997fb FG |
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 | ||
8 | use crate::raw::{ | |
9 | AsRawFilelike, AsRawSocketlike, FromRawFilelike, FromRawSocketlike, IntoRawFilelike, | |
10 | IntoRawSocketlike, RawFilelike, RawSocketlike, | |
11 | }; | |
487cf647 FG |
12 | #[cfg(any(unix, target_os = "wasi"))] |
13 | use crate::OwnedFd; | |
064997fb FG |
14 | use crate::{ |
15 | AsFilelike, AsSocketlike, FromFilelike, FromSocketlike, IntoFilelike, IntoSocketlike, | |
16 | OwnedFilelike, OwnedSocketlike, | |
17 | }; | |
487cf647 FG |
18 | #[cfg(windows)] |
19 | use crate::{OwnedHandle, OwnedSocket}; | |
064997fb FG |
20 | use std::fmt; |
21 | use std::marker::PhantomData; | |
22 | use std::mem::ManuallyDrop; | |
23 | use 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`. | |
33 | pub 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`. | |
43 | pub 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`]. | |
47 | pub 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`]. | |
65 | pub 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 | ||
81 | impl<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 | ||
110 | impl<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 | ||
140 | impl<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 | ||
149 | impl<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 | ||
158 | impl<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 | ||
175 | impl<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 | ||
192 | impl<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 | ||
201 | impl<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 | } | |
487cf647 FG |
209 | |
210 | #[cfg(any(unix, target_os = "wasi"))] | |
211 | unsafe impl FilelikeViewType for OwnedFd {} | |
212 | #[cfg(windows)] | |
213 | unsafe impl FilelikeViewType for OwnedHandle {} | |
214 | #[cfg(windows)] | |
215 | unsafe impl SocketlikeViewType for OwnedSocket {} | |
216 | unsafe impl FilelikeViewType for std::fs::File {} | |
217 | unsafe impl SocketlikeViewType for std::net::TcpStream {} | |
218 | unsafe impl SocketlikeViewType for std::net::TcpListener {} | |
219 | unsafe impl SocketlikeViewType for std::net::UdpSocket {} | |
220 | #[cfg(unix)] | |
221 | unsafe impl SocketlikeViewType for std::os::unix::net::UnixStream {} | |
222 | #[cfg(unix)] | |
223 | unsafe impl SocketlikeViewType for std::os::unix::net::UnixListener {} | |
224 | ||
225 | #[cfg(unix)] | |
226 | unsafe impl SocketlikeViewType for std::os::unix::net::UnixDatagram {} | |
227 | #[cfg(not(target_os = "wasi"))] | |
228 | #[cfg(feature = "os_pipe")] | |
229 | unsafe impl FilelikeViewType for os_pipe::PipeWriter {} | |
230 | #[cfg(not(target_os = "wasi"))] | |
231 | #[cfg(feature = "os_pipe")] | |
232 | unsafe impl FilelikeViewType for os_pipe::PipeReader {} | |
233 | ||
234 | #[cfg(not(target_os = "wasi"))] | |
235 | #[cfg(feature = "socket2")] | |
236 | unsafe impl SocketlikeViewType for socket2::Socket {} | |
237 | ||
238 | #[cfg(not(target_os = "wasi"))] | |
239 | #[cfg(feature = "async_std")] | |
240 | unsafe impl SocketlikeViewType for async_std::net::TcpStream {} | |
241 | #[cfg(not(target_os = "wasi"))] | |
242 | #[cfg(feature = "async_std")] | |
243 | unsafe impl SocketlikeViewType for async_std::net::TcpListener {} | |
244 | #[cfg(not(target_os = "wasi"))] | |
245 | #[cfg(feature = "async_std")] | |
246 | unsafe impl SocketlikeViewType for async_std::net::UdpSocket {} | |
247 | #[cfg(unix)] | |
248 | #[cfg(feature = "async_std")] | |
249 | unsafe impl SocketlikeViewType for async_std::os::unix::net::UnixStream {} | |
250 | #[cfg(unix)] | |
251 | #[cfg(feature = "async_std")] | |
252 | unsafe impl SocketlikeViewType for async_std::os::unix::net::UnixListener {} | |
253 | #[cfg(unix)] | |
254 | #[cfg(feature = "async_std")] | |
255 | unsafe impl SocketlikeViewType for async_std::os::unix::net::UnixDatagram {} | |
256 | ||
257 | #[cfg(feature = "mio")] | |
258 | unsafe impl SocketlikeViewType for mio::net::TcpStream {} | |
259 | #[cfg(feature = "mio")] | |
260 | unsafe impl SocketlikeViewType for mio::net::TcpListener {} | |
261 | #[cfg(feature = "mio")] | |
262 | unsafe impl SocketlikeViewType for mio::net::UdpSocket {} | |
263 | #[cfg(unix)] | |
264 | #[cfg(feature = "mio")] | |
265 | unsafe impl SocketlikeViewType for mio::net::UnixDatagram {} | |
266 | #[cfg(unix)] | |
267 | #[cfg(feature = "mio")] | |
268 | unsafe impl SocketlikeViewType for mio::net::UnixListener {} | |
269 | #[cfg(unix)] | |
270 | #[cfg(feature = "mio")] | |
271 | unsafe impl SocketlikeViewType for mio::net::UnixStream {} | |
272 | #[cfg(unix)] | |
273 | #[cfg(feature = "mio")] | |
274 | unsafe impl FilelikeViewType for mio::unix::pipe::Receiver {} | |
275 | #[cfg(unix)] | |
276 | #[cfg(feature = "mio")] | |
277 | unsafe impl FilelikeViewType for mio::unix::pipe::Sender {} |