use super::{Ctx, Service, ServiceFactory, util};
#[derive(Debug, Clone)]
pub struct Then<A, B> {
svc1: A,
svc2: B,
}
impl<A, B> Then<A, B> {
pub(crate) fn new(svc1: A, svc2: B) -> Then<A, B> {
Self { svc1, svc2 }
}
}
impl<A, B, St, Req> Service<St, Req> for Then<A, B>
where
A: Service<St, Req>,
B: Service<St, Result<A::Res, A::Error>, Error = A::Error>,
{
type Res = B::Res;
type Error = B::Error;
#[inline]
async fn call(&self, req: Req, ctx: Ctx<'_, Self, St>) -> Result<B::Res, B::Error> {
ctx.call(&self.svc2, ctx.call(&self.svc1, req).await).await
}
#[inline]
async fn ready(&self, ctx: Ctx<'_, Self, St>) -> Result<(), Self::Error> {
util::ready(&self.svc1, &self.svc2, ctx).await
}
#[inline]
async fn shutdown(&self, ctx: Ctx<'_, Self, St>) {
util::shutdown(&self.svc1, &self.svc2, ctx).await;
}
}
#[derive(Debug, Clone)]
pub struct ThenFactory<A, B> {
svc1: A,
svc2: B,
}
impl<A, B> ThenFactory<A, B> {
pub(crate) fn new(svc1: A, svc2: B) -> Self {
Self { svc1, svc2 }
}
}
impl<A, B, St, Req> ServiceFactory<St, Req> for ThenFactory<A, B>
where
A: ServiceFactory<St, Req>,
B: ServiceFactory<St, Result<A::Res, A::Error>, Error = A::Error, InitError = A::InitError>,
{
type Res = B::Res;
type Error = A::Error;
type Service = Then<A::Service, B::Service>;
type InitError = A::InitError;
async fn create(&self, st: &St) -> Result<Self::Service, Self::InitError> {
Ok(Then {
svc1: self.svc1.create(st).await?,
svc2: self.svc2.create(st).await?,
})
}
}
#[cfg(test)]
mod tests {
use std::{cell::Cell, rc::Rc};
use crate::{Ctx, Service, factory, fn_factory, service};
#[derive(Clone)]
struct Srv1(Rc<Cell<usize>>, Rc<Cell<usize>>);
impl Service<(), Result<&'static str, &'static str>> for Srv1 {
type Res = &'static str;
type Error = ();
async fn ready(&self, _: Ctx<'_, Self>) -> Result<(), Self::Error> {
self.0.set(self.0.get() + 1);
Ok(())
}
async fn call(
&self,
req: Result<&'static str, &'static str>,
_: Ctx<'_, Self>,
) -> Result<&'static str, ()> {
match req {
Ok(msg) => Ok(msg),
Err(_) => Err(()),
}
}
async fn shutdown(&self, _: Ctx<'_, Self, ()>) {
self.1.set(self.1.get() + 1);
}
}
#[derive(Clone)]
struct Srv2(Rc<Cell<usize>>, Rc<Cell<usize>>);
impl Service<(), Result<&'static str, ()>> for Srv2 {
type Res = (&'static str, &'static str);
type Error = ();
async fn ready(&self, _: Ctx<'_, Self>) -> Result<(), Self::Error> {
self.0.set(self.0.get() + 1);
Ok(())
}
async fn call(
&self,
req: Result<&'static str, ()>,
_: Ctx<'_, Self>,
) -> Result<Self::Res, ()> {
match req {
Ok(msg) => Ok((msg, "ok")),
Err(()) => Ok(("srv2", "err")),
}
}
async fn shutdown(&self, _: Ctx<'_, Self, ()>) {
self.1.set(self.1.get() + 1);
}
}
#[ntex::test]
async fn test_ready() {
let cnt = Rc::new(Cell::new(0));
let cnt_sht = Rc::new(Cell::new(0));
let srv = service(Srv1(cnt.clone(), cnt_sht.clone()))
.then(Srv2(cnt.clone(), cnt_sht.clone()))
.pipeline(());
let res = srv.ready().await;
assert_eq!(res, Ok(()));
assert_eq!(cnt.get(), 2);
srv.shutdown().await;
assert_eq!(cnt_sht.get(), 2);
}
#[ntex::test]
async fn test_call() {
let cnt = Rc::new(Cell::new(0));
let srv = service(Srv1(cnt.clone(), Rc::new(Cell::new(0))))
.then(Srv2(cnt, Rc::new(Cell::new(0))))
.clone()
.pipeline(());
let res = srv.call(Ok("srv1")).await;
assert!(res.is_ok());
assert_eq!(res.unwrap(), ("srv1", "ok"));
let res = srv.call(Err("srv")).await;
assert!(res.is_ok());
assert_eq!(res.unwrap(), ("srv2", "err"));
}
#[ntex::test]
async fn test_factory() {
let cnt = Rc::new(Cell::new(0));
let cnt2 = cnt.clone();
let blank = fn_factory(move |(): &_| {
let cnt = cnt2.clone();
async move { Ok::<_, ()>(Srv1(cnt, Rc::new(Cell::new(0)))) }
});
let factory = factory(blank)
.then(fn_factory(move |(): &()| {
let cnt = cnt.clone();
async move { Ok(Srv2(cnt.clone(), Rc::new(Cell::new(0)))) }
}))
.clone();
let srv = factory.pipeline(()).await.unwrap();
let res = srv.call(Ok("srv1")).await;
assert!(res.is_ok());
assert_eq!(res.unwrap(), ("srv1", "ok"));
let res = srv.call(Err("srv")).await;
assert!(res.is_ok());
assert_eq!(res.unwrap(), ("srv2", "err"));
}
}