use std::{fmt, marker::PhantomData, net::Shutdown, ops::Deref};
use crate::{
buf::{BufResult, IoBuf, IoBufMut, IoVectoredBuf, IoVectoredBufMut},
driver::helpers::socket::Socket,
io::{AsyncRead, AsyncWrite, ReuniteError},
};
#[cfg(target_os = "linux")]
use crate::{buf::PooledBuf, io::AsyncReadManaged};
pub(super) fn split<'a, T>(stream: &'a T) -> (ReadHalf<'a, T>, WriteHalf<'a, T>)
where
&'a T: AsyncRead + AsyncWrite,
{
(ReadHalf(stream), WriteHalf(stream))
}
#[derive(Debug)]
pub struct ReadHalf<'a, T>(&'a T);
impl<'a, T> AsyncRead for ReadHalf<'a, T>
where
&'a T: AsyncRead,
{
async fn read<B: IoBufMut>(&mut self, buf: B) -> BufResult<usize, B> {
self.0.read(buf).await
}
async fn read_vectored<V: IoVectoredBufMut>(&mut self, bufs: V) -> BufResult<usize, V> {
self.0.read_vectored(bufs).await
}
}
impl<T> Deref for ReadHalf<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.0
}
}
#[derive(Debug)]
pub struct WriteHalf<'a, T>(&'a T);
impl<'a, T> AsyncWrite for WriteHalf<'a, T>
where
&'a T: AsyncWrite,
{
async fn write<B: IoBuf>(&mut self, buf: B) -> BufResult<usize, B> {
self.0.write(buf).await
}
async fn write_vectored<V: IoVectoredBuf>(&mut self, bufs: V) -> BufResult<usize, V> {
self.0.write_vectored(bufs).await
}
async fn flush(&mut self) -> std::io::Result<()> {
self.0.flush().await
}
async fn shutdown(&mut self) -> std::io::Result<()> {
self.0.shutdown().await
}
}
impl<T> Deref for WriteHalf<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.0
}
}
pub struct OwnedReadHalf<T> {
pub(crate) inner: Socket,
pub(crate) _stream: PhantomData<fn() -> T>,
}
impl<T> fmt::Debug for OwnedReadHalf<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OwnedReadHalf").finish_non_exhaustive()
}
}
impl<T> AsyncRead for OwnedReadHalf<T> {
async fn read<B: IoBufMut>(&mut self, buf: B) -> BufResult<usize, B> {
self.inner.recv(buf).await
}
async fn read_vectored<V: IoVectoredBufMut>(&mut self, bufs: V) -> BufResult<usize, V> {
let (result, bufs) = self.inner.recvmsg(bufs).await.into_parts();
BufResult(result.map(|(n, _)| n), bufs)
}
}
#[cfg(target_os = "linux")]
impl<T> AsyncReadManaged for OwnedReadHalf<T> {
type Buffer = PooledBuf;
async fn read_managed(&mut self, len: usize) -> std::io::Result<Option<Self::Buffer>> {
self.inner.recv_managed(len).await
}
}
pub struct OwnedWriteHalf<T> {
pub(crate) inner: Socket,
pub(crate) shutdown_on_drop: bool,
pub(crate) _stream: PhantomData<fn() -> T>,
}
impl<T> fmt::Debug for OwnedWriteHalf<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OwnedWriteHalf").finish_non_exhaustive()
}
}
impl<T> AsyncWrite for OwnedWriteHalf<T> {
async fn write<B: IoBuf>(&mut self, buf: B) -> BufResult<usize, B> {
self.inner.send(buf).await
}
async fn write_vectored<V: IoVectoredBuf>(&mut self, bufs: V) -> BufResult<usize, V> {
let (res, bufs) = self.inner.sendmsg(bufs, None, None::<Vec<u8>>).await.into_parts();
BufResult(res.map(|(n, _)| n), bufs)
}
async fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
async fn shutdown(&mut self) -> std::io::Result<()> {
self.inner.shutdown(Shutdown::Write)
}
}
impl<T> Drop for OwnedWriteHalf<T> {
fn drop(&mut self) {
if self.shutdown_on_drop {
let _ = self.inner.shutdown(Shutdown::Write);
}
}
}
#[allow(private_bounds)]
impl<T: From<Socket>> OwnedReadHalf<T> {
pub fn reunite(self, other: OwnedWriteHalf<T>) -> Result<T, ReuniteError<OwnedReadHalf<T>, OwnedWriteHalf<T>>> {
if !self.inner.handle.ptr_eq(&other.inner.handle) {
return Err(ReuniteError::mismatched(self, other));
}
if self.inner.handle.strong_count() != 2 {
return Err(ReuniteError::not_quiescent(self, other));
}
let mut other = other;
other.shutdown_on_drop = false;
drop(other);
let socket = self.inner.clone();
drop(self);
Ok(T::from(socket))
}
}
#[allow(private_bounds)]
impl<T: From<Socket>> OwnedWriteHalf<T> {
pub fn reunite(self, other: OwnedReadHalf<T>) -> Result<T, ReuniteError<OwnedReadHalf<T>, OwnedWriteHalf<T>>> {
other.reunite(self)
}
}