MiddlewareNext iterator without Box

Thanks @jsha for showing me the way.
This commit is contained in:
Martin Algesten
2021-12-21 08:39:16 +01:00
parent 43680335dc
commit 81c0e66ec7
3 changed files with 21 additions and 11 deletions

View File

@@ -43,7 +43,7 @@ pub struct AgentBuilder {
#[cfg(feature = "cookies")]
cookie_store: Option<CookieStore>,
resolver: ArcResolver,
middleware: Vec<Arc<dyn Middleware + Send + Sync>>,
middleware: Vec<Box<dyn Middleware + Send + Sync>>,
}
/// Config as built by AgentBuilder and then static for the lifetime of the Agent.
@@ -111,7 +111,7 @@ pub(crate) struct AgentState {
#[cfg(feature = "cookies")]
pub(crate) cookie_tin: CookieTin,
pub(crate) resolver: ArcResolver,
pub(crate) middleware: Vec<Arc<dyn Middleware + Send + Sync>>,
pub(crate) middleware: Vec<Box<dyn Middleware + Send + Sync>>,
}
impl Agent {
@@ -602,7 +602,7 @@ impl AgentBuilder {
/// All requests made by the agent will use this middleware. Middleware is invoked
/// in the order they are added to the builder.
pub fn middleware(mut self, m: impl Middleware + Send + Sync + 'static) -> Self {
self.middleware.push(Arc::new(m));
self.middleware.push(Box::new(m));
self
}
}

View File

@@ -1,5 +1,3 @@
use std::sync::Arc;
use crate::{Error, Request, Response};
/// Chained processing of request (and response).
@@ -135,13 +133,21 @@ pub trait Middleware {
/// Continuation of a [`Middleware`] chain.
pub struct MiddlewareNext<'a> {
pub(crate) chain: Box<dyn Iterator<Item = Arc<dyn Middleware + Send + Sync + 'static>>>,
pub(crate) chain: &'a mut (dyn Iterator<Item = &'a dyn Middleware>),
// Since request_fn consumes the Payload<'a>, we must have an FnOnce.
//
// It's possible to get rid of this Box if we make MiddlewareNext generic
// over some type variable, i.e. MiddlewareNext<'a, R> where R: FnOnce...
// however that would "leak" to Middleware::handle introducing a complicated
// type signature that is totally irrelevant for someone implementing a middleware.
//
// So in the name of having a sane external API, we accept this Box.
pub(crate) request_fn: Box<dyn FnOnce(Request) -> Result<Response, Error> + 'a>,
}
impl<'a> MiddlewareNext<'a> {
/// Continue the middleware chain by providing (a possibly amended) [`Request`].
pub fn handle(mut self, request: Request) -> Result<Response, Error> {
pub fn handle(self, request: Request) -> Result<Response, Error> {
if let Some(step) = self.chain.next() {
step.handle(request, self)
} else {

View File

@@ -7,8 +7,8 @@ use crate::body::Payload;
use crate::header::{self, Header};
use crate::middleware::MiddlewareNext;
use crate::unit::{self, Unit};
use crate::Response;
use crate::{agent::Agent, error::Error};
use crate::{Middleware, Response};
pub type Result<T> = std::result::Result<T, Error>;
@@ -141,9 +141,13 @@ impl Request {
};
let response = if !self.agent.state.middleware.is_empty() {
let middleware = self.agent.state.middleware.clone();
let chain = Box::new(middleware.into_iter());
// Clone agent to get a local copy with same lifetime as Payload
let agent = self.agent.clone();
let chain = &mut agent
.state
.middleware
.iter()
.map(|mw| mw.as_ref() as &dyn Middleware);
let request_fn = Box::new(request_fn);