Skip to content

Commit

Permalink
remove service dev module and add transformext trait
Browse files Browse the repository at this point in the history
also improve docs on transform and boxed mods
  • Loading branch information
robjtede committed Mar 10, 2021
1 parent 0a705b1 commit 91ea8c5
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 89 deletions.
63 changes: 33 additions & 30 deletions actix-service/src/boxed.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
//! Trait object forms of services and service factories.
use alloc::{boxed::Box, rc::Rc};
use core::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
use core::{future::Future, pin::Pin};

use crate::{Service, ServiceFactory};

/// A boxed future without a Send bound or lifetime parameters.
pub type BoxFuture<T> = Pin<Box<dyn Future<Output = T>>>;

macro_rules! service_object {
Expand All @@ -23,17 +22,41 @@ macro_rules! service_object {
Req: 'static,
S::Future: 'static,
{
$type::new(ServiceWrapper(service))
$type::new(ServiceWrapper::new(service))
}
};
}

service_object!(BoxService, Box, service);

service_object!(RcService, Rc, rc_service);

/// Type alias for service factory trait object that would produce a trait object service
/// (`BoxService`, `RcService`, etc.)
struct ServiceWrapper<S> {
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>);

/// Create service factory trait object.
Expand Down Expand Up @@ -107,26 +130,6 @@ where

fn new_service(&self, cfg: Cfg) -> Self::Future {
let f = self.0.new_service(cfg);
Box::pin(async { f.await.map(|s| Box::new(ServiceWrapper(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))
Box::pin(async { f.await.map(|s| Box::new(ServiceWrapper::new(s)) as _) })
}
}
28 changes: 22 additions & 6 deletions actix-service/src/ext.rs
Original file line number Diff line number Diff line change
@@ -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> {
/// Map this service's output to a different type, returning a new service
Expand All @@ -10,12 +13,12 @@ pub trait ServiceExt<Req>: Service<Req> {
/// Note that this function consumes the receiving service and returns a
/// wrapped version of it, similar to the existing `map` methods in the
/// 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
Self: Sized,
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.
Expand All @@ -26,12 +29,12 @@ pub trait ServiceExt<Req>: Service<Req> {
///
/// Note that this function consumes the receiving service and returns a
/// 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
Self: Sized,
F: Fn(Self::Error) -> E,
{
dev::MapErr::new(self, f)
MapErr::new(self, f)
}
}

Expand Down Expand Up @@ -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> {}
10 changes: 4 additions & 6 deletions actix-service/src/fn_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ where

/// Create `ServiceFactory` for function that can produce services
///
/// # Example
///
/// # Examples
/// ```
/// use std::io;
/// use actix_service::{fn_factory, fn_service, Service, ServiceFactory};
Expand Down Expand Up @@ -62,11 +61,10 @@ where

/// Create `ServiceFactory` for function that accepts config argument and can produce services
///
/// Any function that has following form `Fn(Config) -> Future<Output = Service>` could
/// act as a `ServiceFactory`.
///
/// # Example
/// Any function that has following form `Fn(Config) -> Future<Output = Service>` could act as
/// a `ServiceFactory`.
///
/// # Examples
/// ```
/// use std::io;
/// use actix_service::{fn_factory_with_config, fn_service, Service, ServiceFactory};
Expand Down
18 changes: 3 additions & 15 deletions actix-service/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ mod transform_err;

pub use self::apply::{apply_fn, apply_fn_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::map_config::{map_config, unit_config};
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)]
use self::ready::{err, ok, ready, Ready};
Expand Down Expand Up @@ -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>
where
S: Service<Req>,
Expand Down Expand Up @@ -313,16 +314,3 @@ where
{
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;
}
41 changes: 14 additions & 27 deletions actix-service/src/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@ use core::{
use futures_core::ready;
use pin_project_lite::pin_project;

use crate::transform_err::TransformMapInitErr;
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>
where
I: IntoServiceFactory<S, Req>,
Expand All @@ -25,9 +24,8 @@ where
/// The `Transform` trait defines the interface of a service factory that wraps inner service
/// during construction.
///
/// Transform(middleware) wraps inner service and runs during
/// inbound and/or outbound processing in the request/response lifecycle.
/// It may modify request and/or response.
/// Transform(middleware) wraps inner service and runs during inbound and/or outbound processing in
/// the request/response lifecycle. It may modify request and/or response.
///
/// For example, timeout transform:
///
Expand All @@ -51,20 +49,19 @@ where
/// fn call(&self, req: S::Request) -> Self::Future {
/// TimeoutServiceResponse {
/// 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
/// and could be applied to any service.
/// Timeout service in above example is decoupled from underlying service implementation and could
/// be applied to any service.
///
/// The `Transform` trait defines the interface of a Service factory. `Transform`
/// is often implemented for middleware, defining how to construct a
/// middleware Service. A Service that is constructed by the factory takes
/// the Service that follows it during execution as a parameter, assuming
/// ownership of the next Service.
/// The `Transform` trait defines the interface of a Service factory. `Transform` is often
/// implemented for middleware, defining how to construct a middleware Service. A Service that is
/// constructed by the factory takes the Service that follows it during execution as a parameter,
/// assuming ownership of the next Service.
///
/// Factory for `Timeout` middleware from the above example could look like this:
///
Expand All @@ -85,15 +82,15 @@ where
/// type Future = Ready<Result<Self::Transform, Self::InitError>>;
///
/// fn new_transform(&self, service: S) -> Self::Future {
/// ok(TimeoutService {
/// ready(Ok(TimeoutService {
/// service,
/// timeout: self.timeout,
/// })
/// }))
/// }
/// }
/// ```
pub trait Transform<S, Req> {
/// Responses given by the service.
/// Responses produced by the service.
type Response;

/// Errors produced by the service.
Expand All @@ -110,16 +107,6 @@ pub trait Transform<S, Req> {

/// Creates and returns a new Transform component, asynchronously
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>
Expand Down Expand Up @@ -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>);

impl<T, S, Req> ApplyTransform<T, S, Req>
Expand Down
6 changes: 2 additions & 4 deletions actix-service/src/transform_err.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@ use pin_project_lite::pin_project;

use super::Transform;

/// Transform for the `map_init_err` combinator, changing the type of a new
/// transform's init error.
///
/// This is created by the `Transform::map_init_err` method.
/// Transform for the [`TransformExt::map_init_err`] combinator, changing the type of a new
/// [`Transform`]'s initialization error.
pub struct TransformMapInitErr<T, S, Req, F, E> {
transform: T,
mapper: F,
Expand Down
2 changes: 1 addition & 1 deletion actix-tracing/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use core::marker::PhantomData;

use actix_service::{
apply, dev::ApplyTransform, IntoServiceFactory, Service, ServiceFactory, Transform,
apply, ApplyTransform, IntoServiceFactory, Service, ServiceFactory, Transform,
};
use futures_util::future::{ok, Either, Ready};
use tracing_futures::{Instrument, Instrumented};
Expand Down

0 comments on commit 91ea8c5

Please sign in to comment.