Make views require dedicated unsafe marker traits. (#32)

* Make views require dedicated `unsafe` marker traits.

Requiring `Into` and `From` conversions is not sufficient for
`FilelikeView` and `SocketlikeView`, becuase there's no guarantee
that the `Into` implementation will return the same handle as the `From`
implementation. If a type allows its handle to be reassigned, that
can lead to the old handle being freed twice, and the new handle being
leaked.

To fix this, introduce unsafe marker traits `FilelikeViewType` and
`SocketlikeViewType`, and have `FilelikeView` and `SocketlikeView`
require these traits.

* Fix io_lifetimes_use_std compilation.

* Remove the `DerefMut` from the view types.

* Add API tests for the `&*` idiom for using `Read` and `Write`.

* Add a debug check for views checking that they return the same handle.

* Use `ManuallyDrop` to avoid needing `Option` in the view types.

`ManuallyDrop::take` allows the view types to properly consume their temporary
objects without needing an `.unwrap()`.
This commit is contained in:
Dan Gohman
2022-05-27 09:58:41 -07:00
committed by GitHub
parent a9d3d3764d
commit 7a6eb292e5
10 changed files with 260 additions and 101 deletions
+18
View File
@@ -2,6 +2,7 @@
//! future, we'll prefer to have crates provide their own impls; this is
//! just a temporary measure.
use crate::views::{FilelikeViewType, SocketlikeViewType};
#[cfg(any(unix, target_os = "wasi"))]
use crate::{AsFd, BorrowedFd, FromFd, IntoFd, OwnedFd};
#[cfg(windows)]
@@ -18,6 +19,8 @@ use std::os::windows::io::{
AsRawHandle, AsRawSocket, FromRawHandle, FromRawSocket, IntoRawHandle, IntoRawSocket,
};
unsafe impl FilelikeViewType for async_std::fs::File {}
#[cfg(any(unix, target_os = "wasi"))]
impl AsFd for async_std::fs::File {
#[inline]
@@ -66,6 +69,8 @@ impl FromHandle for async_std::fs::File {
}
}
unsafe impl SocketlikeViewType for async_std::net::TcpStream {}
#[cfg(any(unix, target_os = "wasi"))]
impl AsFd for async_std::net::TcpStream {
#[inline]
@@ -114,6 +119,8 @@ impl FromSocket for async_std::net::TcpStream {
}
}
unsafe impl SocketlikeViewType for async_std::net::TcpListener {}
#[cfg(any(unix, target_os = "wasi"))]
impl AsFd for async_std::net::TcpListener {
#[inline]
@@ -162,6 +169,8 @@ impl FromSocket for async_std::net::TcpListener {
}
}
unsafe impl SocketlikeViewType for async_std::net::UdpSocket {}
#[cfg(any(unix, target_os = "wasi"))]
impl AsFd for async_std::net::UdpSocket {
#[inline]
@@ -258,6 +267,9 @@ impl AsHandle for async_std::io::Stderr {
}
}
#[cfg(unix)]
unsafe impl SocketlikeViewType for async_std::os::unix::net::UnixStream {}
#[cfg(unix)]
impl AsFd for async_std::os::unix::net::UnixStream {
#[inline]
@@ -282,6 +294,9 @@ impl FromFd for async_std::os::unix::net::UnixStream {
}
}
#[cfg(unix)]
unsafe impl SocketlikeViewType for async_std::os::unix::net::UnixListener {}
#[cfg(unix)]
impl AsFd for async_std::os::unix::net::UnixListener {
#[inline]
@@ -306,6 +321,9 @@ impl FromFd for async_std::os::unix::net::UnixListener {
}
}
#[cfg(unix)]
unsafe impl SocketlikeViewType for async_std::os::unix::net::UnixDatagram {}
#[cfg(unix)]
impl AsFd for async_std::os::unix::net::UnixDatagram {
#[inline]
+24
View File
@@ -2,6 +2,9 @@
//! future, we'll prefer to have crates provide their own impls; this is
//! just a temporary measure.
#[cfg(unix)]
use crate::views::FilelikeViewType;
use crate::views::SocketlikeViewType;
#[cfg(any(unix, target_os = "wasi"))]
use crate::{AsFd, BorrowedFd, FromFd, IntoFd, OwnedFd};
#[cfg(windows)]
@@ -13,6 +16,8 @@ use std::os::wasi::io::{AsRawFd, FromRawFd, IntoRawFd};
#[cfg(windows)]
use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket};
unsafe impl SocketlikeViewType for mio::net::TcpStream {}
#[cfg(any(unix, target_os = "wasi"))]
impl AsFd for mio::net::TcpStream {
#[inline]
@@ -61,6 +66,8 @@ impl FromSocket for mio::net::TcpStream {
}
}
unsafe impl SocketlikeViewType for mio::net::TcpListener {}
#[cfg(any(unix, target_os = "wasi"))]
impl AsFd for mio::net::TcpListener {
#[inline]
@@ -109,6 +116,8 @@ impl FromSocket for mio::net::TcpListener {
}
}
unsafe impl SocketlikeViewType for mio::net::UdpSocket {}
#[cfg(any(unix, target_os = "wasi"))]
impl AsFd for mio::net::UdpSocket {
#[inline]
@@ -157,6 +166,9 @@ impl FromSocket for mio::net::UdpSocket {
}
}
#[cfg(unix)]
unsafe impl SocketlikeViewType for mio::net::UnixDatagram {}
#[cfg(unix)]
impl AsFd for mio::net::UnixDatagram {
#[inline]
@@ -181,6 +193,9 @@ impl FromFd for mio::net::UnixDatagram {
}
}
#[cfg(unix)]
unsafe impl SocketlikeViewType for mio::net::UnixListener {}
#[cfg(unix)]
impl AsFd for mio::net::UnixListener {
#[inline]
@@ -205,6 +220,9 @@ impl FromFd for mio::net::UnixListener {
}
}
#[cfg(unix)]
unsafe impl SocketlikeViewType for mio::net::UnixStream {}
#[cfg(unix)]
impl AsFd for mio::net::UnixStream {
#[inline]
@@ -229,6 +247,9 @@ impl FromFd for mio::net::UnixStream {
}
}
#[cfg(unix)]
unsafe impl FilelikeViewType for mio::unix::pipe::Receiver {}
#[cfg(unix)]
impl AsFd for mio::unix::pipe::Receiver {
#[inline]
@@ -253,6 +274,9 @@ impl FromFd for mio::unix::pipe::Receiver {
}
}
#[cfg(unix)]
unsafe impl FilelikeViewType for mio::unix::pipe::Sender {}
#[cfg(unix)]
impl AsFd for mio::unix::pipe::Sender {
#[inline]
+5
View File
@@ -2,6 +2,7 @@
//! future, we'll prefer to have crates provide their own impls; this is
//! just a temporary measure.
use crate::views::FilelikeViewType;
#[cfg(any(unix, target_os = "wasi"))]
use crate::{AsFd, BorrowedFd, FromFd, IntoFd, OwnedFd};
#[cfg(windows)]
@@ -13,6 +14,8 @@ use std::os::wasi::io::{AsRawFd, FromRawFd, IntoRawFd};
#[cfg(windows)]
use std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle};
unsafe impl FilelikeViewType for os_pipe::PipeReader {}
#[cfg(any(unix, target_os = "wasi"))]
impl AsFd for os_pipe::PipeReader {
#[inline]
@@ -61,6 +64,8 @@ impl FromHandle for os_pipe::PipeReader {
}
}
unsafe impl FilelikeViewType for os_pipe::PipeWriter {}
#[cfg(any(unix, target_os = "wasi"))]
impl AsFd for os_pipe::PipeWriter {
#[inline]
+3
View File
@@ -2,6 +2,7 @@
//! future, we'll prefer to have crates provide their own impls; this is
//! just a temporary measure.
use crate::views::SocketlikeViewType;
#[cfg(any(unix, target_os = "wasi"))]
use crate::{AsFd, BorrowedFd, FromFd, IntoFd, OwnedFd};
#[cfg(windows)]
@@ -13,6 +14,8 @@ use std::os::wasi::io::{AsRawFd, FromRawFd, IntoRawFd};
#[cfg(windows)]
use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket};
unsafe impl SocketlikeViewType for socket2::Socket {}
#[cfg(any(unix, target_os = "wasi"))]
impl AsFd for socket2::Socket {
#[inline]
+31
View File
@@ -0,0 +1,31 @@
use crate::views::{FilelikeViewType, SocketlikeViewType};
#[cfg(any(unix, target_os = "wasi"))]
use crate::OwnedFd;
#[cfg(windows)]
use crate::{OwnedHandle, OwnedSocket};
#[cfg(any(unix, target_os = "wasi"))]
unsafe impl FilelikeViewType for OwnedFd {}
#[cfg(windows)]
unsafe impl FilelikeViewType for OwnedHandle {}
#[cfg(windows)]
unsafe impl SocketlikeViewType for OwnedSocket {}
unsafe impl FilelikeViewType for std::fs::File {}
unsafe impl SocketlikeViewType for std::net::TcpStream {}
unsafe impl SocketlikeViewType for std::net::TcpListener {}
unsafe impl SocketlikeViewType for std::net::UdpSocket {}
#[cfg(unix)]
unsafe impl SocketlikeViewType for std::os::unix::net::UnixStream {}
#[cfg(unix)]
unsafe impl SocketlikeViewType for std::os::unix::net::UnixListener {}
#[cfg(unix)]
unsafe impl SocketlikeViewType for std::os::unix::net::UnixDatagram {}
+1
View File
@@ -39,6 +39,7 @@ mod types;
#[cfg(not(io_lifetimes_use_std))]
mod impls_std;
mod impls_std_views;
#[cfg(not(io_lifetimes_use_std))]
#[cfg(any(unix, target_os = "wasi"))]
+53 -25
View File
@@ -6,7 +6,7 @@
//!
//! TODO: Should this layer be folded into types.rs/traits.rs?
use crate::views::{FilelikeView, SocketlikeView};
use crate::views::{FilelikeView, FilelikeViewType, SocketlikeView, SocketlikeViewType};
#[cfg(any(unix, target_os = "wasi"))]
use crate::{AsFd, BorrowedFd, FromFd, IntoFd, OwnedFd};
#[cfg(windows)]
@@ -93,11 +93,20 @@ pub trait AsFilelike: AsFd {
/// ```
fn as_filelike(&self) -> BorrowedFilelike<'_>;
/// Return a borrowing view of a resource which dereferences to a `&Target`
/// or `&mut Target`.
/// Return a borrowing view of a resource which dereferences to a `&Target`.
///
/// Note that [`Read`] or [`Write`] require `&mut Target`, but in some cases,
/// such as [`File`], `Read` and `Write` are implemented for `&Target` in
/// addition to `Target`, and you can get a `&mut &Target` by doing `&*` on
/// the resuting view, like this:
///
/// ```rust,ignore
/// let v = f.as_filelike_view::<std::fs::File>();
/// (&*v).read(&mut buf).unwrap();
/// ```
///
/// [`File`]: std::fs::File
fn as_filelike_view<Target: FromFilelike + IntoFilelike>(&self) -> FilelikeView<'_, Target>;
fn as_filelike_view<Target: FilelikeViewType>(&self) -> FilelikeView<'_, Target>;
}
#[cfg(any(unix, target_os = "wasi"))]
@@ -108,7 +117,7 @@ impl<T: AsFd> AsFilelike for T {
}
#[inline]
fn as_filelike_view<Target: FromFilelike + IntoFilelike>(&self) -> FilelikeView<'_, Target> {
fn as_filelike_view<Target: FilelikeViewType>(&self) -> FilelikeView<'_, Target> {
FilelikeView::new(self)
}
}
@@ -135,11 +144,20 @@ pub trait AsFilelike: AsHandle {
/// ```
fn as_filelike(&self) -> BorrowedFilelike<'_>;
/// Return a borrowing view of a resource which dereferences to a `&Target`
/// or `&mut Target`.
/// Return a borrowing view of a resource which dereferences to a `&Target`.
///
/// Note that [`Read`] or [`Write`] require `&mut Target`, but in some cases,
/// such as [`File`], `Read` and `Write` are implemented for `&Target` in
/// addition to `Target`, and you can get a `&mut &Target` by doing `&*` on
/// the resuting view, like this:
///
/// ```rust,ignore
/// let v = f.as_filelike_view::<std::fs::File>();
/// (&*v).read(&mut buf).unwrap();
/// ```
///
/// [`File`]: std::fs::File
fn as_filelike_view<Target: FromFilelike + IntoFilelike>(&self) -> FilelikeView<'_, Target>;
fn as_filelike_view<Target: FilelikeViewType>(&self) -> FilelikeView<'_, Target>;
}
#[cfg(windows)]
@@ -150,7 +168,7 @@ impl<T: AsHandle> AsFilelike for T {
}
#[inline]
fn as_filelike_view<Target: FromFilelike + IntoFilelike>(&self) -> FilelikeView<'_, Target> {
fn as_filelike_view<Target: FilelikeViewType>(&self) -> FilelikeView<'_, Target> {
FilelikeView::new(self)
}
}
@@ -166,13 +184,20 @@ pub trait AsSocketlike: AsFd {
/// Borrows the reference.
fn as_socketlike(&self) -> BorrowedSocketlike<'_>;
/// Return a borrowing view of a resource which dereferences to a `&Target`
/// or `&mut Target`.
/// Return a borrowing view of a resource which dereferences to a `&Target`.
///
/// Note that [`Read`] or [`Write`] require `&mut Target`, but in some cases,
/// such as [`TcpStream`], `Read` and `Write` are implemented for `&Target` in
/// addition to `Target`, and you can get a `&mut &Target` by doing `&*` on
/// the resuting view, like this:
///
/// ```rust,ignore
/// let v = s.as_socketlike_view::<std::net::TcpStream>();
/// (&*v).read(&mut buf).unwrap();
/// ```
///
/// [`TcpStream`]: std::net::TcpStream
fn as_socketlike_view<Target: FromSocketlike + IntoSocketlike>(
&self,
) -> SocketlikeView<'_, Target>;
fn as_socketlike_view<Target: SocketlikeViewType>(&self) -> SocketlikeView<'_, Target>;
}
#[cfg(any(unix, target_os = "wasi"))]
@@ -183,9 +208,7 @@ impl<T: AsFd> AsSocketlike for T {
}
#[inline]
fn as_socketlike_view<Target: FromSocketlike + IntoSocketlike>(
&self,
) -> SocketlikeView<'_, Target> {
fn as_socketlike_view<Target: SocketlikeViewType>(&self) -> SocketlikeView<'_, Target> {
SocketlikeView::new(self)
}
}
@@ -201,13 +224,20 @@ pub trait AsSocketlike: AsSocket {
/// Borrows the reference.
fn as_socketlike(&self) -> BorrowedSocketlike;
/// Return a borrowing view of a resource which dereferences to a `&Target`
/// or `&mut Target`.
/// Return a borrowing view of a resource which dereferences to a `&Target`.
///
/// Note that [`Read`] or [`Write`] require `&mut Target`, but in some cases,
/// such as [`TcpStream`], `Read` and `Write` are implemented for `&Target` in
/// addition to `Target`, and you can get a `&mut &Target` by doing `&*` on
/// the resuting view, like this:
///
/// ```rust,ignore
/// let v = s.as_socketlike_view::<std::net::TcpStream>();
/// (&*v).read(&mut buf).unwrap();
/// ```
///
/// [`TcpStream`]: std::net::TcpStream
fn as_socketlike_view<Target: FromSocketlike + IntoSocketlike>(
&self,
) -> SocketlikeView<'_, Target>;
fn as_socketlike_view<Target: SocketlikeViewType>(&self) -> SocketlikeView<'_, Target>;
}
#[cfg(windows)]
@@ -218,9 +248,7 @@ impl<T: AsSocket> AsSocketlike for T {
}
#[inline]
fn as_socketlike_view<Target: FromSocketlike + IntoSocketlike>(
&self,
) -> SocketlikeView<'_, Target> {
fn as_socketlike_view<Target: SocketlikeViewType>(&self) -> SocketlikeView<'_, Target> {
SocketlikeView::new(self)
}
}
+8
View File
@@ -150,6 +150,14 @@ pub trait IntoRawSocketlike: IntoRawFd {
fn into_raw_socketlike(self) -> RawSocketlike;
}
#[cfg(any(unix, target_os = "wasi"))]
impl<T: IntoRawFd> IntoRawSocketlike for T {
#[inline]
fn into_raw_socketlike(self) -> RawSocketlike {
self.into_raw_fd()
}
}
/// This is a portability abstraction over Unix-like `IntoRawFd` and Windows'
/// [`IntoRawSocket`].
#[cfg(windows)]
+81 -70
View File
@@ -5,23 +5,51 @@
//!
//! [`AsSocketlike::as_socketlike_view`]: crate::AsSocketlike::as_socketlike_view
use crate::raw::{AsRawFilelike, FromRawFilelike, IntoRawFilelike, RawFilelike};
#[cfg(windows)]
use crate::{
raw::{AsRawSocketlike, FromRawSocketlike, IntoRawSocketlike, RawSocketlike},
AsSocketlike, FromSocketlike, IntoSocketlike, OwnedSocketlike,
use crate::raw::{
AsRawFilelike, AsRawSocketlike, FromRawFilelike, FromRawSocketlike, IntoRawFilelike,
IntoRawSocketlike, RawFilelike, RawSocketlike,
};
use crate::{
AsFilelike, AsSocketlike, FromFilelike, FromSocketlike, IntoFilelike, IntoSocketlike,
OwnedFilelike, OwnedSocketlike,
};
use crate::{AsFilelike, FromFilelike, IntoFilelike, OwnedFilelike};
use std::fmt;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::mem::ManuallyDrop;
use std::ops::Deref;
/// Declare that a type is safe to use in a [`FilelikeView`].
///
/// # Safety
///
/// Types implementing this trait declare that if they are constructed with
/// [`FromFilelike`] and consumed with [`IntoFilelike`], their `IntoFilelike`
/// will return the same `OwnedFd` value that was passed to their
/// `FromFilelike`.
pub unsafe trait FilelikeViewType: FromFilelike + IntoFilelike {}
/// Declare that a type is safe to use in a [`SocketlikeView`].
///
/// # Safety
///
/// Types implementing this trait declare that if they are constructed with
/// [`FromSocketlike`] and consumed with [`IntoSocketlike`], their
/// `IntoSocketlike` will return the same `OwnedFd` value that was passed to
/// their `FromSocketlike`.
pub unsafe trait SocketlikeViewType: FromSocketlike + IntoSocketlike {}
/// A non-owning view of a resource which dereferences to a `&Target` or
/// `&mut Target`. These are returned by [`AsFilelike::as_filelike_view`].
pub struct FilelikeView<'filelike, Target: FromFilelike + IntoFilelike> {
/// The value to dereference to. This is an `Option` so that we can consume
/// it in our `Drop` impl.
target: Option<Target>,
pub struct FilelikeView<'filelike, Target: FilelikeViewType> {
/// The value to dereference to. This is a `ManuallyDrop` so that we can
/// consume it in our `Drop` impl.
target: ManuallyDrop<Target>,
/// `FilelikeViewType` implementors guarantee that their `Into<OwnedFd>`
/// returns the same fd as their `From<OwnedFd>` gave them. This field
/// allows us to verify this.
#[cfg(debug_assertions)]
orig: RawFilelike,
/// This field exists because we don't otherwise explicitly use
/// `'filelike`.
@@ -30,25 +58,23 @@ pub struct FilelikeView<'filelike, Target: FromFilelike + IntoFilelike> {
/// A non-owning view of a resource which dereferences to a `&Target` or
/// `&mut Target`. These are returned by [`AsSocketlike::as_socketlike_view`].
///
/// [`AsSocketlike::as_socketlike_view`]: crate::AsSocketlike::as_socketlike_view
#[cfg(any(unix, target_os = "wasi"))]
pub type SocketlikeView<'socketlike, Target> = FilelikeView<'socketlike, Target>;
pub struct SocketlikeView<'socketlike, Target: SocketlikeViewType> {
/// The value to dereference to. This is a `ManuallyDrop` so that we can
/// consume it in our `Drop` impl.
target: ManuallyDrop<Target>,
/// A non-owning view of a resource which dereferences to a `&Target` or
/// `&mut Target`. These are returned by [`AsSocketlike::as_socketlike_view`].
#[cfg(windows)]
pub struct SocketlikeView<'socketlike, Target: FromSocketlike + IntoSocketlike> {
/// The value to dereference to. This is an `Option` so that we can consume
/// it in our `Drop` impl.
target: Option<Target>,
/// `SocketlikeViewType` implementors guarantee that their `Into<OwnedFd>`
/// returns the same fd as their `From<OwnedFd>` gave them. This field
/// allows us to verify this.
#[cfg(debug_assertions)]
orig: RawSocketlike,
/// This field exists because we don't otherwise explicitly use
/// `'socketlike`.
_phantom: PhantomData<&'socketlike OwnedSocketlike>,
}
impl<Target: FromFilelike + IntoFilelike> FilelikeView<'_, Target> {
impl<Target: FilelikeViewType> FilelikeView<'_, Target> {
/// Construct a temporary `Target` and wrap it in a `FilelikeView` object.
#[inline]
pub(crate) fn new<T: AsFilelike>(filelike: &T) -> Self {
@@ -69,14 +95,15 @@ impl<Target: FromFilelike + IntoFilelike> FilelikeView<'_, Target> {
pub unsafe fn view_raw(raw: RawFilelike) -> Self {
let owned = OwnedFilelike::from_raw_filelike(raw);
Self {
target: Some(Target::from_filelike(owned)),
target: ManuallyDrop::new(Target::from_filelike(owned)),
#[cfg(debug_assertions)]
orig: raw,
_phantom: PhantomData,
}
}
}
#[cfg(windows)]
impl<Target: FromSocketlike + IntoSocketlike> SocketlikeView<'_, Target> {
impl<Target: SocketlikeViewType> SocketlikeView<'_, Target> {
/// Construct a temporary `Target` and wrap it in a `SocketlikeView`
/// object.
#[inline]
@@ -84,13 +111,7 @@ impl<Target: FromSocketlike + IntoSocketlike> SocketlikeView<'_, Target> {
// Safety: The returned `SocketlikeView` is scoped to the lifetime of
// `socketlike`, which we've borrowed here, so the view won't outlive
// the object it's borrowed from.
let owned = unsafe {
OwnedSocketlike::from_raw_socketlike(socketlike.as_socketlike().as_raw_socketlike())
};
Self {
target: Some(Target::from_socketlike(owned)),
_phantom: PhantomData,
}
unsafe { Self::view_raw(socketlike.as_socketlike().as_raw_socketlike()) }
}
/// Construct a temporary `Target` from raw and wrap it in a
@@ -104,72 +125,65 @@ impl<Target: FromSocketlike + IntoSocketlike> SocketlikeView<'_, Target> {
pub unsafe fn view_raw(raw: RawSocketlike) -> Self {
let owned = OwnedSocketlike::from_raw_socketlike(raw);
Self {
target: Some(Target::from_socketlike(owned)),
target: ManuallyDrop::new(Target::from_socketlike(owned)),
#[cfg(debug_assertions)]
orig: raw,
_phantom: PhantomData,
}
}
}
impl<Target: FromFilelike + IntoFilelike> Deref for FilelikeView<'_, Target> {
impl<Target: FilelikeViewType> Deref for FilelikeView<'_, Target> {
type Target = Target;
#[inline]
fn deref(&self) -> &Self::Target {
self.target.as_ref().unwrap()
&self.target
}
}
#[cfg(windows)]
impl<Target: FromSocketlike + IntoSocketlike> Deref for SocketlikeView<'_, Target> {
impl<Target: SocketlikeViewType> Deref for SocketlikeView<'_, Target> {
type Target = Target;
#[inline]
fn deref(&self) -> &Self::Target {
self.target.as_ref().unwrap()
&self.target
}
}
impl<Target: FromFilelike + IntoFilelike> DerefMut for FilelikeView<'_, Target> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.target.as_mut().unwrap()
}
}
#[cfg(windows)]
impl<Target: FromSocketlike + IntoSocketlike> DerefMut for SocketlikeView<'_, Target> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.target.as_mut().unwrap()
}
}
impl<Target: FromFilelike + IntoFilelike> Drop for FilelikeView<'_, Target> {
impl<Target: FilelikeViewType> Drop for FilelikeView<'_, Target> {
fn drop(&mut self) {
// Use `Into*` to consume `self.target` without freeing its resource.
let _ = self
.target
.take()
.unwrap()
//
// Safety: Using `ManuallyDrop::take` requires us to ensure that
// `self.target` is not used again. We don't use it again here, and
// this is the `drop` function, so we know it's not used afterward.
let _raw = unsafe { ManuallyDrop::take(&mut self.target) }
.into_filelike()
.into_raw_filelike();
#[cfg(debug_assertions)]
debug_assert_eq!(self.orig, _raw);
}
}
#[cfg(windows)]
impl<Target: FromSocketlike + IntoSocketlike> Drop for SocketlikeView<'_, Target> {
impl<Target: SocketlikeViewType> Drop for SocketlikeView<'_, Target> {
fn drop(&mut self) {
// Use `Into*` to consume `self.target` without freeing its resource.
let _ = self
.target
.take()
.unwrap()
//
// Safety: Using `ManuallyDrop::take` requires us to ensure that
// `self.target` is not used again. We don't use it again here, and
// this is the `drop` function, so we know it's not used afterward.
let _raw = unsafe { ManuallyDrop::take(&mut self.target) }
.into_socketlike()
.into_raw_socketlike();
#[cfg(debug_assertions)]
debug_assert_eq!(self.orig, _raw);
}
}
impl<Target: FromFilelike + IntoFilelike + fmt::Debug> fmt::Debug for FilelikeView<'_, Target> {
impl<Target: FilelikeViewType> fmt::Debug for FilelikeView<'_, Target> {
#[allow(clippy::missing_inline_in_public_items)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FilelikeView")
@@ -178,10 +192,7 @@ impl<Target: FromFilelike + IntoFilelike + fmt::Debug> fmt::Debug for FilelikeVi
}
}
#[cfg(windows)]
impl<Target: FromSocketlike + IntoSocketlike + fmt::Debug> fmt::Debug
for SocketlikeView<'_, Target>
{
impl<Target: SocketlikeViewType> fmt::Debug for SocketlikeView<'_, Target> {
#[allow(clippy::missing_inline_in_public_items)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SocketlikeView")
+36 -6
View File
@@ -8,45 +8,75 @@ use io_lifetimes::{
AsFilelike, AsSocketlike, BorrowedFilelike, FromFilelike, FromSocketlike, IntoFilelike,
IntoSocketlike,
};
use std::io::{Read, Write};
struct Tester {}
impl Tester {
fn use_file<Filelike: AsFilelike>(filelike: Filelike) {
let mut buf = Vec::new();
let filelike = filelike.as_filelike();
let _ = filelike.as_filelike_view::<std::fs::File>();
let _ = unsafe {
let view = filelike.as_filelike_view::<std::fs::File>();
let _ = (&*view).read(&mut buf).is_ok();
let _ = (&*view).write(&buf).is_ok();
let view = unsafe {
FilelikeView::<std::fs::File>::view_raw(
filelike
.as_filelike_view::<std::fs::File>()
.as_raw_filelike(),
)
};
let _ = (&*view).read(&mut buf).is_ok();
let _ = (&*view).write(&buf).is_ok();
let _ = dbg!(filelike);
}
fn use_socket<Socketlike: AsSocketlike>(socketlike: Socketlike) {
let mut buf = Vec::new();
let socketlike = socketlike.as_socketlike();
let _ = socketlike.as_socketlike_view::<std::net::TcpStream>();
let _ = unsafe {
let view = socketlike.as_socketlike_view::<std::net::TcpStream>();
let _ = (&*view).read(&mut buf).is_ok();
let _ = (&*view).write(&buf).is_ok();
let view = unsafe {
SocketlikeView::<std::net::TcpStream>::view_raw(
socketlike
.as_socketlike_view::<std::net::TcpStream>()
.as_raw_socketlike(),
)
};
let _ = (&*view).read(&mut buf).is_ok();
let _ = (&*view).write(&buf).is_ok();
let _ = dbg!(socketlike);
}
fn from_file<Filelike: IntoFilelike>(filelike: Filelike) {
let mut buf = Vec::new();
let filelike = filelike.into_filelike();
let _ = filelike.as_filelike_view::<std::fs::File>();
let view = filelike.as_filelike_view::<std::fs::File>();
let _ = (&*view).read(&mut buf).is_ok();
let _ = (&*view).write(&buf).is_ok();
drop(view);
let _ = dbg!(&filelike);
let _ = std::fs::File::from_filelike(filelike);
}
fn from_socket<Socketlike: IntoSocketlike>(socketlike: Socketlike) {
let mut buf = Vec::new();
let socketlike = socketlike.into_socketlike();
let _ = socketlike.as_socketlike_view::<std::net::TcpStream>();
let view = socketlike.as_socketlike_view::<std::net::TcpStream>();
let _ = (&*view).read(&mut buf).is_ok();
let _ = (&*view).write(&buf).is_ok();
drop(view);
let _ = dbg!(&socketlike);
let _ = std::net::TcpStream::from_socketlike(socketlike);
}