1
0
mirror of https://github.com/fafhrd91/actix-net synced 2025-02-20 07:40:33 +01:00

remove service dev module and add transformext trait

also improve docs on transform and boxed mods
This commit is contained in:
Rob Ede 2021-03-10 03:18:09 +00:00
parent 0a705b1023
commit 91ea8c5dad
No known key found for this signature in database
GPG Key ID: 97C636207D3EF933
7 changed files with 79 additions and 89 deletions

View File

@ -1,12 +1,11 @@
//! Trait object forms of services and service factories.
use alloc::{boxed::Box, rc::Rc}; use alloc::{boxed::Box, rc::Rc};
use core::{ use core::{future::Future, pin::Pin};
future::Future,
pin::Pin,
task::{Context, Poll},
};
use crate::{Service, ServiceFactory}; use crate::{Service, ServiceFactory};
/// A boxed future without a Send bound or lifetime parameters.
pub type BoxFuture<T> = Pin<Box<dyn Future<Output = T>>>; pub type BoxFuture<T> = Pin<Box<dyn Future<Output = T>>>;
macro_rules! service_object { macro_rules! service_object {
@ -23,17 +22,41 @@ macro_rules! service_object {
Req: 'static, Req: 'static,
S::Future: 'static, S::Future: 'static,
{ {
$type::new(ServiceWrapper(service)) $type::new(ServiceWrapper::new(service))
} }
}; };
} }
service_object!(BoxService, Box, service); service_object!(BoxService, Box, service);
service_object!(RcService, Rc, rc_service); service_object!(RcService, Rc, rc_service);
/// Type alias for service factory trait object that would produce a trait object service struct ServiceWrapper<S> {
/// (`BoxService`, `RcService`, etc.) inner: S,
}
impl<S> ServiceWrapper<S> {
fn new(inner: S) -> Self {
Self { inner }
}
}
impl<S, Req, Res, Err> Service<Req> for ServiceWrapper<S>
where
S: Service<Req, Response = Res, Error = Err>,
S::Future: 'static,
{
type Response = Res;
type Error = Err;
type Future = BoxFuture<Result<Res, Err>>;
crate::forward_ready!(inner);
fn call(&self, req: Req) -> Self::Future {
Box::pin(self.inner.call(req))
}
}
/// Wrapper for a service factory trait object that will produce a boxed trait object service.
pub struct BoxServiceFactory<Cfg, Req, Res, Err, InitErr>(Inner<Cfg, Req, Res, Err, InitErr>); pub struct BoxServiceFactory<Cfg, Req, Res, Err, InitErr>(Inner<Cfg, Req, Res, Err, InitErr>);
/// Create service factory trait object. /// Create service factory trait object.
@ -107,26 +130,6 @@ where
fn new_service(&self, cfg: Cfg) -> Self::Future { fn new_service(&self, cfg: Cfg) -> Self::Future {
let f = self.0.new_service(cfg); let f = self.0.new_service(cfg);
Box::pin(async { f.await.map(|s| Box::new(ServiceWrapper(s)) as _) }) Box::pin(async { f.await.map(|s| Box::new(ServiceWrapper::new(s)) as _) })
}
}
struct ServiceWrapper<S>(S);
impl<S, Req, Res, Err> Service<Req> for ServiceWrapper<S>
where
S: Service<Req, Response = Res, Error = Err>,
S::Future: 'static,
{
type Response = Res;
type Error = Err;
type Future = BoxFuture<Result<Res, Err>>;
fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.0.poll_ready(ctx)
}
fn call(&self, req: Req) -> Self::Future {
Box::pin(self.0.call(req))
} }
} }

View File

