1use std::{fmt, marker::PhantomData};
2
3use super::{Service, ServiceCtx, ServiceFactory};
4
5pub 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 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
78pub 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 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}