refactor(lib): Use pin-project crate to perform pin projections
Remove all pin-related `unsafe` code from Hyper, as well as the now-unused 'pin-utils' dependency.
This commit is contained in:
		
				
					committed by
					
						 Sean McArthur
						Sean McArthur
					
				
			
			
				
	
			
			
			
						parent
						
							d406602c5d
						
					
				
				
					commit
					4c552a4960
				
			| @@ -34,7 +34,8 @@ iovec = "0.1" | |||||||
| itoa = "0.4.1" | itoa = "0.4.1" | ||||||
| log = "0.4" | log = "0.4" | ||||||
| net2 = { version = "0.2.32", optional = true } | net2 = { version = "0.2.32", optional = true } | ||||||
| pin-utils = "=0.1.0-alpha.4" | pin-project = { version = "0.4.0-alpha.7", features = ["project_attr"] } | ||||||
|  |  | ||||||
| time = "0.1" | time = "0.1" | ||||||
| tokio = { version = "=0.2.0-alpha.4", optional = true, default-features = false, features = ["rt-full"] } | tokio = { version = "=0.2.0-alpha.4", optional = true, default-features = false, features = ["rt-full"] } | ||||||
| tower-service = "=0.3.0-alpha.1" | tower-service = "=0.3.0-alpha.1" | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ use std::mem; | |||||||
|  |  | ||||||
| use futures_util::FutureExt as _; | use futures_util::FutureExt as _; | ||||||
| use tokio_sync::{mpsc, watch}; | use tokio_sync::{mpsc, watch}; | ||||||
|  | use pin_project::pin_project; | ||||||
|  |  | ||||||
| use super::{Future, Never, Poll, Pin, task}; | use super::{Future, Never, Poll, Pin, task}; | ||||||
|  |  | ||||||
| @@ -43,7 +44,9 @@ pub struct Watch { | |||||||
| } | } | ||||||
|  |  | ||||||
| #[allow(missing_debug_implementations)] | #[allow(missing_debug_implementations)] | ||||||
|  | #[pin_project] | ||||||
| pub struct Watching<F, FN> { | pub struct Watching<F, FN> { | ||||||
|  |     #[pin] | ||||||
|     future: F, |     future: F, | ||||||
|     state: State<FN>, |     state: State<FN>, | ||||||
|     watch: Watch, |     watch: Watch, | ||||||
| @@ -95,10 +98,10 @@ where | |||||||
| { | { | ||||||
|     type Output = F::Output; |     type Output = F::Output; | ||||||
|  |  | ||||||
|     fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> { |     fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> { | ||||||
|         let me = unsafe { self.get_unchecked_mut() }; |  | ||||||
|         loop { |         loop { | ||||||
|             match mem::replace(&mut me.state, State::Draining) { |             let me = self.project(); | ||||||
|  |             match mem::replace(me.state, State::Draining) { | ||||||
|                 State::Watch(on_drain) => { |                 State::Watch(on_drain) => { | ||||||
|                     let recv = me.watch.rx.recv_ref(); |                     let recv = me.watch.rx.recv_ref(); | ||||||
|                     futures_util::pin_mut!(recv); |                     futures_util::pin_mut!(recv); | ||||||
| @@ -106,17 +109,17 @@ where | |||||||
|                     match recv.poll_unpin(cx) { |                     match recv.poll_unpin(cx) { | ||||||
|                         Poll::Ready(None) => { |                         Poll::Ready(None) => { | ||||||
|                             // Drain has been triggered! |                             // Drain has been triggered! | ||||||
|                             on_drain(unsafe { Pin::new_unchecked(&mut me.future) }); |                             on_drain(me.future); | ||||||
|                         }, |                         }, | ||||||
|                         Poll::Ready(Some(_/*State::Open*/)) | |                         Poll::Ready(Some(_/*State::Open*/)) | | ||||||
|                         Poll::Pending => { |                         Poll::Pending => { | ||||||
|                             me.state = State::Watch(on_drain); |                             *me.state = State::Watch(on_drain); | ||||||
|                             return unsafe { Pin::new_unchecked(&mut me.future) }.poll(cx); |                             return me.future.poll(cx); | ||||||
|                         }, |                         }, | ||||||
|                     } |                     } | ||||||
|                 }, |                 }, | ||||||
|                 State::Draining => { |                 State::Draining => { | ||||||
|                     return unsafe { Pin::new_unchecked(&mut me.future) }.poll(cx); |                     return me.future.poll(cx) | ||||||
|                 }, |                 }, | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| use std::error::Error as StdError; | use std::error::Error as StdError; | ||||||
| use std::marker::Unpin; | use std::marker::Unpin; | ||||||
|  |  | ||||||
|  | use pin_project::{pin_project, project}; | ||||||
| use h2::Reason; | use h2::Reason; | ||||||
| use h2::server::{Builder, Connection, Handshake, SendResponse}; | use h2::server::{Builder, Connection, Handshake, SendResponse}; | ||||||
| use tokio_io::{AsyncRead, AsyncWrite}; | use tokio_io::{AsyncRead, AsyncWrite}; | ||||||
| @@ -199,19 +200,22 @@ where | |||||||
| } | } | ||||||
|  |  | ||||||
| #[allow(missing_debug_implementations)] | #[allow(missing_debug_implementations)] | ||||||
|  | #[pin_project] | ||||||
| pub struct H2Stream<F, B> | pub struct H2Stream<F, B> | ||||||
| where | where | ||||||
|     B: Payload, |     B: Payload, | ||||||
| { | { | ||||||
|     reply: SendResponse<SendBuf<B::Data>>, |     reply: SendResponse<SendBuf<B::Data>>, | ||||||
|  |     #[pin] | ||||||
|     state: H2StreamState<F, B>, |     state: H2StreamState<F, B>, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[pin_project] | ||||||
| enum H2StreamState<F, B> | enum H2StreamState<F, B> | ||||||
| where | where | ||||||
|     B: Payload, |     B: Payload, | ||||||
| { | { | ||||||
|     Service(F), |     Service(#[pin] F), | ||||||
|     Body(PipeToSendStream<B>), |     Body(PipeToSendStream<B>), | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -229,6 +233,19 @@ where | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | macro_rules! reply { | ||||||
|  |     ($me:expr, $res:expr, $eos:expr) => ({ | ||||||
|  |         match $me.reply.send_response($res, $eos) { | ||||||
|  |             Ok(tx) => tx, | ||||||
|  |             Err(e) => { | ||||||
|  |                 debug!("send response error: {}", e); | ||||||
|  |                 $me.reply.send_reset(Reason::INTERNAL_ERROR); | ||||||
|  |                 return Poll::Ready(Err(crate::Error::new_h2(e))); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }) | ||||||
|  | } | ||||||
|  |  | ||||||
| impl<F, B, E> H2Stream<F, B> | impl<F, B, E> H2Stream<F, B> | ||||||
| where | where | ||||||
|     F: Future<Output = Result<Response<B>, E>>, |     F: Future<Output = Result<Response<B>, E>>, | ||||||
| @@ -236,13 +253,14 @@ where | |||||||
|     B::Data: Unpin, |     B::Data: Unpin, | ||||||
|     E: Into<Box<dyn StdError + Send + Sync>>, |     E: Into<Box<dyn StdError + Send + Sync>>, | ||||||
| { | { | ||||||
|     fn poll2(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> { |     #[project] | ||||||
|         // Safety: State::{Service, Body} futures are never moved |     fn poll2(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> { | ||||||
|         let me = unsafe { self.get_unchecked_mut() }; |  | ||||||
|         loop { |         loop { | ||||||
|             let next = match me.state { |             let mut me = self.project(); | ||||||
|                 H2StreamState::Service(ref mut h) => { |             #[project] | ||||||
|                     let res = match unsafe { Pin::new_unchecked(h) }.poll(cx) { |             let next = match me.state.project() { | ||||||
|  |                 H2StreamState::Service(h) => { | ||||||
|  |                     let res = match h.poll(cx) { | ||||||
|                         Poll::Ready(Ok(r)) => r, |                         Poll::Ready(Ok(r)) => r, | ||||||
|                         Poll::Pending => { |                         Poll::Pending => { | ||||||
|                             // Response is not yet ready, so we want to check if the client has sent a |                             // Response is not yet ready, so we want to check if the client has sent a | ||||||
| @@ -274,18 +292,7 @@ where | |||||||
|                         .expect("DATE is a valid HeaderName") |                         .expect("DATE is a valid HeaderName") | ||||||
|                         .or_insert_with(crate::proto::h1::date::update_and_header_value); |                         .or_insert_with(crate::proto::h1::date::update_and_header_value); | ||||||
|  |  | ||||||
|                     macro_rules! reply { |  | ||||||
|                         ($eos:expr) => ({ |  | ||||||
|                             match me.reply.send_response(res, $eos) { |  | ||||||
|                                 Ok(tx) => tx, |  | ||||||
|                                 Err(e) => { |  | ||||||
|                                     debug!("send response error: {}", e); |  | ||||||
|                                     me.reply.send_reset(Reason::INTERNAL_ERROR); |  | ||||||
|                                     return Poll::Ready(Err(crate::Error::new_h2(e))); |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
|                         }) |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                     // automatically set Content-Length from body... |                     // automatically set Content-Length from body... | ||||||
|                     if let Some(len) = body.size_hint().exact() { |                     if let Some(len) = body.size_hint().exact() { | ||||||
| @@ -293,10 +300,10 @@ where | |||||||
|                     } |                     } | ||||||
|  |  | ||||||
|                     if !body.is_end_stream() { |                     if !body.is_end_stream() { | ||||||
|                         let body_tx = reply!(false); |                         let body_tx = reply!(me, res, false); | ||||||
|                         H2StreamState::Body(PipeToSendStream::new(body, body_tx)) |                         H2StreamState::Body(PipeToSendStream::new(body, body_tx)) | ||||||
|                     } else { |                     } else { | ||||||
|                         reply!(true); |                         reply!(me, res, true); | ||||||
|                         return Poll::Ready(Ok(())); |                         return Poll::Ready(Ok(())); | ||||||
|                     } |                     } | ||||||
|                 }, |                 }, | ||||||
| @@ -304,7 +311,7 @@ where | |||||||
|                     return Pin::new(pipe).poll(cx); |                     return Pin::new(pipe).poll(cx); | ||||||
|                 } |                 } | ||||||
|             }; |             }; | ||||||
|             me.state = next; |             me.state.set(next); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -16,8 +16,8 @@ use std::mem; | |||||||
|  |  | ||||||
| use bytes::Bytes; | use bytes::Bytes; | ||||||
| use futures_core::Stream; | use futures_core::Stream; | ||||||
| use pin_utils::{unsafe_pinned, unsafe_unpinned}; |  | ||||||
| use tokio_io::{AsyncRead, AsyncWrite}; | use tokio_io::{AsyncRead, AsyncWrite}; | ||||||
|  | use pin_project::{pin_project, project}; | ||||||
| #[cfg(feature = "runtime")] use tokio_net::driver::Handle; | #[cfg(feature = "runtime")] use tokio_net::driver::Handle; | ||||||
|  |  | ||||||
| use crate::body::{Body, Payload}; | use crate::body::{Body, Payload}; | ||||||
| @@ -69,8 +69,10 @@ enum ConnectionMode { | |||||||
| /// | /// | ||||||
| /// Yields `Connecting`s that are futures that should be put on a reactor. | /// Yields `Connecting`s that are futures that should be put on a reactor. | ||||||
| #[must_use = "streams do nothing unless polled"] | #[must_use = "streams do nothing unless polled"] | ||||||
|  | #[pin_project] | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct Serve<I, S, E = Exec> { | pub struct Serve<I, S, E = Exec> { | ||||||
|  |     #[pin] | ||||||
|     incoming: I, |     incoming: I, | ||||||
|     make_service: S, |     make_service: S, | ||||||
|     protocol: Http<E>, |     protocol: Http<E>, | ||||||
| @@ -81,16 +83,20 @@ pub struct Serve<I, S, E = Exec> { | |||||||
| /// Wraps the future returned from `MakeService` into one that returns | /// Wraps the future returned from `MakeService` into one that returns | ||||||
| /// a `Connection`. | /// a `Connection`. | ||||||
| #[must_use = "futures do nothing unless polled"] | #[must_use = "futures do nothing unless polled"] | ||||||
|  | #[pin_project] | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct Connecting<I, F, E = Exec> { | pub struct Connecting<I, F, E = Exec> { | ||||||
|  |     #[pin] | ||||||
|     future: F, |     future: F, | ||||||
|     io: Option<I>, |     io: Option<I>, | ||||||
|     protocol: Http<E>, |     protocol: Http<E>, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[must_use = "futures do nothing unless polled"] | #[must_use = "futures do nothing unless polled"] | ||||||
|  | #[pin_project] | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub(super) struct SpawnAll<I, S, E> { | pub(super) struct SpawnAll<I, S, E> { | ||||||
|  |     #[pin] | ||||||
|     pub(super) serve: Serve<I, S, E>, |     pub(super) serve: Serve<I, S, E>, | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -98,6 +104,7 @@ pub(super) struct SpawnAll<I, S, E> { | |||||||
| /// | /// | ||||||
| /// Polling this future will drive HTTP forward. | /// Polling this future will drive HTTP forward. | ||||||
| #[must_use = "futures do nothing unless polled"] | #[must_use = "futures do nothing unless polled"] | ||||||
|  | #[pin_project] | ||||||
| pub struct Connection<T, S, E = Exec> | pub struct Connection<T, S, E = Exec> | ||||||
| where | where | ||||||
|     S: Service<Body>, |     S: Service<Body>, | ||||||
| @@ -119,9 +126,10 @@ where | |||||||
|     fallback: Fallback<E>, |     fallback: Fallback<E>, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[pin_project] | ||||||
| pub(super) enum Either<A, B> { | pub(super) enum Either<A, B> { | ||||||
|     A(A), |     A(#[pin] A), | ||||||
|     B(B), |     B(#[pin] B), | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Clone, Debug)] | #[derive(Clone, Debug)] | ||||||
| @@ -484,10 +492,8 @@ where | |||||||
|     /// |     /// | ||||||
|     /// This `Connection` should continue to be polled until shutdown |     /// This `Connection` should continue to be polled until shutdown | ||||||
|     /// can finish. |     /// can finish. | ||||||
|     pub fn graceful_shutdown(self: Pin<&mut Self>) { |     pub fn graceful_shutdown(mut self: Pin<&mut Self>) { | ||||||
|         // Safety: neither h1 nor h2 poll any of the generic futures |         match self.project().conn.as_mut().unwrap() { | ||||||
|         // in these methods. |  | ||||||
|         match unsafe { self.get_unchecked_mut() }.conn.as_mut().unwrap() { |  | ||||||
|             Either::A(ref mut h1) => { |             Either::A(ref mut h1) => { | ||||||
|                 h1.disable_keep_alive(); |                 h1.disable_keep_alive(); | ||||||
|             }, |             }, | ||||||
| @@ -672,9 +678,6 @@ where | |||||||
| // ===== impl Serve ===== | // ===== impl Serve ===== | ||||||
|  |  | ||||||
| impl<I, S, E> Serve<I, S, E> { | impl<I, S, E> Serve<I, S, E> { | ||||||
|     unsafe_pinned!(incoming: I); |  | ||||||
|     unsafe_unpinned!(make_service: S); |  | ||||||
|  |  | ||||||
|     /// Spawn all incoming connections onto the executor in `Http`. |     /// Spawn all incoming connections onto the executor in `Http`. | ||||||
|     pub(super) fn spawn_all(self) -> SpawnAll<I, S, E> { |     pub(super) fn spawn_all(self) -> SpawnAll<I, S, E> { | ||||||
|         SpawnAll { |         SpawnAll { | ||||||
| @@ -709,7 +712,7 @@ where | |||||||
|     type Item = crate::Result<Connecting<IO, S::Future, E>>; |     type Item = crate::Result<Connecting<IO, S::Future, E>>; | ||||||
|  |  | ||||||
|     fn poll_next(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Self::Item>> { |     fn poll_next(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Self::Item>> { | ||||||
|         match ready!(self.as_mut().make_service().poll_ready_ref(cx)) { |         match ready!(self.project().make_service.poll_ready_ref(cx)) { | ||||||
|             Ok(()) => (), |             Ok(()) => (), | ||||||
|             Err(e) => { |             Err(e) => { | ||||||
|                 trace!("make_service closed"); |                 trace!("make_service closed"); | ||||||
| @@ -717,9 +720,9 @@ where | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if let Some(item) = ready!(self.as_mut().incoming().poll_next(cx)) { |         if let Some(item) = ready!(self.project().incoming.poll_next(cx)) { | ||||||
|             let io = item.map_err(crate::Error::new_accept)?; |             let io = item.map_err(crate::Error::new_accept)?; | ||||||
|             let new_fut = self.as_mut().make_service().make_service_ref(&io); |             let new_fut = self.project().make_service.make_service_ref(&io); | ||||||
|             Poll::Ready(Some(Ok(Connecting { |             Poll::Ready(Some(Ok(Connecting { | ||||||
|                 future: new_fut, |                 future: new_fut, | ||||||
|                 io: Some(io), |                 io: Some(io), | ||||||
| @@ -733,10 +736,6 @@ where | |||||||
|  |  | ||||||
| // ===== impl Connecting ===== | // ===== impl Connecting ===== | ||||||
|  |  | ||||||
| impl<I, F, E> Connecting<I, F, E> { |  | ||||||
|     unsafe_pinned!(future: F); |  | ||||||
|     unsafe_unpinned!(io: Option<I>); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl<I, F, S, FE, E, B> Future for Connecting<I, F, E> | impl<I, F, S, FE, E, B> Future for Connecting<I, F, E> | ||||||
| where | where | ||||||
| @@ -750,8 +749,8 @@ where | |||||||
|     type Output = Result<Connection<I, S, E>, FE>; |     type Output = Result<Connection<I, S, E>, FE>; | ||||||
|  |  | ||||||
|     fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> { |     fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> { | ||||||
|         let service = ready!(self.as_mut().future().poll(cx))?; |         let service = ready!(self.project().future.poll(cx))?; | ||||||
|         let io = self.as_mut().io().take().expect("polled after complete"); |         let io = self.project().io.take().expect("polled after complete"); | ||||||
|         Poll::Ready(Ok(self.protocol.serve_connection(io, service))) |         Poll::Ready(Ok(self.protocol.serve_connection(io, service))) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -784,17 +783,15 @@ where | |||||||
|     B: Payload, |     B: Payload, | ||||||
|     E: H2Exec<<S::Service as Service<Body>>::Future, B>, |     E: H2Exec<<S::Service as Service<Body>>::Future, B>, | ||||||
| { | { | ||||||
|     pub(super) fn poll_watch<W>(self: Pin<&mut Self>, cx: &mut task::Context<'_>, watcher: &W) -> Poll<crate::Result<()>> |     pub(super) fn poll_watch<W>(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, watcher: &W) -> Poll<crate::Result<()>> | ||||||
|     where |     where | ||||||
|         E: NewSvcExec<IO, S::Future, S::Service, E, W>, |         E: NewSvcExec<IO, S::Future, S::Service, E, W>, | ||||||
|         W: Watcher<IO, S::Service, E>, |         W: Watcher<IO, S::Service, E>, | ||||||
|     { |     { | ||||||
|         // Safety: futures are never moved... lolwtf |  | ||||||
|         let me = unsafe { self.get_unchecked_mut() }; |  | ||||||
|         loop { |         loop { | ||||||
|             if let Some(connecting) = ready!(unsafe { Pin::new_unchecked(&mut me.serve) }.poll_next(cx)?) { |             if let Some(connecting) = ready!(self.project().serve.poll_next(cx)?) { | ||||||
|                 let fut = NewSvcTask::new(connecting, watcher.clone()); |                 let fut = NewSvcTask::new(connecting, watcher.clone()); | ||||||
|                 me.serve.protocol.exec.execute_new_svc(fut)?; |                 self.project().serve.project().protocol.exec.execute_new_svc(fut)?; | ||||||
|             } else { |             } else { | ||||||
|                 return Poll::Ready(Ok(())); |                 return Poll::Ready(Ok(())); | ||||||
|             } |             } | ||||||
| @@ -810,13 +807,13 @@ where | |||||||
| { | { | ||||||
|     type Output = A::Output; |     type Output = A::Output; | ||||||
|  |  | ||||||
|     fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> { |     #[project] | ||||||
|  |     fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> { | ||||||
|         // Just simple pin projection to the inner variants |         // Just simple pin projection to the inner variants | ||||||
|         unsafe { |         #[project] | ||||||
|             match self.get_unchecked_mut() { |         match self.project() { | ||||||
|                 Either::A(a) => Pin::new_unchecked(a).poll(cx), |             Either::A(a) => a.poll(cx), | ||||||
|                 Either::B(b) => Pin::new_unchecked(b).poll(cx), |             Either::B(b) => b.poll(cx), | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -830,6 +827,7 @@ pub(crate) mod spawn_all { | |||||||
|     use crate::common::{Future, Pin, Poll, Unpin, task}; |     use crate::common::{Future, Pin, Poll, Unpin, task}; | ||||||
|     use crate::service::Service; |     use crate::service::Service; | ||||||
|     use super::{Connecting, UpgradeableConnection}; |     use super::{Connecting, UpgradeableConnection}; | ||||||
|  |     use pin_project::{pin_project, project}; | ||||||
|  |  | ||||||
|     // Used by `SpawnAll` to optionally watch a `Connection` future. |     // Used by `SpawnAll` to optionally watch a `Connection` future. | ||||||
|     // |     // | ||||||
| @@ -872,14 +870,18 @@ pub(crate) mod spawn_all { | |||||||
|     // |     // | ||||||
|     // Users cannot import this type, nor the associated `NewSvcExec`. Instead, |     // Users cannot import this type, nor the associated `NewSvcExec`. Instead, | ||||||
|     // a blanket implementation for `Executor<impl Future>` is sufficient. |     // a blanket implementation for `Executor<impl Future>` is sufficient. | ||||||
|  |  | ||||||
|  |     #[pin_project] | ||||||
|     #[allow(missing_debug_implementations)] |     #[allow(missing_debug_implementations)] | ||||||
|     pub struct NewSvcTask<I, N, S: Service<Body>, E, W: Watcher<I, S, E>> { |     pub struct NewSvcTask<I, N, S: Service<Body>, E, W: Watcher<I, S, E>> { | ||||||
|  |         #[pin] | ||||||
|         state: State<I, N, S, E, W>, |         state: State<I, N, S, E, W>, | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     enum State<I, N, S: Service<Body>, E, W: Watcher<I, S, E>> { |     #[pin_project] | ||||||
|         Connecting(Connecting<I, N, E>, W), |     pub enum State<I, N, S: Service<Body>, E, W: Watcher<I, S, E>> { | ||||||
|         Connected(W::Future), |         Connecting(#[pin] Connecting<I, N, E>, W), | ||||||
|  |         Connected(#[pin] W::Future), | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     impl<I, N, S: Service<Body>, E, W: Watcher<I, S, E>> NewSvcTask<I, N, S, E, W> { |     impl<I, N, S: Service<Body>, E, W: Watcher<I, S, E>> NewSvcTask<I, N, S, E, W> { | ||||||
| @@ -903,16 +905,19 @@ pub(crate) mod spawn_all { | |||||||
|     { |     { | ||||||
|         type Output = (); |         type Output = (); | ||||||
|  |  | ||||||
|         fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> { |         #[project] | ||||||
|  |         fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> { | ||||||
|             // If it weren't for needing to name this type so the `Send` bounds |             // If it weren't for needing to name this type so the `Send` bounds | ||||||
|             // could be projected to the `Serve` executor, this could just be |             // could be projected to the `Serve` executor, this could just be | ||||||
|             // an `async fn`, and much safer. Woe is me. |             // an `async fn`, and much safer. Woe is me. | ||||||
|  |  | ||||||
|             let me = unsafe { self.get_unchecked_mut() }; |  | ||||||
|             loop { |             loop { | ||||||
|                 let next = match me.state { |                 let mut me = self.project(); | ||||||
|                     State::Connecting(ref mut connecting, ref watcher) => { |                 let next = { | ||||||
|                         let res = ready!(unsafe { Pin::new_unchecked(connecting).poll(cx) }); |                     #[project] | ||||||
|  |                     match me.state.project() { | ||||||
|  |                         State::Connecting(connecting, watcher) => { | ||||||
|  |                             let res = ready!(connecting.poll(cx)); | ||||||
|                             let conn = match res { |                             let conn = match res { | ||||||
|                                 Ok(conn) => conn, |                                 Ok(conn) => conn, | ||||||
|                                 Err(err) => { |                                 Err(err) => { | ||||||
| @@ -924,8 +929,8 @@ pub(crate) mod spawn_all { | |||||||
|                             let connected = watcher.watch(conn.with_upgrades()); |                             let connected = watcher.watch(conn.with_upgrades()); | ||||||
|                             State::Connected(connected) |                             State::Connected(connected) | ||||||
|                         }, |                         }, | ||||||
|                     State::Connected(ref mut future) => { |                         State::Connected(future) => { | ||||||
|                         return unsafe { Pin::new_unchecked(future) } |                             return future  | ||||||
|                                 .poll(cx) |                                 .poll(cx) | ||||||
|                                 .map(|res| { |                                 .map(|res| { | ||||||
|                                     if let Err(err) = res { |                                     if let Err(err) = res { | ||||||
| @@ -933,9 +938,10 @@ pub(crate) mod spawn_all { | |||||||
|                                     } |                                     } | ||||||
|                                 }); |                                 }); | ||||||
|                         } |                         } | ||||||
|  |                     } | ||||||
|                 }; |                 }; | ||||||
|  |  | ||||||
|                 me.state = next; |                 me.state.set(next); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -59,8 +59,8 @@ use std::fmt; | |||||||
| #[cfg(feature = "runtime")] use std::time::Duration; | #[cfg(feature = "runtime")] use std::time::Duration; | ||||||
|  |  | ||||||
| use futures_core::Stream; | use futures_core::Stream; | ||||||
| use pin_utils::unsafe_pinned; |  | ||||||
| use tokio_io::{AsyncRead, AsyncWrite}; | use tokio_io::{AsyncRead, AsyncWrite}; | ||||||
|  | use pin_project::pin_project; | ||||||
|  |  | ||||||
| use crate::body::{Body, Payload}; | use crate::body::{Body, Payload}; | ||||||
| use crate::common::exec::{Exec, H2Exec, NewSvcExec}; | use crate::common::exec::{Exec, H2Exec, NewSvcExec}; | ||||||
| @@ -78,7 +78,9 @@ use self::shutdown::{Graceful, GracefulWatcher}; | |||||||
| /// handlers. It is built using the [`Builder`](Builder), and the future | /// handlers. It is built using the [`Builder`](Builder), and the future | ||||||
| /// completes when the server has been shutdown. It should be run by an | /// completes when the server has been shutdown. It should be run by an | ||||||
| /// `Executor`. | /// `Executor`. | ||||||
|  | #[pin_project] | ||||||
| pub struct Server<I, S, E = Exec> { | pub struct Server<I, S, E = Exec> { | ||||||
|  |     #[pin] | ||||||
|     spawn_all: SpawnAll<I, S, E>, |     spawn_all: SpawnAll<I, S, E>, | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -101,11 +103,6 @@ impl<I> Server<I, ()> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<I, S, E> Server<I, S, E> { |  | ||||||
|     // Never moved, just projected |  | ||||||
|     unsafe_pinned!(spawn_all: SpawnAll<I, S, E>); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[cfg(feature = "runtime")] | #[cfg(feature = "runtime")] | ||||||
| impl Server<AddrIncoming, ()> { | impl Server<AddrIncoming, ()> { | ||||||
|     /// Binds to the provided address, and returns a [`Builder`](Builder). |     /// Binds to the provided address, and returns a [`Builder`](Builder). | ||||||
| @@ -216,8 +213,8 @@ where | |||||||
| { | { | ||||||
|     type Output = crate::Result<()>; |     type Output = crate::Result<()>; | ||||||
|  |  | ||||||
|     fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> { |     fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> { | ||||||
|         self.spawn_all().poll_watch(cx, &NoopWatcher) |         self.project().spawn_all.poll_watch(cx, &NoopWatcher) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ use std::error::Error as StdError; | |||||||
|  |  | ||||||
| use futures_core::Stream; | use futures_core::Stream; | ||||||
| use tokio_io::{AsyncRead, AsyncWrite}; | use tokio_io::{AsyncRead, AsyncWrite}; | ||||||
|  | use pin_project::{pin_project, project}; | ||||||
|  |  | ||||||
| use crate::body::{Body, Payload}; | use crate::body::{Body, Payload}; | ||||||
| use crate::common::drain::{self, Draining, Signal, Watch, Watching}; | use crate::common::drain::{self, Draining, Signal, Watch, Watching}; | ||||||
| @@ -11,14 +12,19 @@ use crate::service::{MakeServiceRef, Service}; | |||||||
| use super::conn::{SpawnAll, UpgradeableConnection, Watcher}; | use super::conn::{SpawnAll, UpgradeableConnection, Watcher}; | ||||||
|  |  | ||||||
| #[allow(missing_debug_implementations)] | #[allow(missing_debug_implementations)] | ||||||
|  | #[pin_project] | ||||||
| pub struct Graceful<I, S, F, E> { | pub struct Graceful<I, S, F, E> { | ||||||
|  |     #[pin] | ||||||
|     state: State<I, S, F, E>, |     state: State<I, S, F, E>, | ||||||
| } | } | ||||||
|  |  | ||||||
| enum State<I, S, F, E> { | #[pin_project] | ||||||
|  | pub(super) enum State<I, S, F, E> { | ||||||
|     Running { |     Running { | ||||||
|         drain: Option<(Signal, Watch)>, |         drain: Option<(Signal, Watch)>, | ||||||
|  |         #[pin] | ||||||
|         spawn_all: SpawnAll<I, S, E>, |         spawn_all: SpawnAll<I, S, E>, | ||||||
|  |         #[pin] | ||||||
|         signal: F, |         signal: F, | ||||||
|     }, |     }, | ||||||
|     Draining(Draining), |     Draining(Draining), | ||||||
| @@ -54,16 +60,18 @@ where | |||||||
| { | { | ||||||
|     type Output = crate::Result<()>; |     type Output = crate::Result<()>; | ||||||
|  |  | ||||||
|     fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> { |     #[project] | ||||||
|         // Safety: the futures are NEVER moved, self.state is overwritten instead. |     fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> { | ||||||
|         let me = unsafe { self.get_unchecked_mut() }; |         let mut me = self.project(); | ||||||
|         loop { |         loop { | ||||||
|             let next = match me.state { |             let next = { | ||||||
|  |                 #[project] | ||||||
|  |                 match me.state.project() { | ||||||
|                     State::Running { |                     State::Running { | ||||||
|                     ref mut drain, |                         drain, | ||||||
|                     ref mut spawn_all, |                         spawn_all, | ||||||
|                     ref mut signal, |                         signal, | ||||||
|                 } => match unsafe { Pin::new_unchecked(signal) }.poll(cx) { |                     } => match signal.poll(cx) { | ||||||
|                         Poll::Ready(()) => { |                         Poll::Ready(()) => { | ||||||
|                             debug!("signal received, starting graceful shutdown"); |                             debug!("signal received, starting graceful shutdown"); | ||||||
|                             let sig = drain |                             let sig = drain | ||||||
| @@ -78,15 +86,15 @@ where | |||||||
|                                 .expect("drain channel") |                                 .expect("drain channel") | ||||||
|                                 .1 |                                 .1 | ||||||
|                                 .clone(); |                                 .clone(); | ||||||
|                         return unsafe { Pin::new_unchecked(spawn_all) }.poll_watch(cx, &GracefulWatcher(watch)); |                             return spawn_all.poll_watch(cx, &GracefulWatcher(watch)); | ||||||
|                         }, |                         }, | ||||||
|                     }, |                     }, | ||||||
|                     State::Draining(ref mut draining) => { |                     State::Draining(ref mut draining) => { | ||||||
|                         return Pin::new(draining).poll(cx).map(Ok); |                         return Pin::new(draining).poll(cx).map(Ok); | ||||||
|                     } |                     } | ||||||
|  |                 } | ||||||
|             }; |             }; | ||||||
|             // It's important to just assign, not mem::replace or anything. |             me.state.set(next); | ||||||
|             me.state = next; |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user