Reduce body boxing (#9)

Previously, when routing between one or two requests the two body types
would be merged by boxing them. This isn't ideal since it introduces a
layer indirection for each route.

We can't require the services to be routed between as not all services
use the same body type.

This changes that so it instead uses an `Either` enum that implements
`http_body::Body` if each variant does. Will reduce the overall
allocations and hopefully the compiler can optimize things if both
variants are the same.
This commit is contained in:
David Pedersen
2021-06-12 23:59:18 +02:00
committed by GitHub
parent b3bc4e024c
commit 04d62798b6
7 changed files with 216 additions and 143 deletions
+13 -15
View File
@@ -39,15 +39,14 @@
//! the [`extract`](crate::extract) module.
use crate::{
body::{Body, BoxBody},
body::{self, Body, BoxBody},
extract::FromRequest,
response::IntoResponse,
routing::{BoxResponseBody, EmptyRouter, MethodFilter, RouteFuture},
routing::{EmptyRouter, MethodFilter, RouteFuture},
service::HandleError,
};
use async_trait::async_trait;
use bytes::Bytes;
use futures_util::future::Either;
use http::{Request, Response};
use std::{
convert::Infallible,
@@ -647,14 +646,14 @@ impl<S, F> OnMethod<S, F> {
impl<S, F, SB, FB> Service<Request<Body>> for OnMethod<S, F>
where
S: Service<Request<Body>, Response = Response<SB>, Error = Infallible> + Clone,
SB: http_body::Body<Data = Bytes> + Send + Sync + 'static,
SB::Error: Into<BoxError>,
F: Service<Request<Body>, Response = Response<FB>, Error = Infallible> + Clone,
FB: http_body::Body<Data = Bytes> + Send + Sync + 'static,
SB: http_body::Body<Data = Bytes>,
SB::Error: Into<BoxError>,
FB: http_body::Body<Data = Bytes>,
FB::Error: Into<BoxError>,
{
type Response = Response<BoxBody>;
type Response = Response<body::Or<SB, FB>>;
type Error = Infallible;
type Future = RouteFuture<S, F>;
@@ -663,13 +662,12 @@ where
}
fn call(&mut self, req: Request<Body>) -> Self::Future {
let f = if self.method.matches(req.method()) {
let response_future = self.svc.clone().oneshot(req);
Either::Left(BoxResponseBody(response_future))
if self.method.matches(req.method()) {
let fut = self.svc.clone().oneshot(req);
RouteFuture::a(fut)
} else {
let response_future = self.fallback.clone().oneshot(req);
Either::Right(BoxResponseBody(response_future))
};
RouteFuture(f)
let fut = self.fallback.clone().oneshot(req);
RouteFuture::b(fut)
}
}
}