Skip to content

Commit 6a6a240

Browse files
authored
refactor(lib): Switch from pin-project to pin-project-lite (#2566)
Note the practical affects of this change: - Dependency count with --features full dropped from 65 to 55. - Time to compile after a clean dropped from 48s to 35s (on a pretty underpowered VM). Closes #2388
1 parent 0d82405 commit 6a6a240

File tree

15 files changed

+416
-281
lines changed

15 files changed

+416
-281
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ httparse = "1.4"
3434
h2 = { version = "0.3.3", optional = true }
3535
itoa = "0.4.1"
3636
tracing = { version = "0.1", default-features = false, features = ["std"] }
37-
pin-project = "1.0"
37+
pin-project-lite = "0.2.4"
3838
tower-service = "0.3"
3939
tokio = { version = "1", features = ["sync"] }
4040
want = "0.3"

src/client/conn.rs

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
4949
use std::error::Error as StdError;
5050
use std::fmt;
51-
#[cfg(feature = "http2")]
51+
#[cfg(not(all(feature = "http1", feature = "http2")))]
5252
use std::marker::PhantomData;
5353
use std::sync::Arc;
5454
#[cfg(all(feature = "runtime", feature = "http2"))]
@@ -57,12 +57,14 @@ use std::time::Duration;
5757
use bytes::Bytes;
5858
use futures_util::future::{self, Either, FutureExt as _};
5959
use httparse::ParserConfig;
60-
use pin_project::pin_project;
60+
use pin_project_lite::pin_project;
6161
use tokio::io::{AsyncRead, AsyncWrite};
6262
use tower_service::Service;
6363

6464
use super::dispatch;
6565
use crate::body::HttpBody;
66+
#[cfg(not(all(feature = "http1", feature = "http2")))]
67+
use crate::common::Never;
6668
use crate::common::{
6769
exec::{BoxSendFuture, Exec},
6870
task, Future, Pin, Poll,
@@ -74,17 +76,33 @@ use crate::upgrade::Upgraded;
7476
use crate::{Body, Request, Response};
7577

7678
#[cfg(feature = "http1")]
77-
type Http1Dispatcher<T, B, R> = proto::dispatch::Dispatcher<proto::dispatch::Client<B>, B, T, R>;
79+
type Http1Dispatcher<T, B> =
80+
proto::dispatch::Dispatcher<proto::dispatch::Client<B>, B, T, proto::h1::ClientTransaction>;
7881

79-
#[pin_project(project = ProtoClientProj)]
80-
enum ProtoClient<T, B>
81-
where
82-
B: HttpBody,
83-
{
84-
#[cfg(feature = "http1")]
85-
H1(#[pin] Http1Dispatcher<T, B, proto::h1::ClientTransaction>),
86-
#[cfg(feature = "http2")]
87-
H2(#[pin] proto::h2::ClientTask<B>, PhantomData<fn(T)>),
82+
#[cfg(not(feature = "http1"))]
83+
type Http1Dispatcher<T, B> = (Never, PhantomData<(T, Pin<Box<B>>)>);
84+
85+
#[cfg(feature = "http2")]
86+
type Http2ClientTask<B> = proto::h2::ClientTask<B>;
87+
88+
#[cfg(not(feature = "http2"))]
89+
type Http2ClientTask<B> = (Never, PhantomData<Pin<Box<B>>>);
90+
91+
pin_project! {
92+
#[project = ProtoClientProj]
93+
enum ProtoClient<T, B>
94+
where
95+
B: HttpBody,
96+
{
97+
H1 {
98+
#[pin]
99+
h1: Http1Dispatcher<T, B>,
100+
},
101+
H2 {
102+
#[pin]
103+
h2: Http2ClientTask<B>,
104+
},
105+
}
88106
}
89107

90108
/// Returns a handshake future over some IO.
@@ -405,18 +423,20 @@ where
405423
pub fn into_parts(self) -> Parts<T> {
406424
match self.inner.expect("already upgraded") {
407425
#[cfg(feature = "http1")]
408-
ProtoClient::H1(h1) => {
426+
ProtoClient::H1 { h1 } => {
409427
let (io, read_buf, _) = h1.into_inner();
410428
Parts {
411429
io,
412430
read_buf,
413431
_inner: (),
414432
}
415433
}
416-
#[cfg(feature = "http2")]
417-
ProtoClient::H2(..) => {
434+
ProtoClient::H2 { .. } => {
418435
panic!("http2 cannot into_inner");
419436
}
437+
438+
#[cfg(not(feature = "http1"))]
439+
ProtoClient::H1 { h1 } => match h1.0 {},
420440
}
421441
}
422442

@@ -434,9 +454,14 @@ where
434454
pub fn poll_without_shutdown(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> {
435455
match *self.inner.as_mut().expect("already upgraded") {
436456
#[cfg(feature = "http1")]
437-
ProtoClient::H1(ref mut h1) => h1.poll_without_shutdown(cx),
457+
ProtoClient::H1 { ref mut h1 } => h1.poll_without_shutdown(cx),
438458
#[cfg(feature = "http2")]
439-
ProtoClient::H2(ref mut h2, _) => Pin::new(h2).poll(cx).map_ok(|_| ()),
459+
ProtoClient::H2 { ref mut h2, .. } => Pin::new(h2).poll(cx).map_ok(|_| ()),
460+
461+
#[cfg(not(feature = "http1"))]
462+
ProtoClient::H1 { ref mut h1 } => match h1.0 {},
463+
#[cfg(not(feature = "http2"))]
464+
ProtoClient::H2 { ref mut h2, .. } => match h2.0 {},
440465
}
441466
}
442467

@@ -465,7 +490,7 @@ where
465490
proto::Dispatched::Shutdown => Poll::Ready(Ok(())),
466491
#[cfg(feature = "http1")]
467492
proto::Dispatched::Upgrade(pending) => match self.inner.take() {
468-
Some(ProtoClient::H1(h1)) => {
493+
Some(ProtoClient::H1 { h1 }) => {
469494
let (io, buf, _) = h1.into_inner();
470495
pending.fulfill(Upgraded::new(io, buf));
471496
Poll::Ready(Ok(()))
@@ -756,14 +781,14 @@ impl Builder {
756781
}
757782
let cd = proto::h1::dispatch::Client::new(rx);
758783
let dispatch = proto::h1::Dispatcher::new(cd, conn);
759-
ProtoClient::H1(dispatch)
784+
ProtoClient::H1 { h1: dispatch }
760785
}
761786
#[cfg(feature = "http2")]
762787
Proto::Http2 => {
763788
let h2 =
764789
proto::h2::client::handshake(io, rx, &opts.h2_builder, opts.exec.clone())
765790
.await?;
766-
ProtoClient::H2(h2, PhantomData)
791+
ProtoClient::H2 { h2 }
767792
}
768793
};
769794

@@ -817,9 +842,14 @@ where
817842
fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
818843
match self.project() {
819844
#[cfg(feature = "http1")]
820-
ProtoClientProj::H1(c) => c.poll(cx),
845+
ProtoClientProj::H1 { h1 } => h1.poll(cx),
821846
#[cfg(feature = "http2")]
822-
ProtoClientProj::H2(c, _) => c.poll(cx),
847+
ProtoClientProj::H2 { h2, .. } => h2.poll(cx),
848+
849+
#[cfg(not(feature = "http1"))]
850+
ProtoClientProj::H1 { h1 } => match h1.0 {},
851+
#[cfg(not(feature = "http2"))]
852+
ProtoClientProj::H2 { h2, .. } => match h2.0 {},
823853
}
824854
}
825855
}

src/client/connect/http.rs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use std::time::Duration;
1111

1212
use futures_util::future::Either;
1313
use http::uri::{Scheme, Uri};
14-
use pin_project::pin_project;
14+
use pin_project_lite::pin_project;
1515
use tokio::net::{TcpSocket, TcpStream};
1616
use tokio::time::Sleep;
1717

@@ -373,18 +373,19 @@ impl HttpInfo {
373373
}
374374
}
375375

376-
// Not publicly exported (so missing_docs doesn't trigger).
377-
//
378-
// We return this `Future` instead of the `Pin<Box<dyn Future>>` directly
379-
// so that users don't rely on it fitting in a `Pin<Box<dyn Future>>` slot
380-
// (and thus we can change the type in the future).
381-
#[must_use = "futures do nothing unless polled"]
382-
#[pin_project]
383-
#[allow(missing_debug_implementations)]
384-
pub struct HttpConnecting<R> {
385-
#[pin]
386-
fut: BoxConnecting,
387-
_marker: PhantomData<R>,
376+
pin_project! {
377+
// Not publicly exported (so missing_docs doesn't trigger).
378+
//
379+
// We return this `Future` instead of the `Pin<Box<dyn Future>>` directly
380+
// so that users don't rely on it fitting in a `Pin<Box<dyn Future>>` slot
381+
// (and thus we can change the type in the future).
382+
#[must_use = "futures do nothing unless polled"]
383+
#[allow(missing_debug_implementations)]
384+
pub struct HttpConnecting<R> {
385+
#[pin]
386+
fut: BoxConnecting,
387+
_marker: PhantomData<R>,
388+
}
388389
}
389390

390391
type ConnectResult = Result<TcpStream, ConnectError>;

src/client/pool.rs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use futures_channel::oneshot;
1111
use tokio::time::{Duration, Instant, Interval};
1212

1313
use super::client::Ver;
14-
use crate::common::{task, exec::Exec, Future, Pin, Poll, Unpin};
14+
use crate::common::{exec::Exec, task, Future, Pin, Poll, Unpin};
1515

1616
// FIXME: allow() required due to `impl Trait` leaking types to this lint
1717
#[allow(missing_debug_implementations)]
@@ -714,16 +714,17 @@ impl Expiration {
714714
}
715715

716716
#[cfg(feature = "runtime")]
717-
#[pin_project::pin_project]
718-
struct IdleTask<T> {
719-
#[pin]
720-
interval: Interval,
721-
pool: WeakOpt<Mutex<PoolInner<T>>>,
722-
// This allows the IdleTask to be notified as soon as the entire
723-
// Pool is fully dropped, and shutdown. This channel is never sent on,
724-
// but Err(Canceled) will be received when the Pool is dropped.
725-
#[pin]
726-
pool_drop_notifier: oneshot::Receiver<crate::common::Never>,
717+
pin_project_lite::pin_project! {
718+
struct IdleTask<T> {
719+
#[pin]
720+
interval: Interval,
721+
pool: WeakOpt<Mutex<PoolInner<T>>>,
722+
// This allows the IdleTask to be notified as soon as the entire
723+
// Pool is fully dropped, and shutdown. This channel is never sent on,
724+
// but Err(Canceled) will be received when the Pool is dropped.
725+
#[pin]
726+
pool_drop_notifier: oneshot::Receiver<crate::common::Never>,
727+
}
727728
}
728729

729730
#[cfg(feature = "runtime")]
@@ -776,7 +777,7 @@ mod tests {
776777
use std::time::Duration;
777778

778779
use super::{Connecting, Key, Pool, Poolable, Reservation, WeakOpt};
779-
use crate::common::{task, exec::Exec, Future, Pin};
780+
use crate::common::{exec::Exec, task, Future, Pin};
780781

781782
/// Test unique reservations.
782783
#[derive(Debug, PartialEq, Eq)]

src/common/drain.rs

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

3-
use pin_project::pin_project;
3+
use pin_project_lite::pin_project;
44
use tokio::sync::watch;
55

66
use super::{task, Future, Pin, Poll};
@@ -21,14 +21,15 @@ pub(crate) struct Watch {
2121
rx: watch::Receiver<()>,
2222
}
2323

24-
#[allow(missing_debug_implementations)]
25-
#[pin_project]
26-
pub struct Watching<F, FN> {
27-
#[pin]
28-
future: F,
29-
state: State<FN>,
30-
watch: Pin<Box<dyn Future<Output = ()> + Send + Sync>>,
31-
_rx: watch::Receiver<()>,
24+
pin_project! {
25+
#[allow(missing_debug_implementations)]
26+
pub struct Watching<F, FN> {
27+
#[pin]
28+
future: F,
29+
state: State<FN>,
30+
watch: Pin<Box<dyn Future<Output = ()> + Send + Sync>>,
31+
_rx: watch::Receiver<()>,
32+
}
3233
}
3334

3435
enum State<F> {

src/common/lazy.rs

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use pin_project::pin_project;
1+
use pin_project_lite::pin_project;
22

33
use super::{task, Future, Pin, Poll};
44

@@ -12,23 +12,27 @@ where
1212
R: Future + Unpin,
1313
{
1414
Lazy {
15-
inner: Inner::Init(func),
15+
inner: Inner::Init { func },
1616
}
1717
}
1818

1919
// FIXME: allow() required due to `impl Trait` leaking types to this lint
20-
#[allow(missing_debug_implementations)]
21-
#[pin_project]
22-
pub(crate) struct Lazy<F, R> {
23-
#[pin]
24-
inner: Inner<F, R>,
20+
pin_project! {
21+
#[allow(missing_debug_implementations)]
22+
pub(crate) struct Lazy<F, R> {
23+
#[pin]
24+
inner: Inner<F, R>,
25+
}
2526
}
2627

27-
#[pin_project(project = InnerProj, project_replace = InnerProjReplace)]
28-
enum Inner<F, R> {
29-
Init(F),
30-
Fut(#[pin] R),
31-
Empty,
28+
pin_project! {
29+
#[project = InnerProj]
30+
#[project_replace = InnerProjReplace]
31+
enum Inner<F, R> {
32+
Init { func: F },
33+
Fut { #[pin] fut: R },
34+
Empty,
35+
}
3236
}
3337

3438
impl<F, R> Started for Lazy<F, R>
@@ -38,8 +42,8 @@ where
3842
{
3943
fn started(&self) -> bool {
4044
match self.inner {
41-
Inner::Init(_) => false,
42-
Inner::Fut(_) | Inner::Empty => true,
45+
Inner::Init { .. } => false,
46+
Inner::Fut { .. } | Inner::Empty => true,
4347
}
4448
}
4549
}
@@ -54,15 +58,15 @@ where
5458
fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
5559
let mut this = self.project();
5660

57-
if let InnerProj::Fut(f) = this.inner.as_mut().project() {
58-
return f.poll(cx);
61+
if let InnerProj::Fut { fut } = this.inner.as_mut().project() {
62+
return fut.poll(cx);
5963
}
6064

6165
match this.inner.as_mut().project_replace(Inner::Empty) {
62-
InnerProjReplace::Init(func) => {
63-
this.inner.set(Inner::Fut(func()));
64-
if let InnerProj::Fut(f) = this.inner.project() {
65-
return f.poll(cx);
66+
InnerProjReplace::Init { func } => {
67+
this.inner.set(Inner::Fut { fut: func() });
68+
if let InnerProj::Fut { fut } = this.inner.project() {
69+
return fut.poll(cx);
6670
}
6771
unreachable!()
6872
}

src/proto/h1/dispatch.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,13 @@ cfg_server! {
4444
}
4545

4646
cfg_client! {
47-
pub(crate) struct Client<B> {
48-
callback: Option<crate::client::dispatch::Callback<Request<B>, http::Response<Body>>>,
49-
rx: ClientRx<B>,
50-
rx_closed: bool,
47+
pin_project_lite::pin_project! {
48+
pub(crate) struct Client<B> {
49+
callback: Option<crate::client::dispatch::Callback<Request<B>, http::Response<Body>>>,
50+
#[pin]
51+
rx: ClientRx<B>,
52+
rx_closed: bool,
53+
}
5154
}
5255

5356
type ClientRx<B> = crate::client::dispatch::Receiver<Request<B>, http::Response<Body>>;

0 commit comments

Comments
 (0)