1use core::{
2 future::Future,
3 marker::PhantomData,
4 pin::Pin,
5 task::{Context, Poll},
6};
7
8use pin_project_lite::pin_project;
9
10use super::{Service, ServiceFactory};
11
12pub struct Map<A, F, Req, Res> {
16 service: A,
17 f: F,
18 _t: PhantomData<fn(Req) -> Res>,
19}
20
21impl<A, F, Req, Res> Map<A, F, Req, Res> {
22 pub(crate) fn new(service: A, f: F) -> Self
24 where
25 A: Service<Req>,
26 F: FnMut(A::Response) -> Res,
27 {
28 Self {
29 service,
30 f,
31 _t: PhantomData,
32 }
33 }
34}
35
36impl<A, F, Req, Res> Clone for Map<A, F, Req, Res>
37where
38 A: Clone,
39 F: Clone,
40{
41 fn clone(&self) -> Self {
42 Map {
43 service: self.service.clone(),
44 f: self.f.clone(),
45 _t: PhantomData,
46 }
47 }
48}
49
50impl<A, F, Req, Res> Service<Req> for Map<A, F, Req, Res>
51where
52 A: Service<Req>,
53 F: FnMut(A::Response) -> Res + Clone,
54{
55 type Response = Res;
56 type Error = A::Error;
57 type Future = MapFuture<A, F, Req, Res>;
58
59 crate::forward_ready!(service);
60
61 fn call(&self, req: Req) -> Self::Future {
62 MapFuture::new(self.service.call(req), self.f.clone())
63 }
64}
65
66pin_project! {
67 pub struct MapFuture<A, F, Req, Res>
68 where
69 A: Service<Req>,
70 F: FnMut(A::Response) -> Res,
71 {
72 f: F,
73 #[pin]
74 fut: A::Future,
75 }
76}
77
78impl<A, F, Req, Res> MapFuture<A, F, Req, Res>
79where
80 A: Service<Req>,
81 F: FnMut(A::Response) -> Res,
82{
83 fn new(fut: A::Future, f: F) -> Self {
84 MapFuture { f, fut }
85 }
86}
87
88impl<A, F, Req, Res> Future for MapFuture<A, F, Req, Res>
89where
90 A: Service<Req>,
91 F: FnMut(A::Response) -> Res,
92{
93 type Output = Result<Res, A::Error>;
94
95 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
96 let this = self.project();
97
98 match this.fut.poll(cx) {
99 Poll::Ready(Ok(resp)) => Poll::Ready(Ok((this.f)(resp))),
100 Poll::Ready(Err(err)) => Poll::Ready(Err(err)),
101 Poll::Pending => Poll::Pending,
102 }
103 }
104}
105
106pub struct MapServiceFactory<A, F, Req, Res> {
108 a: A,
109 f: F,
110 r: PhantomData<fn(Req) -> Res>,
111}
112
113impl<A, F, Req, Res> MapServiceFactory<A, F, Req, Res> {
114 pub(crate) fn new(a: A, f: F) -> Self
116 where
117 A: ServiceFactory<Req>,
118 F: FnMut(A::Response) -> Res,
119 {
120 Self {
121 a,
122 f,
123 r: PhantomData,
124 }
125 }
126}
127
128impl<A, F, Req, Res> Clone for MapServiceFactory<A, F, Req, Res>
129where
130 A: Clone,
131 F: Clone,
132{
133 fn clone(&self) -> Self {
134 Self {
135 a: self.a.clone(),
136 f: self.f.clone(),
137 r: PhantomData,
138 }
139 }
140}
141
142impl<A, F, Req, Res> ServiceFactory<Req> for MapServiceFactory<A, F, Req, Res>
143where
144 A: ServiceFactory<Req>,
145 F: FnMut(A::Response) -> Res + Clone,
146{
147 type Response = Res;
148 type Error = A::Error;
149
150 type Config = A::Config;
151 type Service = Map<A::Service, F, Req, Res>;
152 type InitError = A::InitError;
153 type Future = MapServiceFuture<A, F, Req, Res>;
154
155 fn new_service(&self, cfg: A::Config) -> Self::Future {
156 MapServiceFuture::new(self.a.new_service(cfg), self.f.clone())
157 }
158}
159
160pin_project! {
161 pub struct MapServiceFuture<A, F, Req, Res>
162 where
163 A: ServiceFactory<Req>,
164 F: FnMut(A::Response) -> Res,
165 {
166 #[pin]
167 fut: A::Future,
168 f: Option<F>,
169 }
170}
171
172impl<A, F, Req, Res> MapServiceFuture<A, F, Req, Res>
173where
174 A: ServiceFactory<Req>,
175 F: FnMut(A::Response) -> Res,
176{
177 fn new(fut: A::Future, f: F) -> Self {
178 MapServiceFuture { f: Some(f), fut }
179 }
180}
181
182impl<A, F, Req, Res> Future for MapServiceFuture<A, F, Req, Res>
183where
184 A: ServiceFactory<Req>,
185 F: FnMut(A::Response) -> Res,
186{
187 type Output = Result<Map<A::Service, F, Req, Res>, A::InitError>;
188
189 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
190 let this = self.project();
191
192 if let Poll::Ready(svc) = this.fut.poll(cx)? {
193 Poll::Ready(Ok(Map::new(svc, this.f.take().unwrap())))
194 } else {
195 Poll::Pending
196 }
197 }
198}
199
200#[cfg(test)]
201mod tests {
202 use futures_util::future::lazy;
203
204 use super::*;
205 use crate::{ok, IntoServiceFactory, Ready, ServiceExt, ServiceFactoryExt};
206
207 struct Srv;
208
209 impl Service<()> for Srv {
210 type Response = ();
211 type Error = ();
212 type Future = Ready<Result<(), ()>>;
213
214 crate::always_ready!();
215
216 fn call(&self, _: ()) -> Self::Future {
217 ok(())
218 }
219 }
220
221 #[actix_rt::test]
222 async fn test_poll_ready() {
223 let srv = Srv.map(|_| "ok");
224 let res = lazy(|cx| srv.poll_ready(cx)).await;
225 assert_eq!(res, Poll::Ready(Ok(())));
226 }
227
228 #[actix_rt::test]
229 async fn test_call() {
230 let srv = Srv.map(|_| "ok");
231 let res = srv.call(()).await;
232 assert!(res.is_ok());
233 assert_eq!(res.unwrap(), "ok");
234 }
235
236 #[actix_rt::test]
237 async fn test_new_service() {
238 let new_srv = (|| ok::<_, ()>(Srv)).into_factory().map(|_| "ok");
239 let srv = new_srv.new_service(&()).await.unwrap();
240 let res = srv.call(()).await;
241 assert!(res.is_ok());
242 assert_eq!(res.unwrap(), ("ok"));
243 }
244}