Skip to main content

ntex_service/
then.rs

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