actix-net
actix-net copied to clipboard
Improve `ServiceFactory` trait
Add second generic param for the receive argument for new_service method. Default to () because it's all service factory uses at last. actix-server only accept it.
Remove InitError type and use Error type for all instance of error. Most service factory already map the InitError to () at last.
pub trait ServiceFactory<Req, Arg = ()> {
type Response;
type Error;
type Service: Service<Req, Response = Self::Response, Error = Self::Error>;
type Future: Future<Output = Result<Self::Service, Self::Error>>;
fn new_service(&self, arg: Arg) -> Self::Future;
}
Remove Transform
trait and use the new ServiceFactory
trait directly for middleware
impl<S, Req> ServiceFactory<Req, S> for MiddlewareBuilder
where
S: Service<Req>
{
type Response = S::Response;
type Error = S::Error;
type Service = Middleware<S>;
type Future = LocalBoxFuture<'static, Result<Self::Service, Self::Error>;
fn new_service(&self, service: S) -> Self::Future {
Box::pin(async { Ok(Middleware(service)) })
}
}
The actual middleware construct logic would become
impl<F, Req, Arg> ServiceFactoryExt<Req, Arg> for F
where
F: ServiceFactory<Req, Arg>
{
fn wrap<M>(self, middleware_builder: M) -> Builder<Self, M>
where
M: ServiceFactory<Req, Self::Service>
{
Builder { factory: self, middleware_builder: Rc::new(middleware_builder) }
}
}
impl<F, Req, Arg, M> ServiceFactory<Req, Arg> for Builder<F, M>
where
F: ServiceFactory<Req, Arg>
M: ServiceFactory<Req, F::Service>
M::Error: From<F::Error>
{
type Response = M::Response;
type Error = M::Error;
type Service = M::Service;
type Future = LocalBoxFuture<'static, Result<Self::Service, Self::Error>;
fn new_service(&self, arg: Arg) -> Self::Future {
let middleware_builder = self.middleware_builder.clone();
let service = self.factory.new_service(arg);
Box::pin(async move {
let service = service.await?;
middleware_builder.new_service(service).await
})
}
}
It's also considerable to just throw the typed future on ServiceFactory
trait. No one would construct Service all the time and in most case it's one time cost on server start up for every worker thread.
pub trait ServiceFactory<Req, Arg = ()> {
type Response;
type Error;
type Service: Service<Req, Response = Self::Response, Error = Self::Error>;
fn new_service(&self, arg: Arg) -> Pin<Box<dyn Future<Output = Result<Self::Service, Self::Error>> + '_>>;
}