From 9b7f7a02c0d3e1239ef8fbe3eeb1f4779ea31972 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 26 Nov 2019 22:44:05 +0100 Subject: [PATCH] Use #[pin_project] in stream implementation to get rid of remaining unsafe code Now the whole crate has no unsafe code left. --- src/stream.rs | 76 +++++++++++++++++++-------------------------------- 1 file changed, 28 insertions(+), 48 deletions(-) diff --git a/src/stream.rs b/src/stream.rs index 424e9d7..9fd9e2a 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -3,85 +3,65 @@ //! 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(S), + Plain(#[pin] S), /// Encrypted socket stream. - Tls(T), + Tls(#[pin] T), } impl AsyncRead for Stream { + #[project] fn poll_read( - mut self: Pin<&mut Self>, + self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll> { - match *self { - Stream::Plain(ref mut s) => { - let pinned = unsafe { Pin::new_unchecked(s) }; - pinned.poll_read(cx, buf) - } - Stream::Tls(ref mut s) => { - let pinned = unsafe { Pin::new_unchecked(s) }; - pinned.poll_read(cx, buf) - } + #[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( - mut self: Pin<&mut Self>, + self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll> { - match *self { - Stream::Plain(ref mut s) => { - let pinned = unsafe { Pin::new_unchecked(s) }; - pinned.poll_write(cx, buf) - } - Stream::Tls(ref mut s) => { - let pinned = unsafe { Pin::new_unchecked(s) }; - pinned.poll_write(cx, buf) - } + #[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), } } - fn poll_flush( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll> { - match *self { - Stream::Plain(ref mut s) => { - let pinned = unsafe { Pin::new_unchecked(s) }; - pinned.poll_flush(cx) - } - Stream::Tls(ref mut s) => { - let pinned = unsafe { Pin::new_unchecked(s) }; - pinned.poll_flush(cx) - } + #[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), } } - fn poll_close( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll> { - match *self { - Stream::Plain(ref mut s) => { - let pinned = unsafe { Pin::new_unchecked(s) }; - pinned.poll_close(cx) - } - Stream::Tls(ref mut s) => { - let pinned = unsafe { Pin::new_unchecked(s) }; - pinned.poll_close(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), } } }