Skip to main content

ntex_service/
then.rs

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