use futures::{Sink, Stream};
use futures_util::stream::FusedStream;
use pin_project::pin_project;
use std::{
marker::PhantomData,
pin::Pin,
task::{Context, Poll},
};
#[pin_project]
pub struct DuplexStream<Si, Item, St> {
#[pin]
sink: Si,
#[pin]
stream: St,
_phantom: PhantomData<Item>,
}
impl<Si, Item, St> DuplexStream<Si, Item, St> {
pub fn new(sink: Si, stream: St) -> Self {
Self {
sink,
stream,
_phantom: Default::default(),
}
}
#[inline]
pub fn get_sink(&self) -> &Si {
&self.sink
}
#[inline]
pub fn get_sink_mut(&mut self) -> &mut Si {
&mut self.sink
}
#[inline]
pub fn get_sink_pin_mut(self: Pin<&mut Self>) -> Pin<&mut Si> {
self.project().sink
}
#[inline]
pub fn get_stream(&self) -> &St {
&self.stream
}
#[inline]
pub fn get_stream_mut(&mut self) -> &mut St {
&mut self.stream
}
#[inline]
pub fn get_stream_pin_mut(self: Pin<&mut Self>) -> Pin<&mut St> {
self.project().stream
}
#[inline]
pub fn split_into(self) -> (Si, St) {
(self.sink, self.stream)
}
}
impl<Si: Sink<Item>, Item, St: Stream> Sink<Item> for DuplexStream<Si, Item, St> {
type Error = Si::Error;
#[inline]
fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.as_mut().project().sink.poll_ready(cx)
}
#[inline]
fn start_send(mut self: Pin<&mut Self>, item: Item) -> Result<(), Self::Error> {
self.as_mut().project().sink.start_send(item)
}
#[inline]
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.as_mut().project().sink.poll_flush(cx)
}
#[inline]
fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.as_mut().project().sink.poll_close(cx)
}
}
impl<Si: Sink<Item>, Item, St: Stream> Stream for DuplexStream<Si, Item, St> {
type Item = St::Item;
#[inline]
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.as_mut().project().stream.poll_next(cx)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.stream.size_hint()
}
}
impl<Si: Sink<Item>, Item, St: FusedStream> FusedStream for DuplexStream<Si, Item, St> {
fn is_terminated(&self) -> bool {
self.stream.is_terminated()
}
}