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
				
			| @@ -1,6 +1,7 @@ | ||||
| use std::error::Error as StdError; | ||||
| use std::marker::Unpin; | ||||
|  | ||||
| use pin_project::{pin_project, project}; | ||||
| use h2::Reason; | ||||
| use h2::server::{Builder, Connection, Handshake, SendResponse}; | ||||
| use tokio_io::{AsyncRead, AsyncWrite}; | ||||
| @@ -199,19 +200,22 @@ where | ||||
| } | ||||
|  | ||||
| #[allow(missing_debug_implementations)] | ||||
| #[pin_project] | ||||
| pub struct H2Stream<F, B> | ||||
| where | ||||
|     B: Payload, | ||||
| { | ||||
|     reply: SendResponse<SendBuf<B::Data>>, | ||||
|     #[pin] | ||||
|     state: H2StreamState<F, B>, | ||||
| } | ||||
|  | ||||
| #[pin_project] | ||||
| enum H2StreamState<F, B> | ||||
| where | ||||
|     B: Payload, | ||||
| { | ||||
|     Service(F), | ||||
|     Service(#[pin] F), | ||||
|     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> | ||||
| where | ||||
|     F: Future<Output = Result<Response<B>, E>>, | ||||
| @@ -236,13 +253,14 @@ where | ||||
|     B::Data: Unpin, | ||||
|     E: Into<Box<dyn StdError + Send + Sync>>, | ||||
| { | ||||
|     fn poll2(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> { | ||||
|         // Safety: State::{Service, Body} futures are never moved | ||||
|         let me = unsafe { self.get_unchecked_mut() }; | ||||
|     #[project] | ||||
|     fn poll2(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> { | ||||
|         loop { | ||||
|             let next = match me.state { | ||||
|                 H2StreamState::Service(ref mut h) => { | ||||
|                     let res = match unsafe { Pin::new_unchecked(h) }.poll(cx) { | ||||
|             let mut me = self.project(); | ||||
|             #[project] | ||||
|             let next = match me.state.project() { | ||||
|                 H2StreamState::Service(h) => { | ||||
|                     let res = match h.poll(cx) { | ||||
|                         Poll::Ready(Ok(r)) => r, | ||||
|                         Poll::Pending => { | ||||
|                             // 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") | ||||
|                         .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... | ||||
|                     if let Some(len) = body.size_hint().exact() { | ||||
| @@ -293,10 +300,10 @@ where | ||||
|                     } | ||||
|  | ||||
|                     if !body.is_end_stream() { | ||||
|                         let body_tx = reply!(false); | ||||
|                         let body_tx = reply!(me, res, false); | ||||
|                         H2StreamState::Body(PipeToSendStream::new(body, body_tx)) | ||||
|                     } else { | ||||
|                         reply!(true); | ||||
|                         reply!(me, res, true); | ||||
|                         return Poll::Ready(Ok(())); | ||||
|                     } | ||||
|                 }, | ||||
| @@ -304,7 +311,7 @@ where | ||||
|                     return Pin::new(pipe).poll(cx); | ||||
|                 } | ||||
|             }; | ||||
|             me.state = next; | ||||
|             me.state.set(next); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user