//! `TcpStream` split support. //! //! A `TcpStream` can be split into a `ReadHalf` and a //! `WriteHalf` with the `TcpStream::split` method. `ReadHalf` //! implements `AsyncRead` while `WriteHalf` implements `AsyncWrite`. //! //! Compared to the generic split of `AsyncRead + AsyncWrite`, this specialized //! split has no associated overhead and enforces all invariants at the type //! level. use super::TcpStream; use tokio_io::{AsyncRead, AsyncWrite}; use bytes::{Buf, BufMut}; use std::io; use std::net::Shutdown; use std::pin::Pin; use std::task::{Context, Poll}; /// Read half of a `TcpStream`. #[derive(Debug)] pub struct ReadHalf<'a>(&'a TcpStream); /// Write half of a `TcpStream`. /// /// Note that in the `AsyncWrite` implemenation of `TcpStreamWriteHalf`, /// `poll_shutdown` actually shuts down the TCP stream in the write direction. #[derive(Debug)] pub struct WriteHalf<'a>(&'a TcpStream); pub(crate) fn split(stream: &mut TcpStream) -> (ReadHalf<'_>, WriteHalf<'_>) { (ReadHalf(&*stream), WriteHalf(&*stream)) } impl AsyncRead for ReadHalf<'_> { unsafe fn prepare_uninitialized_buffer(&self, _: &mut [u8]) -> bool { false } fn poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll> { self.0.poll_read_priv(cx, buf) } fn poll_read_buf( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut B, ) -> Poll> { self.0.poll_read_buf_priv(cx, buf) } } impl AsyncWrite for WriteHalf<'_> { fn poll_write( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll> { self.0.poll_write_priv(cx, buf) } #[inline] fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { // tcp flush is a no-op Poll::Ready(Ok(())) } // `poll_shutdown` on a write half shutdowns the stream in the "write" direction. fn poll_shutdown(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { self.0.shutdown(Shutdown::Write).into() } fn poll_write_buf( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut B, ) -> Poll> { self.0.poll_write_buf_priv(cx, buf) } } impl AsRef for ReadHalf<'_> { fn as_ref(&self) -> &TcpStream { self.0 } } impl AsRef for WriteHalf<'_> { fn as_ref(&self) -> &TcpStream { self.0 } }