@ -1,4 +1,7 @@
use crate::{dev, Service, ServiceFactory}; use crate::{
map::Map, map_err::MapErr, transform_err::TransformMapInitErr, Service, ServiceFactory,
Transform,
};
pub trait ServiceExt<Req>: Service<Req> { pub trait ServiceExt<Req>: Service<Req> {
/// Map this service's output to a different type, returning a new service /// Map this service's output to a different type, returning a new service
@ -10,12 +13,12 @@ pub trait ServiceExt<Req>: Service<Req> {
/// Note that this function consumes the receiving service and returns a /// Note that this function consumes the receiving service and returns a
/// wrapped version of it, similar to the existing `map` methods in the /// wrapped version of it, similar to the existing `map` methods in the
/// standard library. /// standard library.
fn map<F, R>(self, f: F) -> dev::Map<Self, F, Req, R> fn map<F, R>(self, f: F) -> Map<Self, F, Req, R>
where where
Self: Sized, Self: Sized,
F: FnMut(Self::Response) -> R, F: FnMut(Self::Response) -> R,
{ {
dev::Map::new(self, f) Map::new(self, f)
} }
/// Map this service's error to a different error, returning a new service. /// Map this service's error to a different error, returning a new service.
@ -26,12 +29,12 @@ pub trait ServiceExt<Req>: Service<Req> {
/// ///
/// Note that this function consumes the receiving service and returns a /// Note that this function consumes the receiving service and returns a
/// wrapped version of it. /// wrapped version of it.
fn map_err<F, E>(self, f: F) -> dev::MapErr<Self, Req, F, E> fn map_err<F, E>(self, f: F) -> MapErr<Self, Req, F, E>
where where
Self: Sized, Self: Sized,
F: Fn(Self::Error) -> E, F: Fn(Self::Error) -> E,
{ {
dev::MapErr::new(self, f) MapErr::new(self, f)
} }
} }
@ -67,4 +70,17 @@ pub trait ServiceFactoryExt<Req>: ServiceFactory<Req> {
} }
} }
impl<S, Req> ServiceFactoryExt<Req> for S where S: ServiceFactory<Req> {} impl<SF, Req> ServiceFactoryExt<Req> for SF where SF: ServiceFactory<Req> {}
pub trait TransformExt<S, Req>: Transform<S, Req> {
/// Return a new `Transform` whose init error is mapped to to a different type.
fn map_init_err<F, E>(self, f: F) -> TransformMapInitErr<Self, S, Req, F, E>
where
Self: Sized,
F: Fn(Self::InitError) -> E + Clone,
{
TransformMapInitErr::new(self, f)
}
}
impl<T, Req> TransformExt<T, Req> for T where T: Transform<T, Req> {}

View File

@ -15,8 +15,7 @@ where
/// Create `ServiceFactory` for function that can produce services /// Create `ServiceFactory` for function that can produce services
/// ///
/// # Example /// # Examples
///
/// ``` /// ```
/// use std::io; /// use std::io;
/// use actix_service::{fn_factory, fn_service, Service, ServiceFactory}; /// use actix_service::{fn_factory, fn_service, Service, ServiceFactory};
@ -62,11 +61,10 @@ where
/// Create `ServiceFactory` for function that accepts config argument and can produce services /// Create `ServiceFactory` for function that accepts config argument and can produce services
/// ///
/// Any function that has following form `Fn(Config) -> Future<Output = Service>` could /// Any function that has following form `Fn(Config) -> Future<Output = Service>` could act as
/// act as a `ServiceFactory`. /// a `ServiceFactory`.
///
/// # Example
/// ///
/// # Examples
/// ``` /// ```
/// use std::io; /// use std::io;
/// use actix_service::{fn_factory_with_config, fn_service, Service, ServiceFactory}; /// use actix_service::{fn_factory_with_config, fn_service, Service, ServiceFactory};

View File

