From 421d1a65381b3ad058946912cc002118d55c7e4b Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Mon, 23 Sep 2024 17:28:01 -0400 Subject: [PATCH] chore: remove tower dep by vendoring Oneshot --- Cargo.toml | 9 ++--- src/client/legacy/connect/mod.rs | 12 +++--- src/lib.rs | 2 +- src/{service.rs => service/glue.rs} | 7 ++-- src/service/mod.rs | 11 +++++ src/service/oneshot.rs | 63 +++++++++++++++++++++++++++++ 6 files changed, 88 insertions(+), 16 deletions(-) rename src/{service.rs => service/glue.rs} (91%) create mode 100644 src/service/mod.rs create mode 100644 src/service/oneshot.rs diff --git a/Cargo.toml b/Cargo.toml index 68b3a06..9cd3db8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,8 +28,7 @@ futures-channel = { version = "0.3", optional = true } socket2 = { version = "0.5", optional = true, features = ["all"] } tracing = { version = "0.1", default-features = false, features = ["std"], optional = true } tokio = { version = "1", optional = true, default-features = false } -tower-service ={ version = "0.3", optional = true } -tower = { version = "0.4.1", optional = true, default-features = false, features = ["make", "util"] } +tower-service = { version = "0.3", optional = true } [dev-dependencies] hyper = { version = "1.4.0", features = ["full"] } @@ -58,14 +57,14 @@ full = [ "tokio", ] -client = ["hyper/client", "dep:tracing", "dep:futures-channel", "dep:tower", "dep:tower-service"] +client = ["hyper/client", "dep:tracing", "dep:futures-channel", "dep:tower-service"] client-legacy = ["client", "dep:socket2", "tokio/sync"] server = ["hyper/server"] server-auto = ["server", "http1", "http2"] -server-graceful = ["server", "tokio/sync"] +server-graceful = ["server", "tokio/sync", "futures-util/alloc"] -service = ["dep:tower", "dep:tower-service"] +service = ["dep:tower-service"] http1 = ["hyper/http1"] http2 = ["hyper/http2"] diff --git a/src/client/legacy/connect/mod.rs b/src/client/legacy/connect/mod.rs index e3369b5..3309dbb 100644 --- a/src/client/legacy/connect/mod.rs +++ b/src/client/legacy/connect/mod.rs @@ -29,7 +29,7 @@ //! use std::{future::Future, net::SocketAddr, pin::Pin, task::{self, Poll}}; //! use http::Uri; //! use tokio::net::TcpStream; -//! use tower::Service; +//! use tower_service::Service; //! //! #[derive(Clone)] //! struct LocalConnector; @@ -57,7 +57,7 @@ //! better starting place to extend from. //! //! [`HttpConnector`]: HttpConnector -//! [`Service`]: tower::Service +//! [`Service`]: tower_service::Service //! [`Uri`]: ::http::Uri //! [`Read`]: hyper::rt::Read //! [`Write`]: hyper::rt::Write @@ -343,8 +343,8 @@ pub(super) mod sealed { { type _Svc = S; - fn connect(self, _: Internal, dst: Uri) -> tower::util::Oneshot { - tower::util::Oneshot::new(self, dst) + fn connect(self, _: Internal, dst: Uri) -> crate::service::Oneshot { + crate::service::Oneshot::new(self, dst) } } @@ -357,10 +357,10 @@ pub(super) mod sealed { { type Connection = T; type Error = S::Error; - type Future = tower::util::Oneshot; + type Future = crate::service::Oneshot; fn connect(self, _: Internal, dst: Uri) -> Self::Future { - tower::util::Oneshot::new(self, dst) + crate::service::Oneshot::new(self, dst) } } diff --git a/src/lib.rs b/src/lib.rs index 9df734c..ac8f89b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,7 @@ mod common; pub mod rt; #[cfg(feature = "server")] pub mod server; -#[cfg(feature = "service")] +#[cfg(any(feature = "service", feature = "client-legacy"))] pub mod service; mod error; diff --git a/src/service.rs b/src/service/glue.rs similarity index 91% rename from src/service.rs rename to src/service/glue.rs index 4652a6a..35aa096 100644 --- a/src/service.rs +++ b/src/service/glue.rs @@ -1,12 +1,11 @@ -//! Service utilities. - use pin_project_lite::pin_project; use std::{ future::Future, pin::Pin, task::{Context, Poll}, }; -use tower::{util::Oneshot, ServiceExt}; + +use super::Oneshot; /// A tower service converted into a hyper service. #[derive(Debug, Copy, Clone)] @@ -33,7 +32,7 @@ where fn call(&self, req: R) -> Self::Future { TowerToHyperServiceFuture { - future: self.service.clone().oneshot(req), + future: Oneshot::new(self.service.clone(), req), } } } diff --git a/src/service/mod.rs b/src/service/mod.rs new file mode 100644 index 0000000..33370ca --- /dev/null +++ b/src/service/mod.rs @@ -0,0 +1,11 @@ +//! Service utilities. + +#[cfg(feature = "service")] +mod glue; +#[cfg(any(feature = "client-legacy", feature = "service"))] +mod oneshot; + +#[cfg(feature = "service")] +pub use self::glue::{TowerToHyperService, TowerToHyperServiceFuture}; +#[cfg(any(feature = "client-legacy", feature = "service"))] +pub(crate) use self::oneshot::Oneshot; diff --git a/src/service/oneshot.rs b/src/service/oneshot.rs new file mode 100644 index 0000000..f47e1af --- /dev/null +++ b/src/service/oneshot.rs @@ -0,0 +1,63 @@ +use pin_project_lite::pin_project; +use std::future::Future; +use std::pin::Pin; +use std::task::{Context, Poll}; +use futures_util::ready; +use tower_service::Service; + +// Vendored from tower::util to reduce dependencies, the code is small enough. + +// Not really pub, but used in a trait for bounds +pin_project! { + #[project = OneshotProj] + #[derive(Debug)] + pub enum Oneshot, Req> { + NotReady { + svc: S, + req: Option, + }, + Called { + #[pin] + fut: S::Future, + }, + Done, + } +} + +impl Oneshot +where + S: Service, +{ + pub(crate) const fn new(svc: S, req: Req) -> Self { + Oneshot::NotReady { + svc, + req: Some(req), + } + } +} + +impl Future for Oneshot +where + S: Service, +{ + type Output = Result; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + loop { + let this = self.as_mut().project(); + match this { + OneshotProj::NotReady { svc, req } => { + let _ = ready!(svc.poll_ready(cx))?; + let fut = svc.call(req.take().expect("already called")); + self.set(Oneshot::Called { fut }); + } + OneshotProj::Called { fut } => { + let res = ready!(fut.poll(cx))?; + self.set(Oneshot::Done); + return Poll::Ready(Ok(res)); + } + OneshotProj::Done => panic!("polled after complete"), + } + } + } +}