ntex_service/
map.rs

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