@ -34,11 +34,11 @@ mod transform_err;
pub use self::apply::{apply_fn, apply_fn_factory}; pub use self::apply::{apply_fn, apply_fn_factory};
pub use self::apply_cfg::{apply_cfg, apply_cfg_factory}; pub use self::apply_cfg::{apply_cfg, apply_cfg_factory};
pub use self::ext::{ServiceExt, ServiceFactoryExt}; pub use self::ext::{ServiceExt, ServiceFactoryExt, TransformExt};
pub use self::fn_service::{fn_factory, fn_factory_with_config, fn_service}; pub use self::fn_service::{fn_factory, fn_factory_with_config, fn_service};
pub use self::map_config::{map_config, unit_config}; pub use self::map_config::{map_config, unit_config};
pub use self::pipeline::{pipeline, pipeline_factory, Pipeline, PipelineFactory}; pub use self::pipeline::{pipeline, pipeline_factory, Pipeline, PipelineFactory};
pub use self::transform::{apply, Transform}; pub use self::transform::{apply, ApplyTransform, Transform};
#[allow(unused_imports)] #[allow(unused_imports)]
use self::ready::{err, ok, ready, Ready}; use self::ready::{err, ok, ready, Ready};
@ -220,6 +220,7 @@ where
} }
} }
/// This impl is deprecated since v2 because the `Service` trait now receives shared reference.
impl<S, Req> Service<Req> for RefCell<S> impl<S, Req> Service<Req> for RefCell<S>
where where
S: Service<Req>, S: Service<Req>,
@ -313,16 +314,3 @@ where
{ {
tp.into_service() tp.into_service()
} }
pub mod dev {
pub use crate::apply::{Apply, ApplyFactory};
pub use crate::fn_service::{
FnService, FnServiceConfig, FnServiceFactory, FnServiceNoConfig,
};
pub use crate::map::{Map, MapServiceFactory};
pub use crate::map_config::{MapConfig, UnitConfig};
pub use crate::map_err::{MapErr, MapErrServiceFactory};
pub use crate::map_init_err::MapInitErr;
pub use crate::transform::ApplyTransform;
pub use crate::transform_err::TransformMapInitErr;
}

View File

