mirror of
https://github.com/openharmony/third_party_rust_io-lifetimes.git
synced 2026-07-01 21:04:05 -04:00
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:
@@ -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]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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 {}
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user