Skip to content

Commit

Permalink
chore: remove tower dep by vendoring Oneshot
Browse files Browse the repository at this point in the history
  • Loading branch information
seanmonstar committed Sep 23, 2024
1 parent d3e9699 commit 3111783
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 11 deletions.
9 changes: 4 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }
Expand Down Expand Up @@ -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"]
Expand Down
8 changes: 4 additions & 4 deletions src/client/legacy/connect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,8 +343,8 @@ pub(super) mod sealed {
{
type _Svc = S;

fn connect(self, _: Internal, dst: Uri) -> tower::util::Oneshot<S, Uri> {
tower::util::Oneshot::new(self, dst)
fn connect(self, _: Internal, dst: Uri) -> crate::service::Oneshot<S, Uri> {
crate::service::Oneshot::new(self, dst)
}
}

Expand All @@ -357,10 +357,10 @@ pub(super) mod sealed {
{
type Connection = T;
type Error = S::Error;
type Future = tower::util::Oneshot<S, Uri>;
type Future = crate::service::Oneshot<S, Uri>;

fn connect(self, _: Internal, dst: Uri) -> Self::Future {
tower::util::Oneshot::new(self, dst)
crate::service::Oneshot::new(self, dst)
}
}

Expand Down
68 changes: 66 additions & 2 deletions src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use std::{
pin::Pin,
task::{Context, Poll},
};
use tower::{util::Oneshot, ServiceExt};

pub(crate) use self::internal::Oneshot;

/// A tower service converted into a hyper service.
#[derive(Debug, Copy, Clone)]
Expand All @@ -33,7 +34,7 @@ where

fn call(&self, req: R) -> Self::Future {
TowerToHyperServiceFuture {
future: self.service.clone().oneshot(req),
future: Oneshot::new(self.service.clone(), req),
}
}
}
Expand All @@ -60,3 +61,66 @@ where
self.project().future.poll(cx)
}
}

mod internal {
use pin_project_lite::pin_project;
use std::future::Future;
use std::pin::Pin;
use std::task::{ready, Context, Poll};
use tower_service::Service;

// Not really pub, but used in a trait for bounds
pin_project! {
#[project = OneshotProj]
#[derive(Debug)]
pub enum Oneshot<S: Service<Req>, Req> {
NotReady {
svc: S,
req: Option<Req>,
},
Called {
#[pin]
fut: S::Future,
},
Done,
}
}

impl<S, Req> Oneshot<S, Req>
where
S: Service<Req>,
{
pub(crate) const fn new(svc: S, req: Req) -> Self {
Oneshot::NotReady {
svc,
req: Some(req),
}
}
}

impl<S, Req> Future for Oneshot<S, Req>
where
S: Service<Req>,
{
type Output = Result<S::Response, S::Error>;

fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
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"),
}
}
}
}
}

0 comments on commit 3111783

Please sign in to comment.