diff --git a/src/lib.rs b/src/lib.rs index d720762..04979c7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,5 +12,10 @@ mod common; pub mod rt; #[cfg(feature = "server")] pub mod server; +#[cfg(all( + any(feature = "http1", feature = "http2"), + any(feature = "server", feature = "client") +))] +pub mod service; mod error; diff --git a/src/service.rs b/src/service.rs new file mode 100644 index 0000000..4664bd1 --- /dev/null +++ b/src/service.rs @@ -0,0 +1,70 @@ +//! Service utilities. + +use pin_project_lite::pin_project; +use std::{ + future::Future, + pin::Pin, + task::{Context, Poll}, +}; +use tower::{util::Oneshot, ServiceExt}; + +/// A tower service converted into a hyper service. +#[cfg(all( + any(feature = "http1", feature = "http2"), + any(feature = "server", feature = "client") +))] +#[derive(Debug, Copy, Clone)] +pub struct TowerToHyperService { + service: S, +} + +impl TowerToHyperService { + /// Create a new `TowerToHyperService` from a tower service. + pub fn new(tower_service: S) -> Self { + Self { + service: tower_service, + } + } +} + +impl hyper::service::Service for TowerToHyperService +where + S: tower_service::Service + Clone, +{ + type Response = S::Response; + type Error = S::Error; + type Future = TowerToHyperServiceFuture; + + fn call(&self, req: R) -> Self::Future { + TowerToHyperServiceFuture { + future: self.service.clone().oneshot(req), + } + } +} + +pin_project! { + /// Response future for [`TowerToHyperService`]. + #[cfg(all( + any(feature = "http1", feature = "http2"), + any(feature = "server", feature = "client") + ))] + pub struct TowerToHyperServiceFuture + where + S: tower_service::Service, + { + #[pin] + future: Oneshot, + } +} + +impl Future for TowerToHyperServiceFuture +where + S: tower_service::Service, +{ + type Output = Result; + + #[inline] + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + self.project().future.poll(cx) + } +}