Skip to main content

ntex_service/
map.rs

1use std::{fmt, marker::PhantomData};
2
3use super::{Ctx, Service, ServiceFactory};
4
5/// Service produced by the `map` combinator.
6///
7/// This is created by the `Service::map()` and `ServiceChain::map()` methods.
8pub struct Map<F, S, Res> {
9    f: F,
10    svc: S,
11    _t: PhantomData<fn() -> Res>,
12}
13
14impl<F, S, Res> Map<F, S, Res> {
15    /// Creates a new `Map` service.
16    pub(crate) fn new<St, Req>(f: F, svc: S) -> Self
17    where
18        F: Fn(S::Res) -> Res,
19        S: Service<St, Req>,
20    {
21        Self {
22            f,
23            svc,
24            _t: PhantomData,
25        }
26    }
27}
28
29impl<F, S, Res> Clone for Map<F, S, Res>
30where
31    F: Clone,
32    S: Clone,
33{
34    #[inline]
35    fn clone(&self) -> Self {
36        Map {
37            f: self.f.clone(),
38            svc: self.svc.clone(),
39            _t: PhantomData,
40        }
41    }
42}
43
44impl<F, S, Res> fmt::Debug for Map<F, S, Res>
45where
46    S: fmt::Debug,
47{
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        f.debug_struct("Map")
50            .field("svc", &self.svc)
51            .field("map", &std::any::type_name::<F>())
52            .finish()
53    }
54}
55
56impl<F, S, St, Req, Res> Service<St, Req> for Map<F, S, Res>
57where
58    S: Service<St, Req>,
59    F: Fn(S::Res) -> Res,
60{
61    type Res = Res;
62    type Error = S::Error;
63
64    #[inline]
65    async fn call(&self, req: Req, ctx: Ctx<'_, Self, St>) -> Result<Res, S::Error> {
66        ctx.call_nowait(&self.svc, req).await.map(|r| (self.f)(r))
67    }
68
69    crate::forward_ready!(St, svc);
70    crate::forward_shutdown!(St, svc);
71}
72
73/// Service factory produced by the `map` combinator.
74///
75/// This is created by the `ServiceChainFactory::map()` method.
76pub struct MapFactory<F, Sf, Res> {
77    f: F,
78    sf: Sf,
79    r: PhantomData<fn() -> Res>,
80}
81
82impl<F, Sf, Res> MapFactory<F, Sf, Res> {
83    /// Creates a new `MapFactory`.
84    pub(crate) fn new<St, Req>(f: F, sf: Sf) -> Self
85    where
86        F: Fn(Sf::Res) -> Res,
87        Sf: ServiceFactory<St, Req>,
88    {
89        Self {
90            f,
91            sf,
92            r: PhantomData,
93        }
94    }
95}
96
97impl<F, Sf, Res> Clone for MapFactory<F, Sf, Res>
98where
99    F: Clone,
100    Sf: Clone,
101{
102    #[inline]
103    fn clone(&self) -> Self {
104        Self {
105            sf: self.sf.clone(),
106            f: self.f.clone(),
107            r: PhantomData,
108        }
109    }
110}
111
112impl<F, Sf, Res> fmt::Debug for MapFactory<F, Sf, Res>
113where
114    Sf: fmt::Debug,
115{
116    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117        f.debug_struct("MapFactory")
118            .field("factory", &self.sf)
119            .field("map", &std::any::type_name::<F>())
120            .finish()
121    }
122}
123
124impl<F, Sf, St, Req, Res> ServiceFactory<St, Req> for MapFactory<F, Sf, Res>
125where
126    F: Fn(Sf::Res) -> Res + Clone,
127    Sf: ServiceFactory<St, Req>,
128{
129    type Res = Res;
130    type Error = Sf::Error;
131
132    type Service = Map<F, Sf::Service, Res>;
133    type InitError = Sf::InitError;
134
135    #[inline]
136    async fn create(&self, st: &St) -> Result<Self::Service, Self::InitError> {
137        Ok(Map {
138            svc: self.sf.create(st).await?,
139            f: self.f.clone(),
140            _t: PhantomData,
141        })
142    }
143}
144
145#[cfg(test)]
146mod tests {
147    use std::{cell::Cell, rc::Rc};
148
149    use crate::{Ctx, Pipeline, Service, ServiceFactory, fn_factory, service};
150
151    #[derive(Debug, Default, Clone)]
152    struct Srv(Rc<Cell<usize>>);
153
154    impl Service<(), ()> for Srv {
155        type Res = ();
156        type Error = ();
157
158        async fn ready(&self, _: Ctx<'_, Self>) -> Result<(), Self::Error> {
159            Ok(())
160        }
161
162        async fn call(&self, _r: (), _: Ctx<'_, Self>) -> Result<(), ()> {
163            Ok(())
164        }
165
166        async fn shutdown(&self, _: Ctx<'_, Self, ()>) {
167            self.0.set(self.0.get() + 1);
168        }
169    }
170
171    #[ntex::test]
172    async fn test_service() {
173        let cnt_sht = Rc::new(Cell::new(0));
174        let srv = Pipeline::new((), service(Srv(cnt_sht.clone())).map(|()| "ok").clone());
175        let res = srv.call(()).await;
176        assert!(res.is_ok());
177        assert_eq!(res.unwrap(), "ok");
178
179        let res = srv.ready().await;
180        assert_eq!(res, Ok(()));
181
182        srv.shutdown().await;
183        assert_eq!(cnt_sht.get(), 1);
184        let _ = format!("{srv:?}");
185
186        let cnt_sht = Rc::new(Cell::new(0));
187        let svc = Srv(cnt_sht.clone()).map(|()| "ok");
188        let srv = Pipeline::new((), svc);
189        let res = srv.call(()).await;
190        assert!(res.is_ok());
191        assert_eq!(res.unwrap(), "ok");
192
193        let res = srv.ready().await;
194        assert_eq!(res, Ok(()));
195
196        srv.shutdown().await;
197        assert_eq!(cnt_sht.get(), 1);
198        let _ = format!("{srv:?}");
199    }
200
201    #[ntex::test]
202    async fn test_pipeline() {
203        let srv = Pipeline::new((), crate::service(Srv::default()).map(|()| "ok").clone());
204        let res = srv.call(()).await;
205        assert!(res.is_ok());
206        assert_eq!(res.unwrap(), "ok");
207
208        let res = srv.ready().await;
209        assert_eq!(res, Ok(()));
210    }
211
212    #[ntex::test]
213    async fn test_factory() {
214        let new_srv = fn_factory(|(): &()| async { Ok::<_, ()>(Srv::default()) })
215            .map(|()| "ok")
216            .clone();
217        let srv = Pipeline::new((), new_srv.create(&()).await.unwrap());
218        let res = srv.call(()).await;
219        assert!(res.is_ok());
220        assert_eq!(res.unwrap(), ("ok"));
221
222        let _ = format!("{new_srv:?}");
223    }
224
225    #[ntex::test]
226    async fn test_pipeline_factory() {
227        let new_srv = crate::fn_factory(|(): &()| async { Ok::<_, ()>(Srv::default()) })
228            .map(|()| "ok")
229            .clone();
230        let srv = Pipeline::new((), new_srv.create(&()).await.unwrap());
231        let res = srv.call(()).await;
232        assert!(res.is_ok());
233        assert_eq!(res.unwrap(), ("ok"));
234
235        let _ = format!("{new_srv:?}");
236    }
237}