Skip to main content

ntex_service/
and_then.rs

1use super::{Ctx, Service, ServiceFactory, util};
2
3#[derive(Clone, Debug)]
4/// Service produced by the `and_then` combinator.
5///
6/// This is created by the `Service::and_then()` and `ServiceChain::and_then()` methods.
7pub struct AndThen<A, B> {
8    svc1: A,
9    svc2: B,
10}
11
12impl<A, B> AndThen<A, B> {
13    /// Create new `AndThen` combinator
14    pub(crate) fn new(svc1: A, svc2: B) -> Self {
15        Self { svc1, svc2 }
16    }
17}
18
19impl<A, B, St, Req> Service<St, Req> for AndThen<A, B>
20where
21    A: Service<St, Req>,
22    B: Service<St, A::Res, Error = A::Error>,
23{
24    type Res = B::Res;
25    type Error = A::Error;
26
27    #[inline]
28    async fn call(&self, req: Req, ctx: Ctx<'_, Self, St>) -> Result<B::Res, A::Error> {
29        let result = ctx.call(&self.svc1, req).await?;
30        ctx.call(&self.svc2, result).await
31    }
32
33    #[inline]
34    async fn ready(&self, ctx: Ctx<'_, Self, St>) -> Result<(), Self::Error> {
35        util::ready(&self.svc1, &self.svc2, ctx).await
36    }
37
38    #[inline]
39    async fn shutdown(&self, ctx: Ctx<'_, Self, St>) {
40        util::shutdown(&self.svc1, &self.svc2, ctx).await;
41    }
42}
43
44#[derive(Debug, Clone)]
45/// Service factory produced by the `and_then` combinator.
46pub struct AndThenFactory<A, B> {
47    svc1: A,
48    svc2: B,
49}
50
51impl<A, B> AndThenFactory<A, B> {
52    /// Create new `AndThenFactory` combinator
53    pub fn new(svc1: A, svc2: B) -> Self {
54        Self { svc1, svc2 }
55    }
56}
57
58impl<A, B, St, Req> ServiceFactory<St, Req> for AndThenFactory<A, B>
59where
60    A: ServiceFactory<St, Req>,
61    B: ServiceFactory<St, A::Res, Error = A::Error, InitError = A::InitError>,
62{
63    type Res = B::Res;
64    type Error = A::Error;
65
66    type Service = AndThen<A::Service, B::Service>;
67    type InitError = A::InitError;
68
69    #[inline]
70    async fn create(&self, st: &St) -> Result<Self::Service, Self::InitError> {
71        Ok(AndThen {
72            svc1: self.svc1.create(st).await?,
73            svc2: self.svc2.create(st).await?,
74        })
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use std::{cell::Cell, rc::Rc};
81
82    use crate::{Ctx, Service, factory, fn_factory, service};
83
84    #[derive(Debug, Clone)]
85    struct Srv1(Rc<Cell<usize>>, Rc<Cell<usize>>);
86
87    impl Service<(), &'static str> for Srv1 {
88        type Res = &'static str;
89        type Error = ();
90
91        async fn ready(&self, _: Ctx<'_, Self>) -> Result<(), Self::Error> {
92            self.0.set(self.0.get() + 1);
93            Ok(())
94        }
95
96        async fn call(&self, req: &'static str, _: Ctx<'_, Self>) -> Result<Self::Res, ()> {
97            Ok(req)
98        }
99
100        async fn shutdown(&self, _: Ctx<'_, Self, ()>) {
101            self.1.set(self.1.get() + 1);
102        }
103    }
104
105    #[derive(Debug, Clone)]
106    struct Srv2(Rc<Cell<usize>>, Rc<Cell<usize>>);
107
108    impl Service<(), &'static str> for Srv2 {
109        type Res = (&'static str, &'static str);
110        type Error = ();
111
112        async fn ready(&self, _: Ctx<'_, Self>) -> Result<(), Self::Error> {
113            self.0.set(self.0.get() + 1);
114            Ok(())
115        }
116
117        async fn call(&self, req: &'static str, _: Ctx<'_, Self>) -> Result<Self::Res, ()> {
118            Ok((req, "srv2"))
119        }
120
121        async fn shutdown(&self, _: Ctx<'_, Self, ()>) {
122            self.1.set(self.1.get() + 1);
123        }
124    }
125
126    #[ntex::test]
127    async fn test_ready() {
128        let cnt = Rc::new(Cell::new(0));
129        let cnt_sht = Rc::new(Cell::new(0));
130        let srv = service(Rc::new(Srv1(cnt.clone(), cnt_sht.clone())))
131            .clone()
132            .and_then(crate::boxed::service(Srv2(cnt.clone(), cnt_sht.clone())));
133        assert!(format!("{srv:?}").contains("AndThen"));
134
135        let srv = srv.pipeline(());
136        let res = srv.ready().await;
137        assert_eq!(res, Ok(()));
138        assert_eq!(cnt.get(), 2);
139
140        srv.shutdown().await;
141        assert_eq!(cnt_sht.get(), 2);
142    }
143
144    #[ntex::test]
145    async fn test_ready2() {
146        let cnt = Rc::new(Cell::new(0));
147        let srv = Box::new(
148            service(Srv1(cnt.clone(), Rc::new(Cell::new(0))))
149                .and_then(Srv2(cnt.clone(), Rc::new(Cell::new(0)))),
150        )
151        .pipeline(());
152        let res = srv.ready().await;
153        assert_eq!(res, Ok(()));
154        assert_eq!(cnt.get(), 2);
155    }
156
157    #[ntex::test]
158    async fn test_call() {
159        let cnt = Rc::new(Cell::new(0));
160        let cnt_sht = Rc::new(Cell::new(0));
161        let srv = Srv1(cnt.clone(), cnt_sht.clone())
162            .and_then(Srv2(cnt, cnt_sht.clone()))
163            .pipeline(());
164        let res = srv.call("srv1").await;
165        assert!(res.is_ok());
166        assert_eq!(res.unwrap(), ("srv1", "srv2"));
167
168        srv.shutdown().await;
169        assert_eq!(cnt_sht.get(), 2);
170    }
171
172    #[ntex::test]
173    async fn test_factory() {
174        let cnt = Rc::new(Cell::new(0));
175        let cnt2 = cnt.clone();
176        let new_srv = factory(fn_factory(move |(): &()| {
177            let cnt = cnt2.clone();
178            async move { Ok::<_, ()>(Srv1(cnt, Rc::new(Cell::new(0)))) }
179        }))
180        .and_then(fn_factory(move |(): &()| {
181            let cnt = cnt.clone();
182            async move { Ok(Srv2(cnt.clone(), Rc::new(Cell::new(0)))) }
183        }))
184        .clone();
185
186        let srv = new_srv.pipeline(()).await.unwrap();
187        let res = srv.call("srv1").await;
188        assert!(res.is_ok());
189        assert_eq!(res.unwrap(), ("srv1", "srv2"));
190    }
191}