//! Convenience wrapper for streams to switch between plain TCP and TLS at runtime. //! //! There is no dependency on actual TLS implementations. Everything like //! `native_tls` or `openssl` will work as long as there is a TLS stream supporting standard //! `AsyncRead + AsyncWrite` traits. use pin_project::{pin_project, project}; use std::pin::Pin; use std::task::{Context, Poll}; use futures::io::{AsyncRead, AsyncWrite}; /// Stream, either plain TCP or TLS. #[pin_project] pub enum Stream { /// Unencrypted socket stream. Plain(#[pin] S), /// Encrypted socket stream. Tls(#[pin] T), } impl AsyncRead for Stream { #[project] fn poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll> { #[project] match self.project() { Stream::Plain(ref mut s) => Pin::new(s).poll_read(cx, buf), Stream::Tls(ref mut s) => Pin::new(s).poll_read(cx, buf), } } } impl AsyncWrite for Stream { #[project] fn poll_write( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll> { #[project] match self.project() { Stream::Plain(ref mut s) => Pin::new(s).poll_write(cx, buf), Stream::Tls(ref mut s) => Pin::new(s).poll_write(cx, buf), } } #[project] fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { #[project] match self.project() { Stream::Plain(ref mut s) => Pin::new(s).poll_flush(cx), Stream::Tls(ref mut s) => Pin::new(s).poll_flush(cx), } } #[project] fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { #[project] match self.project() { Stream::Plain(ref mut s) => Pin::new(s).poll_close(cx), Stream::Tls(ref mut s) => Pin::new(s).poll_close(cx), } } }