use std::marker::PhantomData; use std::pin::Pin; use std::task::{Context, Poll}; use actix_codec::{AsyncRead, AsyncWrite, Decoder, Encoder, Framed}; use actix_utils::mpsc::Receiver; use futures::Stream; pub struct Connect where Codec: Encoder + Decoder, { io: Io, _t: PhantomData, } impl Connect where Io: AsyncRead + AsyncWrite, Codec: Encoder + Decoder, { pub(crate) fn new(io: Io) -> Self { Self { io, _t: PhantomData, } } pub fn codec( self, codec: Codec, ) -> ConnectResult::Item>> { ConnectResult { state: (), out: None, framed: Framed::new(self.io, codec), } } } #[pin_project::pin_project] pub struct ConnectResult { pub(crate) state: St, pub(crate) out: Option, #[pin] pub(crate) framed: Framed, } impl ConnectResult { #[inline] pub fn get_ref(&self) -> &Io { self.framed.get_ref() } #[inline] pub fn get_mut(&mut self) -> &mut Io { self.framed.get_mut() } pub fn out(self, out: U) -> ConnectResult where U: Stream::Item> + Unpin, { ConnectResult { state: self.state, framed: self.framed, out: Some(out), } } #[inline] pub fn state(self, state: S) -> ConnectResult { ConnectResult { state, framed: self.framed, out: self.out, } } } impl Stream for ConnectResult where Io: AsyncRead + AsyncWrite, Codec: Encoder + Decoder, { type Item = Result<::Item, ::Error>; fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { self.project().framed.next_item(cx) } } impl futures::Sink<::Item> for ConnectResult where Io: AsyncRead + AsyncWrite, Codec: Encoder + Decoder, { type Error = ::Error; fn poll_ready(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { if self.as_mut().project().framed.is_write_ready() { Poll::Ready(Ok(())) } else { Poll::Pending } } fn start_send( self: Pin<&mut Self>, item: ::Item, ) -> Result<(), Self::Error> { self.project().framed.write(item) } fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { self.as_mut().project().framed.flush(cx) } fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { self.as_mut().project().framed.close(cx) } }