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