• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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"))]
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]
new<T: AsFilelike>(filelike: &T) -> Self84     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]
view_raw(raw: RawFilelike) -> Self99     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]
new<T: AsSocketlike>(socketlike: &T) -> Self114     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]
view_raw(raw: RawSocketlike) -> Self129     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]
deref(&self) -> &Self::Target144     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]
deref(&self) -> &Self::Target153     fn deref(&self) -> &Self::Target {
154         &self.target
155     }
156 }
157 
158 impl<Target: FilelikeViewType> Drop for FilelikeView<'_, Target> {
159     #[inline]
drop(&mut self)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]
drop(&mut self)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)]
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result194     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)]
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result203     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"))]
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 {}
278