mirror of
https://github.com/ntex-rs/ntex.git
synced 2025-04-06 06:17:40 +03:00
simplify Transform trait; add PipelineFactory::apply() combinator
This commit is contained in:
parent
fe73511576
commit
b4b6f2fe88
7 changed files with 50 additions and 213 deletions
|
@ -1,5 +1,11 @@
|
|||
# Changes
|
||||
|
||||
## [0.2.0-b.0] - 2021-08-26
|
||||
|
||||
* Simplify Transform trait
|
||||
|
||||
* Add PipelineFactory::apply() combinator
|
||||
|
||||
## [0.1.9] - 2021-06-03
|
||||
|
||||
* Add rc wrapped service, `RcService`
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "ntex-service"
|
||||
version = "0.1.9"
|
||||
version = "0.2.0-b.0"
|
||||
authors = ["ntex contributors <team@ntex.rs>"]
|
||||
description = "ntex service"
|
||||
keywords = ["network", "framework", "async", "futures"]
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
use ntex_util::future::Ready;
|
||||
use std::{future::Future, marker::PhantomData};
|
||||
|
||||
use crate::{apply_fn, dev::Apply, Service, Transform};
|
||||
|
||||
/// Use function as transform service
|
||||
pub fn fn_transform<S, F, R, Req, Res, Err>(
|
||||
f: F,
|
||||
) -> impl Transform<S, Request = Req, Response = Res, Error = Err, InitError = ()> + Clone
|
||||
pub fn fn_transform<S, F, R, Req, Res, Err>(f: F) -> FnTransform<S, F, R, Req, Res, Err>
|
||||
where
|
||||
S: Service<Error = Err>,
|
||||
F: Fn(Req, &S) -> R + Clone,
|
||||
|
@ -42,15 +39,10 @@ where
|
|||
F: Fn(Req, &S) -> R + Clone,
|
||||
R: Future<Output = Result<Res, Err>>,
|
||||
{
|
||||
type Request = Req;
|
||||
type Response = Res;
|
||||
type Error = Err;
|
||||
type Transform = Apply<S, F, R, Req, Res, Err>;
|
||||
type InitError = ();
|
||||
type Future = Ready<Self::Transform, Self::InitError>;
|
||||
|
||||
fn new_transform(&self, service: S) -> Self::Future {
|
||||
Ready::Ok(apply_fn(service, self.f.clone()))
|
||||
fn new_transform(&self, service: S) -> Self::Transform {
|
||||
apply_fn(service, self.f.clone())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,7 +60,7 @@ where
|
|||
#[cfg(test)]
|
||||
#[allow(clippy::redundant_clone)]
|
||||
mod tests {
|
||||
use ntex_util::future::lazy;
|
||||
use ntex_util::future::{lazy, Ready};
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use super::*;
|
||||
|
@ -94,12 +86,7 @@ mod tests {
|
|||
|
||||
#[ntex::test]
|
||||
async fn transform() {
|
||||
let srv =
|
||||
fn_transform::<Srv, _, _, _, _, _>(|i: usize, srv: &_| srv.call(i + 1))
|
||||
.clone()
|
||||
.new_transform(Srv)
|
||||
.await
|
||||
.unwrap();
|
||||
let srv = fn_transform(|i: usize, srv: &Srv| srv.call(i + 1)).new_transform(Srv);
|
||||
|
||||
let res = srv.call(10usize).await;
|
||||
assert!(res.is_ok());
|
||||
|
|
|
@ -19,7 +19,6 @@ mod map_init_err;
|
|||
mod pipeline;
|
||||
mod then;
|
||||
mod transform;
|
||||
mod transform_err;
|
||||
|
||||
pub use self::apply::{apply_fn, apply_fn_factory};
|
||||
pub use self::fn_service::{
|
||||
|
@ -342,17 +341,10 @@ pub mod dev {
|
|||
pub use crate::fn_service::{
|
||||
FnMutService, FnService, FnServiceConfig, FnServiceFactory, FnServiceNoConfig,
|
||||
};
|
||||
pub use crate::fn_transform::FnTransform;
|
||||
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;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub mod util {
|
||||
pub use ntex_util::future::Either;
|
||||
pub use ntex_util::future::Ready;
|
||||
pub use ntex_util::future::{lazy, Lazy};
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ use crate::map::{Map, MapServiceFactory};
|
|||
use crate::map_err::{MapErr, MapErrServiceFactory};
|
||||
use crate::map_init_err::MapInitErr;
|
||||
use crate::then::{ThenService, ThenServiceFactory};
|
||||
use crate::transform::{ApplyTransform, Transform};
|
||||
use crate::{IntoService, IntoServiceFactory, Service, ServiceFactory};
|
||||
|
||||
/// Contruct new pipeline with one service in pipeline chain.
|
||||
|
@ -249,6 +250,18 @@ impl<T: ServiceFactory> PipelineFactory<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Apply transform to current service factory.
|
||||
///
|
||||
/// Short version of `apply(transform, pipeline_factory(...))`
|
||||
pub fn apply<U>(self, tr: U) -> PipelineFactory<ApplyTransform<U, T>>
|
||||
where
|
||||
U: Transform<T::Service>,
|
||||
{
|
||||
PipelineFactory {
|
||||
factory: ApplyTransform::new(tr, self.factory),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create `NewService` to chain on a computation for when a call to the
|
||||
/// service finished, passing the result of the call to the next
|
||||
/// service `U`.
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
use std::{future::Future, pin::Pin, rc::Rc, task::Context, task::Poll};
|
||||
|
||||
use crate::transform_err::TransformMapInitErr;
|
||||
use crate::{IntoServiceFactory, Service, ServiceFactory};
|
||||
|
||||
/// Apply transform to a service.
|
||||
pub fn apply<T, S, U>(t: T, factory: U) -> ApplyTransform<T, S>
|
||||
where
|
||||
S: ServiceFactory,
|
||||
T: Transform<S::Service, InitError = S::InitError>,
|
||||
T: Transform<S::Service>,
|
||||
U: IntoServiceFactory<S>,
|
||||
{
|
||||
ApplyTransform::new(t, factory.into_factory())
|
||||
|
@ -70,14 +69,9 @@ where
|
|||
/// where
|
||||
/// S: Service,
|
||||
/// {
|
||||
/// type Request = S::Request;
|
||||
/// type Response = S::Response;
|
||||
/// type Error = TimeoutError<S::Error>;
|
||||
/// type InitError = S::Error;
|
||||
/// type Transform = Timeout<S>;
|
||||
/// type Future = Ready<Result<Self::Transform, Self::InitError>>;
|
||||
///
|
||||
/// fn new_transform(&self, service: S) -> Self::Future {
|
||||
/// fn new_transform(&self, service: S) -> Self::Transform {
|
||||
/// ok(TimeoutService {
|
||||
/// service,
|
||||
/// timeout: self.timeout,
|
||||
|
@ -86,54 +80,20 @@ where
|
|||
/// }
|
||||
/// ```
|
||||
pub trait Transform<S> {
|
||||
/// Requests handled by the service.
|
||||
type Request;
|
||||
|
||||
/// Responses given by the service.
|
||||
type Response;
|
||||
|
||||
/// Errors produced by the service.
|
||||
type Error;
|
||||
|
||||
/// The `TransformService` value created by this factory
|
||||
type Transform: Service<
|
||||
Request = Self::Request,
|
||||
Response = Self::Response,
|
||||
Error = Self::Error,
|
||||
>;
|
||||
|
||||
/// Errors produced while building a transform service.
|
||||
type InitError;
|
||||
|
||||
/// The future response value.
|
||||
type Future: Future<Output = Result<Self::Transform, Self::InitError>>;
|
||||
type Transform: Service;
|
||||
|
||||
/// Creates and returns a new Transform component, asynchronously
|
||||
fn new_transform(&self, service: S) -> Self::Future;
|
||||
|
||||
/// Map this transforms'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, F, E>
|
||||
where
|
||||
Self: Sized,
|
||||
F: Fn(Self::InitError) -> E + Clone,
|
||||
{
|
||||
TransformMapInitErr::new(self, f)
|
||||
}
|
||||
fn new_transform(&self, service: S) -> Self::Transform;
|
||||
}
|
||||
|
||||
impl<T, S> Transform<S> for Rc<T>
|
||||
where
|
||||
T: Transform<S>,
|
||||
{
|
||||
type Request = T::Request;
|
||||
type Response = T::Response;
|
||||
type Error = T::Error;
|
||||
type InitError = T::InitError;
|
||||
type Transform = T::Transform;
|
||||
type Future = T::Future;
|
||||
|
||||
fn new_transform(&self, service: S) -> T::Future {
|
||||
fn new_transform(&self, service: S) -> T::Transform {
|
||||
self.as_ref().new_transform(service)
|
||||
}
|
||||
}
|
||||
|
@ -144,10 +104,10 @@ pub struct ApplyTransform<T, S>(Rc<(T, S)>);
|
|||
impl<T, S> ApplyTransform<T, S>
|
||||
where
|
||||
S: ServiceFactory,
|
||||
T: Transform<S::Service, InitError = S::InitError>,
|
||||
T: Transform<S::Service>,
|
||||
{
|
||||
/// Create new `ApplyTransform` new service instance
|
||||
fn new(t: T, service: S) -> Self {
|
||||
pub(crate) fn new(t: T, service: S) -> Self {
|
||||
Self(Rc::new((t, service)))
|
||||
}
|
||||
}
|
||||
|
@ -161,23 +121,21 @@ impl<T, S> Clone for ApplyTransform<T, S> {
|
|||
impl<T, S> ServiceFactory for ApplyTransform<T, S>
|
||||
where
|
||||
S: ServiceFactory,
|
||||
T: Transform<S::Service, InitError = S::InitError>,
|
||||
T: Transform<S::Service>,
|
||||
{
|
||||
type Request = T::Request;
|
||||
type Response = T::Response;
|
||||
type Error = T::Error;
|
||||
type Request = <T::Transform as Service>::Request;
|
||||
type Response = <T::Transform as Service>::Response;
|
||||
type Error = <T::Transform as Service>::Error;
|
||||
|
||||
type Config = S::Config;
|
||||
type Service = T::Transform;
|
||||
type InitError = T::InitError;
|
||||
type InitError = S::InitError;
|
||||
type Future = ApplyTransformFuture<T, S>;
|
||||
|
||||
fn new_service(&self, cfg: S::Config) -> Self::Future {
|
||||
ApplyTransformFuture {
|
||||
store: self.0.clone(),
|
||||
state: ApplyTransformFutureState::A {
|
||||
fut: self.0.as_ref().1.new_service(cfg),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -186,46 +144,27 @@ pin_project_lite::pin_project! {
|
|||
pub struct ApplyTransformFuture<T, S>
|
||||
where
|
||||
S: ServiceFactory,
|
||||
T: Transform<S::Service, InitError = S::InitError>,
|
||||
T: Transform<S::Service>,
|
||||
{
|
||||
store: Rc<(T, S)>,
|
||||
#[pin]
|
||||
state: ApplyTransformFutureState<T, S>,
|
||||
}
|
||||
}
|
||||
|
||||
pin_project_lite::pin_project! {
|
||||
#[project = ApplyTransformFutureStateProject]
|
||||
pub enum ApplyTransformFutureState<T, S>
|
||||
where
|
||||
S: ServiceFactory,
|
||||
T: Transform<S::Service, InitError = S::InitError>,
|
||||
{
|
||||
A { #[pin] fut: S::Future },
|
||||
B { #[pin] fut: T::Future },
|
||||
fut: S::Future,
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S> Future for ApplyTransformFuture<T, S>
|
||||
where
|
||||
S: ServiceFactory,
|
||||
T: Transform<S::Service, InitError = S::InitError>,
|
||||
T: Transform<S::Service>,
|
||||
{
|
||||
type Output = Result<T::Transform, T::InitError>;
|
||||
type Output = Result<T::Transform, S::InitError>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let mut this = self.as_mut().project();
|
||||
let this = self.as_mut().project();
|
||||
|
||||
match this.state.as_mut().project() {
|
||||
ApplyTransformFutureStateProject::A { fut } => match fut.poll(cx)? {
|
||||
Poll::Ready(srv) => {
|
||||
let fut = this.store.0.new_transform(srv);
|
||||
this.state.set(ApplyTransformFutureState::B { fut });
|
||||
self.poll(cx)
|
||||
}
|
||||
match this.fut.poll(cx)? {
|
||||
Poll::Ready(srv) => Poll::Ready(Ok(this.store.0.new_transform(srv))),
|
||||
Poll::Pending => Poll::Pending,
|
||||
},
|
||||
ApplyTransformFutureStateProject::B { fut } => fut.poll(cx),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -242,16 +181,10 @@ mod tests {
|
|||
struct Tr;
|
||||
|
||||
impl<S: Service> Transform<S> for Tr {
|
||||
type Request = S::Request;
|
||||
type Response = S::Response;
|
||||
type Error = S::Error;
|
||||
|
||||
type Transform = Srv<S>;
|
||||
type InitError = ();
|
||||
type Future = Ready<Self::Transform, Self::InitError>;
|
||||
|
||||
fn new_transform(&self, service: S) -> Self::Future {
|
||||
Ready::Ok(Srv(service))
|
||||
fn new_transform(&self, service: S) -> Self::Transform {
|
||||
Srv(service)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -276,7 +209,7 @@ mod tests {
|
|||
#[ntex::test]
|
||||
async fn transform() {
|
||||
let factory = apply(
|
||||
Rc::new(Tr.map_init_err(|_| ()).clone()),
|
||||
Rc::new(Tr.clone()),
|
||||
fn_service(|i: usize| Ready::<_, ()>::Ok(i * 2)),
|
||||
)
|
||||
.clone();
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
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.
|
||||
pub struct TransformMapInitErr<T, S, F, E> {
|
||||
t: T,
|
||||
f: F,
|
||||
e: PhantomData<(S, E)>,
|
||||
}
|
||||
|
||||
impl<T, S, F, E> TransformMapInitErr<T, S, F, E> {
|
||||
pub(crate) fn new(t: T, f: F) -> Self
|
||||
where
|
||||
T: Transform<S>,
|
||||
F: Fn(T::InitError) -> E,
|
||||
{
|
||||
Self {
|
||||
t,
|
||||
f,
|
||||
e: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S, F, E> Clone for TransformMapInitErr<T, S, F, E>
|
||||
where
|
||||
T: Clone,
|
||||
F: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
t: self.t.clone(),
|
||||
f: self.f.clone(),
|
||||
e: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S, F, E> Transform<S> for TransformMapInitErr<T, S, F, E>
|
||||
where
|
||||
T: Transform<S>,
|
||||
F: Fn(T::InitError) -> E + Clone,
|
||||
{
|
||||
type Request = T::Request;
|
||||
type Response = T::Response;
|
||||
type Error = T::Error;
|
||||
type Transform = T::Transform;
|
||||
|
||||
type InitError = E;
|
||||
type Future = TransformMapInitErrFuture<T, S, F, E>;
|
||||
|
||||
fn new_transform(&self, service: S) -> Self::Future {
|
||||
TransformMapInitErrFuture {
|
||||
fut: self.t.new_transform(service),
|
||||
f: self.f.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pin_project_lite::pin_project! {
|
||||
pub struct TransformMapInitErrFuture<T, S, F, E>
|
||||
where
|
||||
T: Transform<S>,
|
||||
F: Fn(T::InitError) -> E,
|
||||
{
|
||||
#[pin]
|
||||
fut: T::Future,
|
||||
f: F,
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S, F, E> Future for TransformMapInitErrFuture<T, S, F, E>
|
||||
where
|
||||
T: Transform<S>,
|
||||
F: Fn(T::InitError) -> E + Clone,
|
||||
{
|
||||
type Output = Result<T::Transform, E>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
if let Poll::Ready(res) = this.fut.poll(cx) {
|
||||
Poll::Ready(res.map_err(this.f))
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue