1 //! Portability abstractions over `Owned*` and `Borrowed*`. 2 //! 3 //! On Unix, "everything is a file descriptor". On Windows, file/pipe/process 4 //! handles are distinct from socket descriptors. This file provides a minimal 5 //! layer of portability over this difference. 6 7 use crate::views::{FilelikeView, FilelikeViewType, SocketlikeView, SocketlikeViewType}; 8 #[cfg(any(unix, target_os = "wasi"))] 9 use crate::{AsFd, BorrowedFd, OwnedFd}; 10 #[cfg(windows)] 11 use crate::{AsHandle, AsSocket, BorrowedHandle, BorrowedSocket, OwnedHandle, OwnedSocket}; 12 13 /// A reference to a filelike object. 14 /// 15 /// This is a portability abstraction over Unix-like [`BorrowedFd`] and 16 /// Windows' `BorrowedHandle`. 17 #[cfg(any(unix, target_os = "wasi"))] 18 pub type BorrowedFilelike<'filelike> = BorrowedFd<'filelike>; 19 20 /// A reference to a filelike object. 21 /// 22 /// This is a portability abstraction over Unix-like `BorrowedFd` and 23 /// Windows' [`BorrowedHandle`]. 24 #[cfg(windows)] 25 pub type BorrowedFilelike<'filelike> = BorrowedHandle<'filelike>; 26 27 /// A reference to a socketlike object. 28 /// 29 /// This is a portability abstraction over Unix-like [`BorrowedFd`] and 30 /// Windows' `BorrowedSocket`. 31 #[cfg(any(unix, target_os = "wasi"))] 32 pub type BorrowedSocketlike<'socketlike> = BorrowedFd<'socketlike>; 33 34 /// A reference to a socketlike object. 35 /// 36 /// This is a portability abstraction over Unix-like `BorrowedFd` and 37 /// Windows' [`BorrowedSocket`]. 38 #[cfg(windows)] 39 pub type BorrowedSocketlike<'socketlike> = BorrowedSocket<'socketlike>; 40 41 /// An owned filelike object. 42 /// 43 /// This is a portability abstraction over Unix-like [`OwnedFd`] and 44 /// Windows' `OwnedHandle`. 45 #[cfg(any(unix, target_os = "wasi"))] 46 pub type OwnedFilelike = OwnedFd; 47 48 /// An owned filelike object. 49 /// 50 /// This is a portability abstraction over Unix-like `OwnedFd` and 51 /// Windows' [`OwnedHandle`]. 52 #[cfg(windows)] 53 pub type OwnedFilelike = OwnedHandle; 54 55 /// An owned socketlike object. 56 /// 57 /// This is a portability abstraction over Unix-like [`OwnedFd`] and 58 /// Windows' `OwnedSocket`. 59 #[cfg(any(unix, target_os = "wasi"))] 60 pub type OwnedSocketlike = OwnedFd; 61 62 /// An owned socketlike object. 63 /// 64 /// This is a portability abstraction over Unix-like `OwnedFd` and 65 /// Windows' [`OwnedSocket`]. 66 #[cfg(windows)] 67 pub type OwnedSocketlike = OwnedSocket; 68 69 /// A portable trait to borrow a reference from an underlying filelike object. 70 /// 71 /// This is a portability abstraction over Unix-like [`AsFd`] and Windows' 72 /// `AsHandle`. It also provides the `as_filelike_view` convenience function 73 /// providing typed views. 74 #[cfg(any(unix, target_os = "wasi"))] 75 pub trait AsFilelike: AsFd { 76 /// Borrows the reference. 77 /// 78 /// # Example 79 /// 80 /// ```rust,no_run 81 /// use std::fs::File; 82 /// # use std::io; 83 /// use io_lifetimes::{AsFilelike, BorrowedFilelike}; 84 /// 85 /// let mut f = File::open("foo.txt")?; 86 /// let borrowed_filelike: BorrowedFilelike<'_> = f.as_filelike(); 87 /// # Ok::<(), io::Error>(()) 88 /// ``` as_filelike(&self) -> BorrowedFilelike<'_>89 fn as_filelike(&self) -> BorrowedFilelike<'_>; 90 91 /// Return a borrowing view of a resource which dereferences to a `&Target`. 92 /// 93 /// Note that [`Read`] or [`Write`] require `&mut Target`, but in some cases, 94 /// such as [`File`], `Read` and `Write` are implemented for `&Target` in 95 /// addition to `Target`, and you can get a `&mut &Target` by doing `&*` on 96 /// the resuting view, like this: 97 /// 98 /// ```rust,ignore 99 /// let v = f.as_filelike_view::<std::fs::File>(); 100 /// (&*v).read(&mut buf).unwrap(); 101 /// ``` 102 /// 103 /// [`File`]: std::fs::File 104 /// [`Read`]: std::io::Read 105 /// [`Write`]: std::io::Write as_filelike_view<Target: FilelikeViewType>(&self) -> FilelikeView<'_, Target>106 fn as_filelike_view<Target: FilelikeViewType>(&self) -> FilelikeView<'_, Target>; 107 } 108 109 #[cfg(any(unix, target_os = "wasi"))] 110 impl<T: AsFd> AsFilelike for T { 111 #[inline] as_filelike(&self) -> BorrowedFilelike<'_>112 fn as_filelike(&self) -> BorrowedFilelike<'_> { 113 self.as_fd() 114 } 115 116 #[inline] as_filelike_view<Target: FilelikeViewType>(&self) -> FilelikeView<'_, Target>117 fn as_filelike_view<Target: FilelikeViewType>(&self) -> FilelikeView<'_, Target> { 118 FilelikeView::new(self) 119 } 120 } 121 122 /// A portable trait to borrow a reference from an underlying filelike object. 123 /// 124 /// This is a portability abstraction over Unix-like `AsFd` and Windows' 125 /// [`AsHandle`]. It also provides the `as_filelike_view` convenience function 126 /// providing typed views. 127 #[cfg(windows)] 128 pub trait AsFilelike: AsHandle { 129 /// Borrows the reference. 130 /// 131 /// # Example 132 /// 133 /// ```rust,no_run 134 /// use std::fs::File; 135 /// # use std::io; 136 /// use io_lifetimes::{AsFilelike, BorrowedFilelike}; 137 /// 138 /// let mut f = File::open("foo.txt")?; 139 /// let borrowed_filelike: BorrowedFilelike<'_> = f.as_filelike(); 140 /// # Ok::<(), io::Error>(()) 141 /// ``` as_filelike(&self) -> BorrowedFilelike<'_>142 fn as_filelike(&self) -> BorrowedFilelike<'_>; 143 144 /// Return a borrowing view of a resource which dereferences to a `&Target`. 145 /// 146 /// Note that [`Read`] or [`Write`] require `&mut Target`, but in some cases, 147 /// such as [`File`], `Read` and `Write` are implemented for `&Target` in 148 /// addition to `Target`, and you can get a `&mut &Target` by doing `&*` on 149 /// the resuting view, like this: 150 /// 151 /// ```rust,ignore 152 /// let v = f.as_filelike_view::<std::fs::File>(); 153 /// (&*v).read(&mut buf).unwrap(); 154 /// ``` 155 /// 156 /// [`File`]: std::fs::File 157 /// [`Read`]: std::io::Read 158 /// [`Write`]: std::io::Write as_filelike_view<Target: FilelikeViewType>(&self) -> FilelikeView<'_, Target>159 fn as_filelike_view<Target: FilelikeViewType>(&self) -> FilelikeView<'_, Target>; 160 } 161 162 #[cfg(windows)] 163 impl<T: AsHandle> AsFilelike for T { 164 #[inline] as_filelike(&self) -> BorrowedFilelike<'_>165 fn as_filelike(&self) -> BorrowedFilelike<'_> { 166 self.as_handle() 167 } 168 169 #[inline] as_filelike_view<Target: FilelikeViewType>(&self) -> FilelikeView<'_, Target>170 fn as_filelike_view<Target: FilelikeViewType>(&self) -> FilelikeView<'_, Target> { 171 FilelikeView::new(self) 172 } 173 } 174 175 /// A portable trait to borrow a reference from an underlying socketlike 176 /// object. 177 /// 178 /// This is a portability abstraction over Unix-like [`AsFd`] and Windows' 179 /// `AsSocket`. It also provides the `as_socketlike_view` convenience 180 /// function providing typed views. 181 #[cfg(any(unix, target_os = "wasi"))] 182 pub trait AsSocketlike: AsFd { 183 /// Borrows the reference. as_socketlike(&self) -> BorrowedSocketlike<'_>184 fn as_socketlike(&self) -> BorrowedSocketlike<'_>; 185 186 /// Return a borrowing view of a resource which dereferences to a `&Target`. 187 /// 188 /// Note that [`Read`] or [`Write`] require `&mut Target`, but in some cases, 189 /// such as [`TcpStream`], `Read` and `Write` are implemented for `&Target` in 190 /// addition to `Target`, and you can get a `&mut &Target` by doing `&*` on 191 /// the resuting view, like this: 192 /// 193 /// ```rust,ignore 194 /// let v = s.as_socketlike_view::<std::net::TcpStream>(); 195 /// (&*v).read(&mut buf).unwrap(); 196 /// ``` 197 /// 198 /// [`TcpStream`]: std::net::TcpStream 199 /// [`Read`]: std::io::Read 200 /// [`Write`]: std::io::Write as_socketlike_view<Target: SocketlikeViewType>(&self) -> SocketlikeView<'_, Target>201 fn as_socketlike_view<Target: SocketlikeViewType>(&self) -> SocketlikeView<'_, Target>; 202 } 203 204 #[cfg(any(unix, target_os = "wasi"))] 205 impl<T: AsFd> AsSocketlike for T { 206 #[inline] as_socketlike(&self) -> BorrowedSocketlike<'_>207 fn as_socketlike(&self) -> BorrowedSocketlike<'_> { 208 self.as_fd() 209 } 210 211 #[inline] as_socketlike_view<Target: SocketlikeViewType>(&self) -> SocketlikeView<'_, Target>212 fn as_socketlike_view<Target: SocketlikeViewType>(&self) -> SocketlikeView<'_, Target> { 213 SocketlikeView::new(self) 214 } 215 } 216 217 /// A portable trait to borrow a reference from an underlying socketlike 218 /// object. 219 /// 220 /// This is a portability abstraction over Unix-like `AsFd` and Windows' 221 /// [`AsSocket`]. It also provides the `as_socketlike_view` convenience 222 /// function providing typed views. 223 #[cfg(windows)] 224 pub trait AsSocketlike: AsSocket { 225 /// Borrows the reference. as_socketlike(&self) -> BorrowedSocketlike226 fn as_socketlike(&self) -> BorrowedSocketlike; 227 228 /// Return a borrowing view of a resource which dereferences to a `&Target`. 229 /// 230 /// Note that [`Read`] or [`Write`] require `&mut Target`, but in some cases, 231 /// such as [`TcpStream`], `Read` and `Write` are implemented for `&Target` in 232 /// addition to `Target`, and you can get a `&mut &Target` by doing `&*` on 233 /// the resuting view, like this: 234 /// 235 /// ```rust,ignore 236 /// let v = s.as_socketlike_view::<std::net::TcpStream>(); 237 /// (&*v).read(&mut buf).unwrap(); 238 /// ``` 239 /// 240 /// [`TcpStream`]: std::net::TcpStream as_socketlike_view<Target: SocketlikeViewType>(&self) -> SocketlikeView<'_, Target>241 fn as_socketlike_view<Target: SocketlikeViewType>(&self) -> SocketlikeView<'_, Target>; 242 } 243 244 #[cfg(windows)] 245 impl<T: AsSocket> AsSocketlike for T { 246 #[inline] as_socketlike(&self) -> BorrowedSocketlike<'_>247 fn as_socketlike(&self) -> BorrowedSocketlike<'_> { 248 self.as_socket() 249 } 250 251 #[inline] as_socketlike_view<Target: SocketlikeViewType>(&self) -> SocketlikeView<'_, Target>252 fn as_socketlike_view<Target: SocketlikeViewType>(&self) -> SocketlikeView<'_, Target> { 253 SocketlikeView::new(self) 254 } 255 } 256 257 /// A portable trait to express the ability to consume an object and acquire 258 /// ownership of its filelike object. 259 /// 260 /// This is a portability abstraction over Unix-like [`Into<OwnedFd>`] and Windows' 261 /// `Into<OwnedHandle>`. 262 #[cfg(any(unix, target_os = "wasi"))] 263 pub trait IntoFilelike: Into<OwnedFd> { 264 /// Consumes this object, returning the underlying filelike object. 265 /// 266 /// # Example 267 /// 268 /// ```rust,no_run 269 /// use std::fs::File; 270 /// # use std::io; 271 /// use io_lifetimes::{IntoFilelike, OwnedFilelike}; 272 /// 273 /// let f = File::open("foo.txt")?; 274 /// let owned_filelike: OwnedFilelike = f.into_filelike(); 275 /// # Ok::<(), io::Error>(()) 276 /// ``` into_filelike(self) -> OwnedFilelike277 fn into_filelike(self) -> OwnedFilelike; 278 } 279 280 #[cfg(any(unix, target_os = "wasi"))] 281 impl<T: Into<OwnedFd>> IntoFilelike for T { 282 #[inline] into_filelike(self) -> OwnedFilelike283 fn into_filelike(self) -> OwnedFilelike { 284 self.into() 285 } 286 } 287 288 /// A portable trait to express the ability to consume an object and acquire 289 /// ownership of its filelike object. 290 /// 291 /// This is a portability abstraction over Unix-like `Into<OwnedFd>` and Windows' 292 /// [`Into<OwnedHandle>`]. 293 #[cfg(windows)] 294 pub trait IntoFilelike: Into<OwnedHandle> { 295 /// Consumes this object, returning the underlying filelike object. into_filelike(self) -> OwnedFilelike296 fn into_filelike(self) -> OwnedFilelike; 297 } 298 299 #[cfg(windows)] 300 impl<T: Into<OwnedHandle>> IntoFilelike for T { 301 #[inline] into_filelike(self) -> OwnedFilelike302 fn into_filelike(self) -> OwnedFilelike { 303 self.into() 304 } 305 } 306 307 /// A portable trait to express the ability to consume an object and acquire 308 /// ownership of its socketlike object. 309 /// 310 /// This is a portability abstraction over Unix-like [`Into<OwnedFd>`] and Windows' 311 /// `Into<OwnedSocket>`. 312 #[cfg(any(unix, target_os = "wasi"))] 313 pub trait IntoSocketlike: Into<OwnedFd> { 314 /// Consumes this object, returning the underlying socketlike object. into_socketlike(self) -> OwnedSocketlike315 fn into_socketlike(self) -> OwnedSocketlike; 316 } 317 318 #[cfg(any(unix, target_os = "wasi"))] 319 impl<T: Into<OwnedFd>> IntoSocketlike for T { 320 #[inline] into_socketlike(self) -> OwnedSocketlike321 fn into_socketlike(self) -> OwnedSocketlike { 322 self.into() 323 } 324 } 325 326 /// A portable trait to express the ability to consume an object and acquire 327 /// ownership of its socketlike object. 328 /// 329 /// This is a portability abstraction over Unix-like `Into<OwnedFd>` and Windows' 330 /// [`Into<OwnedSocket>`]. 331 #[cfg(windows)] 332 pub trait IntoSocketlike: Into<OwnedSocket> { 333 /// Consumes this object, returning the underlying socketlike object. 334 /// 335 /// # Example 336 /// 337 /// ```rust,no_run 338 /// use std::fs::File; 339 /// # use std::io; 340 /// use io_lifetimes::{IntoFilelike, OwnedFilelike}; 341 /// 342 /// let f = File::open("foo.txt")?; 343 /// let owned_filelike: OwnedFilelike = f.into_filelike(); 344 /// # Ok::<(), io::Error>(()) 345 /// ``` into_socketlike(self) -> OwnedSocketlike346 fn into_socketlike(self) -> OwnedSocketlike; 347 } 348 349 #[cfg(windows)] 350 impl<T: Into<OwnedSocket>> IntoSocketlike for T { 351 #[inline] into_socketlike(self) -> OwnedSocketlike352 fn into_socketlike(self) -> OwnedSocketlike { 353 self.into() 354 } 355 } 356 357 /// A portable trait to express the ability to construct an object from a 358 /// filelike object. 359 /// 360 /// This is a portability abstraction over Unix-like [`From<OwnedFd>`] and Windows' 361 /// `From<OwnedHandle>`. It also provides the `from_into_filelike` convenience 362 /// function providing simplified from+into conversions. 363 #[cfg(any(unix, target_os = "wasi"))] 364 pub trait FromFilelike: From<OwnedFd> { 365 /// Constructs a new instance of `Self` from the given filelike object. 366 /// 367 /// # Example 368 /// 369 /// ```rust,no_run 370 /// use std::fs::File; 371 /// # use std::io; 372 /// use io_lifetimes::{FromFilelike, IntoFilelike, OwnedFilelike}; 373 /// 374 /// let f = File::open("foo.txt")?; 375 /// let owned_filelike: OwnedFilelike = f.into_filelike(); 376 /// let f = File::from_filelike(owned_filelike); 377 /// # Ok::<(), io::Error>(()) 378 /// ``` from_filelike(owned: OwnedFilelike) -> Self379 fn from_filelike(owned: OwnedFilelike) -> Self; 380 381 /// Constructs a new instance of `Self` from the given filelike object 382 /// converted from `into_owned`. 383 /// 384 /// # Example 385 /// 386 /// ```rust,no_run 387 /// use std::fs::File; 388 /// # use std::io; 389 /// use io_lifetimes::{FromFilelike, IntoFilelike}; 390 /// 391 /// let f = File::open("foo.txt")?; 392 /// let f = File::from_into_filelike(f); 393 /// # Ok::<(), io::Error>(()) 394 /// ``` from_into_filelike<Owned: IntoFilelike>(owned: Owned) -> Self395 fn from_into_filelike<Owned: IntoFilelike>(owned: Owned) -> Self; 396 } 397 398 #[cfg(any(unix, target_os = "wasi"))] 399 impl<T: From<OwnedFd>> FromFilelike for T { 400 #[inline] from_filelike(owned: OwnedFilelike) -> Self401 fn from_filelike(owned: OwnedFilelike) -> Self { 402 Self::from(owned) 403 } 404 405 #[inline] from_into_filelike<Owned: IntoFilelike>(owned: Owned) -> Self406 fn from_into_filelike<Owned: IntoFilelike>(owned: Owned) -> Self { 407 Self::from_filelike(owned.into_filelike()) 408 } 409 } 410 411 /// A portable trait to express the ability to construct an object from a 412 /// filelike object. 413 /// 414 /// This is a portability abstraction over Unix-like `From<OwnedFd>` and Windows' 415 /// [`From<OwnedHandle>`]. It also provides the `from_into_filelike` convenience 416 /// function providing simplified from+into conversions. 417 #[cfg(windows)] 418 pub trait FromFilelike: From<OwnedHandle> { 419 /// Constructs a new instance of `Self` from the given filelike object. 420 /// 421 /// # Example 422 /// 423 /// ```rust,no_run 424 /// use std::fs::File; 425 /// # use std::io; 426 /// use io_lifetimes::{FromFilelike, IntoFilelike, OwnedFilelike}; 427 /// 428 /// let f = File::open("foo.txt")?; 429 /// let owned_filelike: OwnedFilelike = f.into_filelike(); 430 /// let f = File::from_filelike(owned_filelike); 431 /// # Ok::<(), io::Error>(()) 432 /// ``` from_filelike(owned: OwnedFilelike) -> Self433 fn from_filelike(owned: OwnedFilelike) -> Self; 434 435 /// Constructs a new instance of `Self` from the given filelike object 436 /// converted from `into_owned`. 437 /// 438 /// # Example 439 /// 440 /// ```rust,no_run 441 /// use std::fs::File; 442 /// # use std::io; 443 /// use io_lifetimes::{FromFilelike, IntoFilelike}; 444 /// 445 /// let f = File::open("foo.txt")?; 446 /// let f = File::from_into_filelike(f); 447 /// # Ok::<(), io::Error>(()) 448 /// ``` from_into_filelike<Owned: IntoFilelike>(owned: Owned) -> Self449 fn from_into_filelike<Owned: IntoFilelike>(owned: Owned) -> Self; 450 } 451 452 #[cfg(windows)] 453 impl<T: From<OwnedHandle>> FromFilelike for T { 454 #[inline] from_filelike(owned: OwnedFilelike) -> Self455 fn from_filelike(owned: OwnedFilelike) -> Self { 456 Self::from(owned) 457 } 458 459 #[inline] from_into_filelike<Owned: IntoFilelike>(owned: Owned) -> Self460 fn from_into_filelike<Owned: IntoFilelike>(owned: Owned) -> Self { 461 Self::from_filelike(owned.into_filelike()) 462 } 463 } 464 465 /// A portable trait to express the ability to construct an object from a 466 /// socketlike object. 467 /// 468 /// This is a portability abstraction over Unix-like [`From<OwnedFd>`] and Windows' 469 /// `From<OwnedSocketFrom<OwnedSocket> It also provides the `from_into_socketlike` convenience 470 /// function providing simplified from+into conversions. 471 #[cfg(any(unix, target_os = "wasi"))] 472 pub trait FromSocketlike: From<OwnedFd> { 473 /// Constructs a new instance of `Self` from the given socketlike object. from_socketlike(owned: OwnedSocketlike) -> Self474 fn from_socketlike(owned: OwnedSocketlike) -> Self; 475 476 /// Constructs a new instance of `Self` from the given socketlike object 477 /// converted from `into_owned`. from_into_socketlike<Owned: IntoSocketlike>(owned: Owned) -> Self478 fn from_into_socketlike<Owned: IntoSocketlike>(owned: Owned) -> Self; 479 } 480 481 #[cfg(any(unix, target_os = "wasi"))] 482 impl<T: From<OwnedFd>> FromSocketlike for T { 483 #[inline] from_socketlike(owned: OwnedSocketlike) -> Self484 fn from_socketlike(owned: OwnedSocketlike) -> Self { 485 Self::from(owned) 486 } 487 488 #[inline] from_into_socketlike<Owned: IntoSocketlike>(owned: Owned) -> Self489 fn from_into_socketlike<Owned: IntoSocketlike>(owned: Owned) -> Self { 490 Self::from_socketlike(owned.into_socketlike()) 491 } 492 } 493 494 /// A portable trait to express the ability to construct an object from a 495 /// socketlike object. 496 /// 497 /// This is a portability abstraction over Unix-like `From<OwnedFd>` and Windows' 498 /// [`From<OwnedSocket>`]. It also provides the `from_into_socketlike` convenience 499 /// function providing simplified from+into conversions. 500 #[cfg(windows)] 501 pub trait FromSocketlike: From<OwnedSocket> { 502 /// Constructs a new instance of `Self` from the given socketlike object. from_socketlike(owned: OwnedSocketlike) -> Self503 fn from_socketlike(owned: OwnedSocketlike) -> Self; 504 505 /// Constructs a new instance of `Self` from the given socketlike object 506 /// converted from `into_owned`. from_into_socketlike<Owned: IntoSocketlike>(owned: Owned) -> Self507 fn from_into_socketlike<Owned: IntoSocketlike>(owned: Owned) -> Self; 508 } 509 510 #[cfg(windows)] 511 impl<T: From<OwnedSocket>> FromSocketlike for T { 512 #[inline] from_socketlike(owned: OwnedSocketlike) -> Self513 fn from_socketlike(owned: OwnedSocketlike) -> Self { 514 Self::from(owned) 515 } 516 517 #[inline] from_into_socketlike<Owned: IntoSocketlike>(owned: Owned) -> Self518 fn from_into_socketlike<Owned: IntoSocketlike>(owned: Owned) -> Self { 519 Self::from_socketlike(owned.into_socketlike()) 520 } 521 } 522