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 | }; |
12 | #[cfg (any(unix, target_os = "wasi" , target_os = "hermit" ))] |
13 | use crate::OwnedFd; |
14 | use crate::{ |
15 | AsFilelike, AsSocketlike, FromFilelike, FromSocketlike, IntoFilelike, IntoSocketlike, |
16 | OwnedFilelike, OwnedSocketlike, |
17 | }; |
18 | #[cfg (windows)] |
19 | use crate::{OwnedHandle, OwnedSocket}; |
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: 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 | |
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: 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 | |
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&mut DebugStruct<'_, '_>.debug_struct("FilelikeView" ) |
196 | .field(name:"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&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" ))] |
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(any(target_os = "wasi" , target_os = "hermit" )))] |
228 | #[cfg (feature = "os_pipe" )] |
229 | unsafe impl FilelikeViewType for os_pipe::PipeWriter {} |
230 | #[cfg (not(any(target_os = "wasi" , target_os = "hermit" )))] |
231 | #[cfg (feature = "os_pipe" )] |
232 | unsafe impl FilelikeViewType for os_pipe::PipeReader {} |
233 | |
234 | #[cfg (not(any(target_os = "wasi" , target_os = "hermit" )))] |
235 | #[cfg (feature = "socket2" )] |
236 | unsafe impl SocketlikeViewType for socket2::Socket {} |
237 | |
238 | #[cfg (not(any(target_os = "wasi" , target_os = "hermit" )))] |
239 | #[cfg (feature = "async_std" )] |
240 | unsafe impl SocketlikeViewType for async_std::net::TcpStream {} |
241 | #[cfg (not(any(target_os = "wasi" , target_os = "hermit" )))] |
242 | #[cfg (feature = "async_std" )] |
243 | unsafe impl SocketlikeViewType for async_std::net::TcpListener {} |
244 | #[cfg (not(any(target_os = "wasi" , target_os = "hermit" )))] |
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 {} |
278 | |