Skip to content

Commit 2b2c352

Browse files
authored
refactor: limit dependency futures-util to tests and client-legacy (#192)
Enable non-trivial applications based on hyper + tokio without pulling in this heavyweight dependency. Keep MSRV 1.63 by using `ready!` from `futures_core` and polyfilling `poll_fn`. Don't remove futures-util from the `client-legacy` code, because this would require re-implementing several non-trivial combinators.
1 parent 1bcd489 commit 2b2c352

File tree

11 files changed

+53
-16
lines changed

11 files changed

+53
-16
lines changed

Cargo.toml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ rustdoc-args = ["--cfg", "docsrs"]
2121
base64 = { version = "0.22", optional = true }
2222
bytes = "1.7.1"
2323
futures-channel = { version = "0.3", optional = true }
24-
futures-util = { version = "0.3.16", default-features = false }
24+
futures-core = { version = "0.3" }
25+
futures-util = { version = "0.3.16", default-features = false, optional = true }
2526
http = "1.0"
2627
http-body = "1.0.0"
2728
hyper = "1.6.0"
@@ -37,6 +38,7 @@ tower-service = { version = "0.3", optional = true }
3738
[dev-dependencies]
3839
hyper = { version = "1.4.0", features = ["full"] }
3940
bytes = "1"
41+
futures-util = { version = "0.3.16", default-features = false, features = ["alloc"] }
4042
http-body-util = "0.1.0"
4143
tokio = { version = "1", features = ["macros", "test-util", "signal"] }
4244
tokio-test = "0.4"
@@ -69,13 +71,13 @@ full = [
6971
]
7072

7173
client = ["hyper/client", "dep:tracing", "dep:futures-channel", "dep:tower-service"]
72-
client-legacy = ["client", "dep:socket2", "tokio/sync", "dep:libc"]
74+
client-legacy = ["client", "dep:socket2", "tokio/sync", "dep:libc", "dep:futures-util"]
7375
client-proxy = ["client", "dep:base64", "dep:ipnet", "dep:percent-encoding"]
7476
client-proxy-system = ["dep:system-configuration", "dep:windows-registry"]
7577

7678
server = ["hyper/server"]
7779
server-auto = ["server", "http1", "http2"]
78-
server-graceful = ["server", "tokio/sync", "futures-util/alloc"]
80+
server-graceful = ["server", "tokio/sync"]
7981

8082
service = ["dep:tower-service"]
8183

src/client/legacy/client.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use super::connect::HttpConnector;
2525
use super::connect::{Alpn, Connect, Connected, Connection};
2626
use super::pool::{self, Ver};
2727

28+
use crate::common::future::poll_fn;
2829
use crate::common::{lazy as hyper_lazy, timer, Exec, Lazy, SyncWrapper};
2930

3031
type BoxSendFuture = Pin<Box<dyn Future<Output = ()> + Send>>;
@@ -360,7 +361,7 @@ where
360361
} else if !res.body().is_end_stream() {
361362
//let (delayed_tx, delayed_rx) = oneshot::channel::<()>();
362363
//res.body_mut().delayed_eof(delayed_rx);
363-
let on_idle = future::poll_fn(move |cx| pooled.poll_ready(cx)).map(move |_| {
364+
let on_idle = poll_fn(move |cx| pooled.poll_ready(cx)).map(move |_| {
364365
// At this point, `pooled` is dropped, and had a chance
365366
// to insert into the pool (if conn was idle)
366367
//drop(delayed_tx);
@@ -370,7 +371,7 @@ where
370371
} else {
371372
// There's no body to delay, but the connection isn't
372373
// ready yet. Only re-insert when it's ready
373-
let on_idle = future::poll_fn(move |cx| pooled.poll_ready(cx)).map(|_| ());
374+
let on_idle = poll_fn(move |cx| pooled.poll_ready(cx)).map(|_| ());
374375

375376
self.exec.execute(on_idle);
376377
}

src/client/legacy/connect/dns.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ pub(super) async fn resolve<R>(resolver: &mut R, name: Name) -> Result<R::Addrs,
284284
where
285285
R: Resolve,
286286
{
287-
futures_util::future::poll_fn(|cx| resolver.poll_ready(cx)).await?;
287+
crate::common::future::poll_fn(|cx| resolver.poll_ready(cx)).await?;
288288
resolver.resolve(name).await
289289
}
290290

src/client/legacy/connect/http.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::sync::Arc;
99
use std::task::{self, Poll};
1010
use std::time::Duration;
1111

12+
use futures_core::ready;
1213
use futures_util::future::Either;
1314
use http::uri::{Scheme, Uri};
1415
use pin_project_lite::pin_project;
@@ -464,7 +465,7 @@ where
464465
type Future = HttpConnecting<R>;
465466

466467
fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> {
467-
futures_util::ready!(self.resolver.poll_ready(cx)).map_err(ConnectError::dns)?;
468+
ready!(self.resolver.poll_ready(cx)).map_err(ConnectError::dns)?;
468469
Poll::Ready(Ok(()))
469470
}
470471

src/client/legacy/connect/proxy/tunnel.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::marker::{PhantomData, Unpin};
44
use std::pin::Pin;
55
use std::task::{self, Poll};
66

7+
use futures_core::ready;
78
use http::{HeaderMap, HeaderValue, Uri};
89
use hyper::rt::{Read, Write};
910
use pin_project_lite::pin_project;
@@ -127,8 +128,7 @@ where
127128
type Future = Tunneling<C::Future, C::Response>;
128129

129130
fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> {
130-
futures_util::ready!(self.inner.poll_ready(cx))
131-
.map_err(|e| TunnelError::ConnectFailed(e.into()))?;
131+
ready!(self.inner.poll_ready(cx)).map_err(|e| TunnelError::ConnectFailed(e.into()))?;
132132
Poll::Ready(Ok(()))
133133
}
134134

src/client/legacy/pool.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use std::task::{self, Poll};
1414
use std::time::{Duration, Instant};
1515

1616
use futures_channel::oneshot;
17-
use futures_util::ready;
17+
use futures_core::ready;
1818
use tracing::{debug, trace};
1919

2020
use hyper::rt::Sleep;

src/common/future.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use std::{
2+
future::Future,
3+
pin::Pin,
4+
task::{Context, Poll},
5+
};
6+
7+
// TODO: replace with `std::future::poll_fn` once MSRV >= 1.64
8+
pub(crate) fn poll_fn<T, F>(f: F) -> PollFn<F>
9+
where
10+
F: FnMut(&mut Context<'_>) -> Poll<T>,
11+
{
12+
PollFn { f }
13+
}
14+
15+
pub(crate) struct PollFn<F> {
16+
f: F,
17+
}
18+
19+
impl<F> Unpin for PollFn<F> {}
20+
21+
impl<T, F> Future for PollFn<F>
22+
where
23+
F: FnMut(&mut Context<'_>) -> Poll<T>,
24+
{
25+
type Output = T;
26+
27+
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
28+
(self.f)(cx)
29+
}
30+
}

src/common/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@ pub(crate) use exec::Exec;
1515
pub(crate) use lazy::{lazy, Started as Lazy};
1616
#[cfg(feature = "client")]
1717
pub(crate) use sync::SyncWrapper;
18+
19+
pub(crate) mod future;

src/rt/io.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@ use std::marker::Unpin;
22
use std::pin::Pin;
33
use std::task::Poll;
44

5-
use futures_util::future;
6-
use futures_util::ready;
5+
use futures_core::ready;
76
use hyper::rt::{Read, ReadBuf, Write};
87

8+
use crate::common::future::poll_fn;
9+
910
pub(crate) async fn read<T>(io: &mut T, buf: &mut [u8]) -> Result<usize, std::io::Error>
1011
where
1112
T: Read + Unpin,
1213
{
13-
future::poll_fn(move |cx| {
14+
poll_fn(move |cx| {
1415
let mut buf = ReadBuf::new(buf);
1516
ready!(Pin::new(&mut *io).poll_read(cx, buf.unfilled()))?;
1617
Poll::Ready(Ok(buf.filled().len()))
@@ -23,7 +24,7 @@ where
2324
T: Write + Unpin,
2425
{
2526
let mut n = 0;
26-
future::poll_fn(move |cx| {
27+
poll_fn(move |cx| {
2728
while n < buf.len() {
2829
n += ready!(Pin::new(&mut *io).poll_write(cx, &buf[n..])?);
2930
}

src/server/conn/auto/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
33
pub mod upgrade;
44

5-
use futures_util::ready;
65
use hyper::service::HttpService;
76
use std::future::Future;
87
use std::marker::PhantomPinned;
@@ -12,6 +11,7 @@ use std::task::{Context, Poll};
1211
use std::{error::Error as StdError, io, time::Duration};
1312

1413
use bytes::Bytes;
14+
use futures_core::ready;
1515
use http::{Request, Response};
1616
use http_body::Body;
1717
use hyper::{

src/service/oneshot.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use futures_util::ready;
1+
use futures_core::ready;
22
use pin_project_lite::pin_project;
33
use std::future::Future;
44
use std::pin::Pin;

0 commit comments

Comments
 (0)