From c20cd2014894f352708b1599c2f7e19ad59c11e1 Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Thu, 16 Nov 2023 13:05:09 -0500 Subject: [PATCH] clean up exposed crate features (#50) - Put `TokioExecutor` and `TokioIo` into a single `rt::tokio` module. - The `rt::tokio` module is behind a `tokio` crate feature. - Changed `auto` crate feature to `server-auto`. - Added `client-legacy` crate feature, with `client::legacy` behind it. - Removed `tcp` and `runtime` features, code now depends on the `tokio` feature. --- Cargo.toml | 23 +++++++++++----- src/client/legacy/client.rs | 18 ++++++------- src/client/legacy/connect/mod.rs | 3 +++ src/client/mod.rs | 1 + src/client/pool.rs | 28 +++++-------------- src/rt/mod.rs | 9 +++---- src/rt/{tokio_io.rs => tokio.rs} | 46 ++++++++++++++++++++++++++++++++ src/rt/tokio_executor.rs | 42 ----------------------------- src/server/conn/mod.rs | 2 +- 9 files changed, 87 insertions(+), 85 deletions(-) rename src/rt/{tokio_io.rs => tokio.rs} (80%) delete mode 100644 src/rt/tokio_executor.rs diff --git a/Cargo.toml b/Cargo.toml index 6bd5701..bc751ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,9 +22,9 @@ http = "1.0" http-body = "1.0.0" bytes = "1" pin-project-lite = "0.2.4" -socket2 = "0.5" +socket2 = { version = "0.5", optional = true } tracing = { version = "0.1", default-features = false, features = ["std"] } -tokio = { version = "1", features = ["net", "rt", "time"] } +tokio = { version = "1", optional = true, features = ["net", "rt", "time"] } tower-service = "0.3" tower = { version = "0.4", features = ["make", "util"] } @@ -42,21 +42,30 @@ pnet_datalink = "0.34.0" default = [] # Shorthand to enable everything -full = ["client", "server", "http1", "http2", "tcp", "auto", "runtime"] +full = [ + "client", + "client-legacy", + "server", + "server-auto", + "http1", + "http2", + "tokio", +] client = ["hyper/client"] +client-legacy = ["client"] + server = ["hyper/server"] +server-auto = ["hyper/server", "http1", "http2"] http1 = ["hyper/http1"] http2 = ["hyper/http2"] -tcp = [] -auto = ["hyper/server", "http1", "http2"] -runtime = [] +tokio = ["dep:tokio", "dep:socket2"] # internal features used in CI __internal_happy_eyeballs_tests = [] [[example]] name = "client" -required-features = ["client", "http1", "tcp", "runtime"] +required-features = ["client-legacy", "http1", "tokio"] diff --git a/src/client/legacy/client.rs b/src/client/legacy/client.rs index bfc25e0..9aa6460 100644 --- a/src/client/legacy/client.rs +++ b/src/client/legacy/client.rs @@ -19,7 +19,7 @@ use hyper::{body::Body, Method, Request, Response, Uri, Version}; use tracing::{debug, trace, warn}; use super::super::pool::{self, Ver}; -#[cfg(feature = "tcp")] +#[cfg(feature = "tokio")] use super::connect::HttpConnector; use super::connect::{Alpn, Connect, Connected, Connection}; use crate::common::{lazy as hyper_lazy, Exec, Lazy, SyncWrapper}; @@ -103,7 +103,7 @@ impl Client<(), ()> { /// # Example /// /// ``` - /// # #[cfg(feature = "runtime")] + /// # #[cfg(feature = "tokio")] /// # fn run () { /// use std::time::Duration; /// use hyper::Client; @@ -144,7 +144,7 @@ where /// # Example /// /// ``` - /// # #[cfg(feature = "runtime")] + /// # #[cfg(feature = "tokio")] /// # fn run () { /// use hyper::{Client, Uri}; /// @@ -173,7 +173,7 @@ where /// # Example /// /// ``` - /// # #[cfg(feature = "runtime")] + /// # #[cfg(feature = "tokio")] /// # fn run () { /// use hyper::{Method, Client, Request}; /// use http_body_util::Full; @@ -934,7 +934,7 @@ fn is_schema_secure(uri: &Uri) -> bool { /// # Example /// /// ``` -/// # #[cfg(feature = "runtime")] +/// # #[cfg(feature = "tokio")] /// # fn run () { /// use std::time::Duration; /// use hyper::Client; @@ -1286,7 +1286,7 @@ impl Builder { /// # Cargo Feature /// /// Requires the `runtime` cargo feature to be enabled. - #[cfg(feature = "runtime")] + #[cfg(feature = "tokio")] #[cfg(feature = "http2")] #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] pub fn http2_keep_alive_interval( @@ -1307,7 +1307,7 @@ impl Builder { /// # Cargo Feature /// /// Requires the `runtime` cargo feature to be enabled. - #[cfg(feature = "runtime")] + #[cfg(feature = "tokio")] #[cfg(feature = "http2")] #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] pub fn http2_keep_alive_timeout(&mut self, timeout: Duration) -> &mut Self { @@ -1327,7 +1327,7 @@ impl Builder { /// # Cargo Feature /// /// Requires the `runtime` cargo feature to be enabled. - #[cfg(feature = "runtime")] + #[cfg(feature = "tokio")] #[cfg(feature = "http2")] #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] pub fn http2_keep_alive_while_idle(&mut self, enabled: bool) -> &mut Self { @@ -1410,7 +1410,7 @@ impl Builder { } /// Builder a client with this configuration and the default `HttpConnector`. - #[cfg(feature = "tcp")] + #[cfg(feature = "tokio")] pub fn build_http(&self) -> Client where B: Body + Send, diff --git a/src/client/legacy/connect/mod.rs b/src/client/legacy/connect/mod.rs index 147ff3c..8eed2cd 100644 --- a/src/client/legacy/connect/mod.rs +++ b/src/client/legacy/connect/mod.rs @@ -66,9 +66,12 @@ use std::fmt; use ::http::Extensions; +#[cfg(feature = "tokio")] pub use self::http::{HttpConnector, HttpInfo}; +#[cfg(feature = "tokio")] pub mod dns; +#[cfg(feature = "tokio")] mod http; pub use self::sealed::Connect; diff --git a/src/client/mod.rs b/src/client/mod.rs index 9803632..009a45d 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -1,6 +1,7 @@ //! HTTP client utilities /// Legacy implementations of `connect` module and `Client` +#[cfg(feature = "client-legacy")] pub mod legacy; #[doc(hidden)] pub mod pool; diff --git a/src/client/pool.rs b/src/client/pool.rs index 70e7959..804d5b7 100644 --- a/src/client/pool.rs +++ b/src/client/pool.rs @@ -12,10 +12,7 @@ use std::pin::Pin; use std::sync::{Arc, Mutex, Weak}; use std::task::{self, Poll}; -#[cfg(not(feature = "runtime"))] use std::time::{Duration, Instant}; -#[cfg(feature = "runtime")] -use tokio::time::{Duration, Instant, Interval}; use futures_channel::oneshot; use tracing::{debug, trace}; @@ -97,9 +94,7 @@ struct PoolInner { waiters: HashMap>>, // A oneshot channel is used to allow the interval to be notified when // the Pool completely drops. That way, the interval can cancel immediately. - #[cfg(feature = "runtime")] idle_interval_ref: Option>, - #[cfg(feature = "runtime")] exec: Exec, timeout: Option, } @@ -130,11 +125,9 @@ impl Pool { Some(Arc::new(Mutex::new(PoolInner { connecting: HashSet::new(), idle: HashMap::new(), - #[cfg(feature = "runtime")] idle_interval_ref: None, max_idle_per_host: config.max_idle_per_host, waiters: HashMap::new(), - #[cfg(feature = "runtime")] exec, timeout: config.idle_timeout, }))) @@ -152,7 +145,6 @@ impl Pool { #[cfg(test)] pub(super) fn no_timer(&self) { // Prevent an actual interval from being created for this pool... - #[cfg(feature = "runtime")] { let mut inner = self.inner.as_ref().unwrap().lock().unwrap(); assert!(inner.idle_interval_ref.is_none(), "timer already spawned"); @@ -207,13 +199,11 @@ impl Pool { } /* Used in client/tests.rs... - #[cfg(feature = "runtime")] #[cfg(test)] pub(super) fn h1_key(&self, s: &str) -> Key { Arc::new(s.to_string()) } - #[cfg(feature = "runtime")] #[cfg(test)] pub(super) fn idle_count(&self, key: &Key) -> usize { self @@ -403,10 +393,7 @@ impl PoolInner { }); } - #[cfg(feature = "runtime")] - { - self.spawn_idle_interval(__pool_ref); - } + self.spawn_idle_interval(__pool_ref); } None => trace!("put; found waiter for {:?}", key), } @@ -423,8 +410,9 @@ impl PoolInner { self.waiters.remove(key); } - #[cfg(feature = "runtime")] - fn spawn_idle_interval(&mut self, pool_ref: &Arc>>) { + fn spawn_idle_interval(&mut self, _pool_ref: &Arc>>) { + // TODO + /* let (dur, rx) = { if self.idle_interval_ref.is_some() { return; @@ -446,6 +434,7 @@ impl PoolInner { }; self.exec.execute(interval); + */ } } @@ -466,7 +455,6 @@ impl PoolInner { } } -#[cfg(feature = "runtime")] impl PoolInner { /// This should *only* be called by the IdleTask fn clear_expired(&mut self) { @@ -766,7 +754,7 @@ impl Expiration { } } -#[cfg(feature = "runtime")] +/* pin_project_lite::pin_project! { struct IdleTask { #[pin] @@ -780,7 +768,6 @@ pin_project_lite::pin_project! { } } -#[cfg(feature = "runtime")] impl Future for IdleTask { type Output = (); @@ -809,6 +796,7 @@ impl Future for IdleTask { } } } +*/ impl WeakOpt { fn none() -> Self { @@ -932,7 +920,6 @@ mod tests { assert!(is_not_ready); } - #[cfg(feature = "runtime")] #[tokio::test] async fn test_pool_checkout_removes_expired() { let pool = pool_no_timer(); @@ -971,7 +958,6 @@ mod tests { ); } - #[cfg(feature = "runtime")] #[tokio::test] async fn test_pool_timer_removes_expired() { tokio::time::pause(); diff --git a/src/rt/mod.rs b/src/rt/mod.rs index b6c18cd..cedc8cc 100644 --- a/src/rt/mod.rs +++ b/src/rt/mod.rs @@ -1,8 +1,7 @@ //! Runtime utilities -/// Implementation of [`hyper::rt::Executor`] that utilises [`tokio::spawn`]. -pub mod tokio_executor; -mod tokio_io; +#[cfg(feature = "tokio")] +pub mod tokio; -pub use tokio_executor::TokioExecutor; -pub use tokio_io::TokioIo; +#[cfg(feature = "tokio")] +pub use self::tokio::{TokioExecutor, TokioIo}; diff --git a/src/rt/tokio_io.rs b/src/rt/tokio.rs similarity index 80% rename from src/rt/tokio_io.rs rename to src/rt/tokio.rs index 344c099..696f3f6 100644 --- a/src/rt/tokio_io.rs +++ b/src/rt/tokio.rs @@ -1,12 +1,19 @@ #![allow(dead_code)] //! Tokio IO integration for hyper use std::{ + future::Future, pin::Pin, task::{Context, Poll}, }; +use hyper::rt::Executor; use pin_project_lite::pin_project; +/// Future executor that utilises `tokio` threads. +#[non_exhaustive] +#[derive(Default, Debug, Clone)] +pub struct TokioExecutor {} + pin_project! { /// A wrapping implementing hyper IO traits for a type that /// implements Tokio's IO traits. @@ -17,6 +24,27 @@ pin_project! { } } +// ===== impl TokioExecutor ===== + +impl Executor for TokioExecutor +where + Fut: Future + Send + 'static, + Fut::Output: Send + 'static, +{ + fn execute(&self, fut: Fut) { + tokio::spawn(fut); + } +} + +impl TokioExecutor { + /// Create new executor that relies on [`tokio::spawn`] to execute futures. + pub fn new() -> Self { + Self {} + } +} + +// ==== impl TokioIo ===== + impl TokioIo { /// Wrap a type implementing Tokio's IO traits. pub fn new(inner: T) -> Self { @@ -161,3 +189,21 @@ where hyper::rt::Write::poll_write_vectored(self.project().inner, cx, bufs) } } + +#[cfg(test)] +mod tests { + use crate::rt::tokio_executor::TokioExecutor; + use hyper::rt::Executor; + use tokio::sync::oneshot; + + #[cfg(not(miri))] + #[tokio::test] + async fn simple_execute() -> Result<(), Box> { + let (tx, rx) = oneshot::channel(); + let executor = TokioExecutor::new(); + executor.execute(async move { + tx.send(()).unwrap(); + }); + rx.await.map_err(Into::into) + } +} diff --git a/src/rt/tokio_executor.rs b/src/rt/tokio_executor.rs deleted file mode 100644 index 787220a..0000000 --- a/src/rt/tokio_executor.rs +++ /dev/null @@ -1,42 +0,0 @@ -use hyper::rt::Executor; -use std::future::Future; - -/// Future executor that utilises `tokio` threads. -#[non_exhaustive] -#[derive(Default, Debug, Clone)] -pub struct TokioExecutor {} - -impl Executor for TokioExecutor -where - Fut: Future + Send + 'static, - Fut::Output: Send + 'static, -{ - fn execute(&self, fut: Fut) { - tokio::spawn(fut); - } -} - -impl TokioExecutor { - /// Create new executor that relies on [`tokio::spawn`] to execute futures. - pub fn new() -> Self { - Self {} - } -} - -#[cfg(test)] -mod tests { - use crate::rt::tokio_executor::TokioExecutor; - use hyper::rt::Executor; - use tokio::sync::oneshot; - - #[cfg(not(miri))] - #[tokio::test] - async fn simple_execute() -> Result<(), Box> { - let (tx, rx) = oneshot::channel(); - let executor = TokioExecutor::new(); - executor.execute(async move { - tx.send(()).unwrap(); - }); - rx.await.map_err(Into::into) - } -} diff --git a/src/server/conn/mod.rs b/src/server/conn/mod.rs index 70057c8..535aee2 100644 --- a/src/server/conn/mod.rs +++ b/src/server/conn/mod.rs @@ -1,4 +1,4 @@ //! Connection utilities. -#[cfg(feature = "auto")] +#[cfg(feature = "server-auto")] pub mod auto;