Skip to main content

ntex_service/
and_then.rs

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