From 9998f0fd0b5d6c433e14d2977b677cfe63dddd69 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Tue, 9 Jun 2020 08:02:14 +0900 Subject: [PATCH] refactor(lib): remove pin related unsafe code (#2220) --- Cargo.toml | 2 +- src/server/accept.rs | 12 +++++++++--- src/service/oneshot.rs | 36 ++++++++++++++---------------------- 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 06ec070f54..cebbfc3b23 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ httparse = "1.0" h2 = "0.2.2" itoa = "0.4.1" log = "0.4" -pin-project = "0.4.17" +pin-project = "0.4.20" time = "0.1" tower-service = "0.3" tokio = { version = "0.2.5", features = ["sync"] } diff --git a/src/server/accept.rs b/src/server/accept.rs index e56e3acf84..4ec287129d 100644 --- a/src/server/accept.rs +++ b/src/server/accept.rs @@ -8,6 +8,8 @@ #[cfg(feature = "stream")] use futures_core::Stream; +#[cfg(feature = "stream")] +use pin_project::pin_project; use crate::common::{ task::{self, Poll}, @@ -53,6 +55,9 @@ where { struct PollFn(F); + // The closure `F` is never pinned + impl Unpin for PollFn {} + impl Accept for PollFn where F: FnMut(&mut task::Context<'_>) -> Poll>>, @@ -63,7 +68,7 @@ where self: Pin<&mut Self>, cx: &mut task::Context<'_>, ) -> Poll>> { - unsafe { (self.get_unchecked_mut().0)(cx) } + (self.get_mut().0)(cx) } } @@ -81,7 +86,8 @@ pub fn from_stream(stream: S) -> impl Accept where S: Stream>, { - struct FromStream(S); + #[pin_project] + struct FromStream(#[pin] S); impl Accept for FromStream where @@ -93,7 +99,7 @@ where self: Pin<&mut Self>, cx: &mut task::Context<'_>, ) -> Poll>> { - unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().0).poll_next(cx) } + self.project().0.poll_next(cx) } } diff --git a/src/service/oneshot.rs b/src/service/oneshot.rs index 94f4b43a80..766d0c4689 100644 --- a/src/service/oneshot.rs +++ b/src/service/oneshot.rs @@ -1,8 +1,6 @@ // TODO: Eventually to be replaced with tower_util::Oneshot. -use std::marker::Unpin; -use std::mem; - +use pin_project::pin_project; use tower_service::Service; use crate::common::{task, Future, Pin, Poll}; @@ -20,24 +18,19 @@ where // is ready, and then calling `Service::call` with the request, and // waiting for that `Future`. #[allow(missing_debug_implementations)] +#[pin_project] pub struct Oneshot, Req> { + #[pin] state: State, } +#[pin_project(project = StateProj, project_replace = StateProjOwn)] enum State, Req> { NotReady(S, Req), - Called(S::Future), + Called(#[pin] S::Future), Tmp, } -// Unpin is projected to S::Future, but never S. -impl Unpin for Oneshot -where - S: Service, - S::Future: Unpin, -{ -} - impl Future for Oneshot where S: Service, @@ -45,24 +38,23 @@ where type Output = Result; fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll { - // Safety: The service's future is never moved once we get one. - let mut me = unsafe { Pin::get_unchecked_mut(self) }; + let mut me = self.project(); loop { - match me.state { - State::NotReady(ref mut svc, _) => { + match me.state.as_mut().project() { + StateProj::NotReady(ref mut svc, _) => { ready!(svc.poll_ready(cx))?; // fallthrough out of the match's borrow } - State::Called(ref mut fut) => { - return unsafe { Pin::new_unchecked(fut) }.poll(cx); + StateProj::Called(fut) => { + return fut.poll(cx); } - State::Tmp => unreachable!(), + StateProj::Tmp => unreachable!(), } - match mem::replace(&mut me.state, State::Tmp) { - State::NotReady(mut svc, req) => { - me.state = State::Called(svc.call(req)); + match me.state.as_mut().project_replace(State::Tmp) { + StateProjOwn::NotReady(mut svc, req) => { + me.state.set(State::Called(svc.call(req))); } _ => unreachable!(), }