Skip to content

Commit

Permalink
Add .apply_fn() for chain and chain factory (#220)
Browse files Browse the repository at this point in the history
* Add .apply_fn() for chain and chain factory
  • Loading branch information
fafhrd91 committed Aug 12, 2023
1 parent 594bf0a commit 17ffaf1
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 9 deletions.
6 changes: 6 additions & 0 deletions ntex-service/CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changes

## [1.2.4] - 2023-08-12

* Forward readiness check for Apply service

* Add .apply_fn() for chain and chanin factory

## [1.2.3] - 2023-08-10

* Check readiness for pipeline calls
Expand Down
2 changes: 1 addition & 1 deletion ntex-service/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ntex-service"
version = "1.2.3"
version = "1.2.4"
authors = ["ntex contributors <team@ntex.rs>"]
description = "ntex service"
keywords = ["network", "framework", "async", "futures"]
Expand Down
61 changes: 55 additions & 6 deletions ntex-service/src/apply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,7 @@ where
R: Future<Output = Result<Out, Err>>,
U: IntoService<T, Req>,
{
Apply {
f,
service: Pipeline::new(service.into_service()),
r: marker::PhantomData,
}
Apply::new(service.into_service(), f)
}

/// Service factory that produces `apply_fn` service.
Expand Down Expand Up @@ -60,6 +56,21 @@ impl<S> ApplyService<S> {
}
}

impl<T, Req, F, R, In, Out, Err> Apply<T, Req, F, R, In, Out, Err>
where
T: Service<Req, Error = Err>,
F: Fn(In, ApplyService<T>) -> R,
R: Future<Output = Result<Out, Err>>,
{
pub(crate) fn new(service: T, f: F) -> Self {
Apply {
f,
service: Pipeline::new(service),
r: marker::PhantomData,
}
}
}

impl<T, Req, F, R, In, Out, Err> Clone for Apply<T, Req, F, R, In, Out, Err>
where
T: Service<Req, Error = Err> + Clone,
Expand All @@ -85,6 +96,7 @@ where
type Error = Err;
type Future<'f> = R where Self: 'f, In: 'f, R: 'f;

crate::forward_poll_ready!(service);
crate::forward_poll_shutdown!(service);

#[inline]
Expand Down Expand Up @@ -115,7 +127,7 @@ where
R: Future<Output = Result<Out, Err>>,
{
/// Create new `ApplyNewService` new service instance
fn new(service: T, f: F) -> Self {
pub(crate) fn new(service: T, f: F) -> Self {
Self {
f,
service,
Expand Down Expand Up @@ -246,6 +258,25 @@ mod tests {
assert_eq!(res.unwrap(), ("srv", ()));
}

#[ntex::test]
async fn test_call_chain() {
let srv = chain(Srv)
.apply_fn(|req: &'static str, svc| async move {
svc.call(()).await.unwrap();
Ok((req, ()))
})
.clone()
.pipeline();

assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
let res = lazy(|cx| srv.poll_shutdown(cx)).await;
assert_eq!(res, Poll::Ready(()));

let res = srv.call("srv").await;
assert!(res.is_ok());
assert_eq!(res.unwrap(), ("srv", ()));
}

#[ntex::test]
async fn test_create() {
let new_srv = chain_factory(
Expand All @@ -267,4 +298,22 @@ mod tests {
assert!(res.is_ok());
assert_eq!(res.unwrap(), ("srv", ()));
}

#[ntex::test]
async fn test_create_chain() {
let new_srv = chain_factory(|| Ready::<_, ()>::Ok(Srv))
.apply_fn(|req: &'static str, srv| async move {
srv.call(()).await.unwrap();
Ok((req, ()))
})
.clone();

let srv = new_srv.pipeline(&()).await.unwrap();

assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));

let res = srv.call("srv").await;
assert!(res.is_ok());
assert_eq!(res.unwrap(), ("srv", ()));
}
}
42 changes: 40 additions & 2 deletions ntex-service/src/chain.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::marker::PhantomData;
#![allow(clippy::type_complexity)]
use std::{future::Future, marker::PhantomData};

use crate::and_then::{AndThen, AndThenFactory};
use crate::apply::{Apply, ApplyFactory, ApplyService};
use crate::ctx::{ServiceCall, ServiceCtx};
use crate::map::{Map, MapFactory};
use crate::map_err::{MapErr, MapErrFactory};
Expand Down Expand Up @@ -118,6 +120,24 @@ impl<Svc: Service<Req>, Req> ServiceChain<Svc, Req> {
}
}

/// Use function as middleware for current service.
///
/// Short version of `apply_fn(chain(...), fn)`
pub fn apply_fn<F, R, In, Out, Err>(
self,
f: F,
) -> ServiceChain<Apply<Svc, Req, F, R, In, Out, Err>, In>
where
F: Fn(In, ApplyService<Svc>) -> R,
R: Future<Output = Result<Out, Err>>,
Svc: Service<Req, Error = Err>,
{
ServiceChain {
service: Apply::new(self.service, f),
_t: PhantomData,
}
}

/// Create service pipeline
pub fn pipeline(self) -> Pipeline<Svc> {
Pipeline::new(self.service)
Expand Down Expand Up @@ -175,7 +195,7 @@ impl<T: ServiceFactory<Req, C>, Req, C> ServiceChainFactory<T, Req, C> {

/// Apply middleware to current service factory.
///
/// Short version of `apply(middleware, pipeline_factory(...))`
/// Short version of `apply(middleware, chain_factory(...))`
pub fn apply<U>(self, tr: U) -> ServiceChainFactory<ApplyMiddleware<U, T, C>, Req, C>
where
U: Middleware<T::Service>,
Expand All @@ -186,6 +206,24 @@ impl<T: ServiceFactory<Req, C>, Req, C> ServiceChainFactory<T, Req, C> {
}
}

/// Apply function middleware to current service factory.
///
/// Short version of `apply_fn_factory(chain_factory(...), fn)`
pub fn apply_fn<F, R, In, Out, Err>(
self,
f: F,
) -> ServiceChainFactory<ApplyFactory<T, Req, C, F, R, In, Out, Err>, In, C>
where
F: Fn(In, ApplyService<T::Service>) -> R + Clone,
R: Future<Output = Result<Out, Err>>,
T: ServiceFactory<Req, C, Error = Err>,
{
ServiceChainFactory {
factory: ApplyFactory::new(self.factory, f),
_t: PhantomData,
}
}

/// 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`.
Expand Down

0 comments on commit 17ffaf1

Please sign in to comment.