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