| 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 = 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 = 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 | |