@ -9,10 +9,9 @@ use core::{
use futures_core::ready; use futures_core::ready;
use pin_project_lite::pin_project; use pin_project_lite::pin_project;
use crate::transform_err::TransformMapInitErr;
use crate::{IntoServiceFactory, Service, ServiceFactory}; use crate::{IntoServiceFactory, Service, ServiceFactory};
/// Apply transform to a service. /// Apply a [`Transform`] to a [`Service`].
pub fn apply<T, S, I, Req>(t: T, factory: I) -> ApplyTransform<T, S, Req> pub fn apply<T, S, I, Req>(t: T, factory: I) -> ApplyTransform<T, S, Req>
where where
I: IntoServiceFactory<S, Req>, I: IntoServiceFactory<S, Req>,
@ -25,9 +24,8 @@ where
/// The `Transform` trait defines the interface of a service factory that wraps inner service /// The `Transform` trait defines the interface of a service factory that wraps inner service
/// during construction. /// during construction.
/// ///
/// Transform(middleware) wraps inner service and runs during /// Transform(middleware) wraps inner service and runs during inbound and/or outbound processing in
/// inbound and/or outbound processing in the request/response lifecycle. /// the request/response lifecycle. It may modify request and/or response.
/// It may modify request and/or response.
/// ///
/// For example, timeout transform: /// For example, timeout transform:
/// ///
@ -51,20 +49,19 @@ where
/// fn call(&self, req: S::Request) -> Self::Future { /// fn call(&self, req: S::Request) -> Self::Future {
/// TimeoutServiceResponse { /// TimeoutServiceResponse {
/// fut: self.service.call(req), /// fut: self.service.call(req),
/// sleep: Delay::new(clock::now() + self.timeout), /// sleep: Sleep::new(clock::now() + self.timeout),
/// } /// }
/// } /// }
/// } /// }
/// ``` /// ```
/// ///
/// Timeout service in above example is decoupled from underlying service implementation /// Timeout service in above example is decoupled from underlying service implementation and could
/// and could be applied to any service. /// be applied to any service.
/// ///
/// The `Transform` trait defines the interface of a Service factory. `Transform` /// The `Transform` trait defines the interface of a Service factory. `Transform` is often
/// is often implemented for middleware, defining how to construct a /// implemented for middleware, defining how to construct a middleware Service. A Service that is
/// middleware Service. A Service that is constructed by the factory takes /// constructed by the factory takes the Service that follows it during execution as a parameter,
/// the Service that follows it during execution as a parameter, assuming /// assuming ownership of the next Service.
/// ownership of the next Service.
/// ///
/// Factory for `Timeout` middleware from the above example could look like this: /// Factory for `Timeout` middleware from the above example could look like this:
/// ///
@ -85,15 +82,15 @@ where
/// type Future = Ready<Result<Self::Transform, Self::InitError>>; /// type Future = Ready<Result<Self::Transform, Self::InitError>>;
/// ///
/// fn new_transform(&self, service: S) -> Self::Future { /// fn new_transform(&self, service: S) -> Self::Future {
/// ok(TimeoutService { /// ready(Ok(TimeoutService {
/// service, /// service,
/// timeout: self.timeout, /// timeout: self.timeout,
/// }) /// }))
/// } /// }
/// } /// }
/// ``` /// ```
pub trait Transform<S, Req> { pub trait Transform<S, Req> {
/// Responses given by the service. /// Responses produced by the service.
type Response; type Response;
/// Errors produced by the service. /// Errors produced by the service.
@ -110,16 +107,6 @@ pub trait Transform<S, Req> {
/// Creates and returns a new Transform component, asynchronously /// Creates and returns a new Transform component, asynchronously
fn new_transform(&self, service: S) -> Self::Future; fn new_transform(&self, service: S) -> Self::Future;
/// Map this transform's factory error to a different error,
/// returning a new transform service factory.
fn map_init_err<F, E>(self, f: F) -> TransformMapInitErr<Self, S, Req, F, E>
where
Self: Sized,
F: Fn(Self::InitError) -> E + Clone,
{
TransformMapInitErr::new(self, f)
}
} }
impl<T, S, Req> Transform<S, Req> for Rc<T> impl<T, S, Req> Transform<S, Req> for Rc<T>
@ -152,7 +139,7 @@ where
} }
} }
/// `Apply` transform to new service /// Apply a [`Transform`] to a [`Service`].
pub struct ApplyTransform<T, S, Req>(Rc<(T, S)>, PhantomData<Req>); pub struct ApplyTransform<T, S, Req>(Rc<(T, S)>, PhantomData<Req>);
impl<T, S, Req> ApplyTransform<T, S, Req> impl<T, S, Req> ApplyTransform<T, S, Req>

View File

@ -9,10 +9,8 @@ use pin_project_lite::pin_project;
use super::Transform; use super::Transform;
/// Transform for the `map_init_err` combinator, changing the type of a new /// Transform for the [`TransformExt::map_init_err`] combinator, changing the type of a new
/// transform's init error. /// [`Transform`]'s initialization error.
///
/// This is created by the `Transform::map_init_err` method.
pub struct TransformMapInitErr<T, S, Req, F, E> { pub struct TransformMapInitErr<T, S, Req, F, E> {
transform: T, transform: T,
mapper: F, mapper: F,

View File

@ -7,7 +7,7 @@
use core::marker::PhantomData; use core::marker::PhantomData;
use actix_service::{ use actix_service::{
apply, dev::ApplyTransform, IntoServiceFactory, Service, ServiceFactory, Transform, apply, ApplyTransform, IntoServiceFactory, Service, ServiceFactory, Transform,
}; };
use futures_util::future::{ok, Either, Ready}; use futures_util::future::{ok, Either, Ready};
use tracing_futures::{Instrument, Instrumented}; use tracing_futures::{Instrument, Instrumented};