Skip to content

Commit 4c552a4

Browse files
Aaron1011seanmonstar
authored andcommitted
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.
1 parent d406602 commit 4c552a4

File tree

6 files changed

+147
-125
lines changed

6 files changed

+147
-125
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ iovec = "0.1"
3434
itoa = "0.4.1"
3535
log = "0.4"
3636
net2 = { version = "0.2.32", optional = true }
37-
pin-utils = "=0.1.0-alpha.4"
37+
pin-project = { version = "0.4.0-alpha.7", features = ["project_attr"] }
38+
3839
time = "0.1"
3940
tokio = { version = "=0.2.0-alpha.4", optional = true, default-features = false, features = ["rt-full"] }
4041
tower-service = "=0.3.0-alpha.1"

src/common/drain.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::mem;
22

33
use futures_util::FutureExt as _;
44
use tokio_sync::{mpsc, watch};
5+
use pin_project::pin_project;
56

67
use super::{Future, Never, Poll, Pin, task};
78

@@ -43,7 +44,9 @@ pub struct Watch {
4344
}
4445

4546
#[allow(missing_debug_implementations)]
47+
#[pin_project]
4648
pub struct Watching<F, FN> {
49+
#[pin]
4750
future: F,
4851
state: State<FN>,
4952
watch: Watch,
@@ -95,28 +98,28 @@ where
9598
{
9699
type Output = F::Output;
97100

98-
fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
99-
let me = unsafe { self.get_unchecked_mut() };
101+
fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
100102
loop {
101-
match mem::replace(&mut me.state, State::Draining) {
103+
let me = self.project();
104+
match mem::replace(me.state, State::Draining) {
102105
State::Watch(on_drain) => {
103106
let recv = me.watch.rx.recv_ref();
104107
futures_util::pin_mut!(recv);
105108

106109
match recv.poll_unpin(cx) {
107110
Poll::Ready(None) => {
108111
// Drain has been triggered!
109-
on_drain(unsafe { Pin::new_unchecked(&mut me.future) });
112+
on_drain(me.future);
110113
},
111114
Poll::Ready(Some(_/*State::Open*/)) |
112115
Poll::Pending => {
113-
me.state = State::Watch(on_drain);
114-
return unsafe { Pin::new_unchecked(&mut me.future) }.poll(cx);
116+
*me.state = State::Watch(on_drain);
117+
return me.future.poll(cx);
115118
},
116119
}
117120
},
118121
State::Draining => {
119-
return unsafe { Pin::new_unchecked(&mut me.future) }.poll(cx);
122+
return me.future.poll(cx)
120123
},
121124
}
122125
}

src/proto/h2/server.rs

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::error::Error as StdError;
22
use std::marker::Unpin;
33

4+
use pin_project::{pin_project, project};
45
use h2::Reason;
56
use h2::server::{Builder, Connection, Handshake, SendResponse};
67
use tokio_io::{AsyncRead, AsyncWrite};
@@ -199,19 +200,22 @@ where
199200
}
200201

201202
#[allow(missing_debug_implementations)]
203+
#[pin_project]
202204
pub struct H2Stream<F, B>
203205
where
204206
B: Payload,
205207
{
206208
reply: SendResponse<SendBuf<B::Data>>,
209+
#[pin]
207210
state: H2StreamState<F, B>,
208211
}
209212

213+
#[pin_project]
210214
enum H2StreamState<F, B>
211215
where
212216
B: Payload,
213217
{
214-
Service(F),
218+
Service(#[pin] F),
215219
Body(PipeToSendStream<B>),
216220
}
217221

@@ -229,20 +233,34 @@ where
229233
}
230234
}
231235

236+
macro_rules! reply {
237+
($me:expr, $res:expr, $eos:expr) => ({
238+
match $me.reply.send_response($res, $eos) {
239+
Ok(tx) => tx,
240+
Err(e) => {
241+
debug!("send response error: {}", e);
242+
$me.reply.send_reset(Reason::INTERNAL_ERROR);
243+
return Poll::Ready(Err(crate::Error::new_h2(e)));
244+
}
245+
}
246+
})
247+
}
248+
232249
impl<F, B, E> H2Stream<F, B>
233250
where
234251
F: Future<Output = Result<Response<B>, E>>,
235252
B: Payload + Unpin,
236253
B::Data: Unpin,
237254
E: Into<Box<dyn StdError + Send + Sync>>,
238255
{
239-
fn poll2(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> {
240-
// Safety: State::{Service, Body} futures are never moved
241-
let me = unsafe { self.get_unchecked_mut() };
256+
#[project]
257+
fn poll2(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> {
242258
loop {
243-
let next = match me.state {
244-
H2StreamState::Service(ref mut h) => {
245-
let res = match unsafe { Pin::new_unchecked(h) }.poll(cx) {
259+
let mut me = self.project();
260+
#[project]
261+
let next = match me.state.project() {
262+
H2StreamState::Service(h) => {
263+
let res = match h.poll(cx) {
246264
Poll::Ready(Ok(r)) => r,
247265
Poll::Pending => {
248266
// Response is not yet ready, so we want to check if the client has sent a
@@ -274,37 +292,26 @@ where
274292
.expect("DATE is a valid HeaderName")
275293
.or_insert_with(crate::proto::h1::date::update_and_header_value);
276294

277-
macro_rules! reply {
278-
($eos:expr) => ({
279-
match me.reply.send_response(res, $eos) {
280-
Ok(tx) => tx,
281-
Err(e) => {
282-
debug!("send response error: {}", e);
283-
me.reply.send_reset(Reason::INTERNAL_ERROR);
284-
return Poll::Ready(Err(crate::Error::new_h2(e)));
285-
}
286-
}
287-
})
288-
}
295+
289296

290297
// automatically set Content-Length from body...
291298
if let Some(len) = body.size_hint().exact() {
292299
headers::set_content_length_if_missing(res.headers_mut(), len);
293300
}
294301

295302
if !body.is_end_stream() {
296-
let body_tx = reply!(false);
303+
let body_tx = reply!(me, res, false);
297304
H2StreamState::Body(PipeToSendStream::new(body, body_tx))
298305
} else {
299-
reply!(true);
306+
reply!(me, res, true);
300307
return Poll::Ready(Ok(()));
301308
}
302309
},
303310
H2StreamState::Body(ref mut pipe) => {
304311
return Pin::new(pipe).poll(cx);
305312
}
306313
};
307-
me.state = next;
314+
me.state.set(next);
308315
}
309316
}
310317
}

0 commit comments

Comments
 (0)