use std::fmt::Debug;
use tower::Layer;
use tower::Service;
#[derive(Debug, Clone)]
pub struct IncomingRequestLayer<BIn, BOut> {
body: std::marker::PhantomData<fn(BIn) -> BOut>,
}
impl<BIn, BOut> Default for IncomingRequestLayer<BIn, BOut> {
fn default() -> Self {
Self {
body: std::marker::PhantomData,
}
}
}
impl<BIn, BOut> IncomingRequestLayer<BIn, BOut> {
pub fn new() -> Self {
Self {
body: std::marker::PhantomData,
}
}
}
impl<BIn, BOut, S> Layer<S> for IncomingRequestLayer<BIn, BOut> {
type Service = IncomingRequestService<S, BIn, BOut>;
fn layer(&self, inner: S) -> Self::Service {
IncomingRequestService {
inner,
body: std::marker::PhantomData,
}
}
}
pub struct IncomingRequestService<S, BIn, BOut> {
inner: S,
body: std::marker::PhantomData<fn(BIn) -> BOut>,
}
impl<S: Debug, BIn, BOut> Debug for IncomingRequestService<S, BIn, BOut> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("AdaptIncomingService")
.field(&self.inner)
.finish()
}
}
impl<S: Default, BIn, BOut> Default for IncomingRequestService<S, BIn, BOut> {
fn default() -> Self {
Self {
inner: S::default(),
body: std::marker::PhantomData,
}
}
}
impl<S: Clone, BIn, BOut> Clone for IncomingRequestService<S, BIn, BOut> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
body: std::marker::PhantomData,
}
}
}
impl<S, BIn, BOut> IncomingRequestService<S, BIn, BOut> {
pub fn new(inner: S) -> Self {
Self {
inner,
body: std::marker::PhantomData,
}
}
}
#[cfg(feature = "incoming")]
impl<T, BIn, BOut> Service<http::Request<hyper::body::Incoming>>
for IncomingRequestService<T, BIn, BOut>
where
T: Service<http::Request<BIn>, Response = http::Response<BOut>>,
BIn: From<hyper::body::Incoming>,
{
type Response = http::Response<BOut>;
type Error = T::Error;
type Future = T::Future;
fn poll_ready(
&mut self,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Result<(), Self::Error>> {
self.inner.poll_ready(cx)
}
fn call(&mut self, req: http::Request<hyper::body::Incoming>) -> Self::Future {
self.inner.call(req.map(BIn::from))
}
}
#[derive(Debug, Clone)]
pub struct IncomingResponseLayer<BIn, BOut> {
body: std::marker::PhantomData<fn(BIn) -> BOut>,
}
impl<BIn, BOut> Default for IncomingResponseLayer<BIn, BOut> {
fn default() -> Self {
Self {
body: std::marker::PhantomData,
}
}
}
impl<BIn, BOut> IncomingResponseLayer<BIn, BOut> {
pub fn new() -> Self {
Self {
body: std::marker::PhantomData,
}
}
}
impl<BIn, BOut, S> Layer<S> for IncomingResponseLayer<BIn, BOut> {
type Service = IncomingResponseService<S, BIn, BOut>;
fn layer(&self, inner: S) -> Self::Service {
IncomingResponseService {
inner,
body: std::marker::PhantomData,
}
}
}
pub struct IncomingResponseService<S, BIn, BOut> {
inner: S,
body: std::marker::PhantomData<fn(BIn) -> BOut>,
}
impl<S: Debug, BIn, BOut> Debug for IncomingResponseService<S, BIn, BOut> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("IncomingResponseService")
.field(&self.inner)
.finish()
}
}
impl<S: Default, BIn, BOut> Default for IncomingResponseService<S, BIn, BOut> {
fn default() -> Self {
Self {
inner: S::default(),
body: std::marker::PhantomData,
}
}
}
impl<S: Clone, BIn, BOut> Clone for IncomingResponseService<S, BIn, BOut> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
body: std::marker::PhantomData,
}
}
}
impl<S, BIn, BOut> IncomingResponseService<S, BIn, BOut> {
pub fn new(inner: S) -> Self {
Self {
inner,
body: std::marker::PhantomData,
}
}
}
impl<T, BIn, BOut> Service<http::Request<BIn>> for IncomingResponseService<T, BIn, BOut>
where
T: Service<http::Request<BIn>, Response = http::Response<hyper::body::Incoming>>,
BOut: From<hyper::body::Incoming>,
{
type Response = http::Response<BOut>;
type Error = T::Error;
type Future = future::IncomingResponseFuture<T::Future, BOut, T::Error>;
fn poll_ready(
&mut self,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Result<(), Self::Error>> {
self.inner.poll_ready(cx)
}
fn call(&mut self, req: http::Request<BIn>) -> Self::Future {
future::IncomingResponseFuture::new(self.inner.call(req))
}
}
mod future {
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
#[derive(Debug)]
#[pin_project::pin_project]
pub struct IncomingResponseFuture<F, BOut, Error> {
#[pin]
future: F,
body: std::marker::PhantomData<fn() -> (BOut, Error)>,
}
impl<F, BOut, Error> IncomingResponseFuture<F, BOut, Error> {
pub fn new(future: F) -> Self {
Self {
future,
body: std::marker::PhantomData,
}
}
}
impl<F, BOut, Error> Future for IncomingResponseFuture<F, BOut, Error>
where
F: Future<Output = Result<http::Response<hyper::body::Incoming>, Error>>,
BOut: From<hyper::body::Incoming>,
{
type Output = Result<http::Response<BOut>, Error>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.project().future.poll(cx) {
Poll::Ready(res) => Poll::Ready(res.map(|res| res.map(BOut::from))),
Poll::Pending => Poll::Pending,
}
}
}
}
#[cfg(test)]
#[cfg(feature = "incoming")]
mod tests {
use std::convert::Infallible;
use super::*;
use crate::body::Body;
use http_body::Body as HttpBody;
#[allow(dead_code, clippy::async_yields_async)]
fn compile_adapt_incoming() {
let _ = tower::ServiceBuilder::new()
.layer(IncomingRequestLayer::<Body, Body>::new())
.service(tower::service_fn(|req: http::Request<Body>| async move {
assert_eq!(req.body().size_hint().exact(), Some(0));
async { Ok::<_, Infallible>(http::Response::new(Body::empty())) }
}));
}
}