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