1use core::{
2 future::Future,
3 marker::PhantomData,
4 pin::Pin,
5 task::{Context, Poll},
6};
7
8use futures_core::ready;
9use pin_project_lite::pin_project;
10
11use super::{IntoService, IntoServiceFactory, Service, ServiceFactory};
12
13pub fn apply_fn<I, S, F, Fut, Req, In, Res, Err>(
17 service: I,
18 wrap_fn: F,
19) -> Apply<S, F, Req, In, Res, Err>
20where
21 I: IntoService<S, In>,
22 S: Service<In, Error = Err>,
23 F: Fn(Req, &S) -> Fut,
24 Fut: Future<Output = Result<Res, Err>>,
25{
26 Apply::new(service.into_service(), wrap_fn)
27}
28
29pub fn apply_fn_factory<I, SF, F, Fut, Req, In, Res, Err>(
33 service: I,
34 f: F,
35) -> ApplyFactory<SF, F, Req, In, Res, Err>
36where
37 I: IntoServiceFactory<SF, In>,
38 SF: ServiceFactory<In, Error = Err>,
39 F: Fn(Req, &SF::Service) -> Fut + Clone,
40 Fut: Future<Output = Result<Res, Err>>,
41{
42 ApplyFactory::new(service.into_factory(), f)
43}
44
45pub struct Apply<S, F, Req, In, Res, Err>
49where
50 S: Service<In, Error = Err>,
51{
52 service: S,
53 wrap_fn: F,
54 _phantom: PhantomData<fn(Req) -> (In, Res, Err)>,
55}
56
57impl<S, F, Fut, Req, In, Res, Err> Apply<S, F, Req, In, Res, Err>
58where
59 S: Service<In, Error = Err>,
60 F: Fn(Req, &S) -> Fut,
61 Fut: Future<Output = Result<Res, Err>>,
62{
63 fn new(service: S, wrap_fn: F) -> Self {
65 Self {
66 service,
67 wrap_fn,
68 _phantom: PhantomData,
69 }
70 }
71}
72
73impl<S, F, Fut, Req, In, Res, Err> Clone for Apply<S, F, Req, In, Res, Err>
74where
75 S: Service<In, Error = Err> + Clone,
76 F: Fn(Req, &S) -> Fut + Clone,
77 Fut: Future<Output = Result<Res, Err>>,
78{
79 fn clone(&self) -> Self {
80 Apply {
81 service: self.service.clone(),
82 wrap_fn: self.wrap_fn.clone(),
83 _phantom: PhantomData,
84 }
85 }
86}
87
88impl<S, F, Fut, Req, In, Res, Err> Service<Req> for Apply<S, F, Req, In, Res, Err>
89where
90 S: Service<In, Error = Err>,
91 F: Fn(Req, &S) -> Fut,
92 Fut: Future<Output = Result<Res, Err>>,
93{
94 type Response = Res;
95 type Error = Err;
96 type Future = Fut;
97
98 crate::forward_ready!(service);
99
100 fn call(&self, req: Req) -> Self::Future {
101 (self.wrap_fn)(req, &self.service)
102 }
103}
104
105pub struct ApplyFactory<SF, F, Req, In, Res, Err> {
107 factory: SF,
108 wrap_fn: F,
109 _phantom: PhantomData<fn(Req) -> (In, Res, Err)>,
110}
111
112impl<SF, F, Fut, Req, In, Res, Err> ApplyFactory<SF, F, Req, In, Res, Err>
113where
114 SF: ServiceFactory<In, Error = Err>,
115 F: Fn(Req, &SF::Service) -> Fut + Clone,
116 Fut: Future<Output = Result<Res, Err>>,
117{
118 fn new(factory: SF, wrap_fn: F) -> Self {
120 Self {
121 factory,
122 wrap_fn,
123 _phantom: PhantomData,
124 }
125 }
126}
127
128impl<SF, F, Fut, Req, In, Res, Err> Clone for ApplyFactory<SF, F, Req, In, Res, Err>
129where
130 SF: ServiceFactory<In, Error = Err> + Clone,
131 F: Fn(Req, &SF::Service) -> Fut + Clone,
132 Fut: Future<Output = Result<Res, Err>>,
133{
134 fn clone(&self) -> Self {
135 Self {
136 factory: self.factory.clone(),
137 wrap_fn: self.wrap_fn.clone(),
138 _phantom: PhantomData,
139 }
140 }
141}
142
143impl<SF, F, Fut, Req, In, Res, Err> ServiceFactory<Req>
144 for ApplyFactory<SF, F, Req, In, Res, Err>
145where
146 SF: ServiceFactory<In, Error = Err>,
147 F: Fn(Req, &SF::Service) -> Fut + Clone,
148 Fut: Future<Output = Result<Res, Err>>,
149{
150 type Response = Res;
151 type Error = Err;
152
153 type Config = SF::Config;
154 type Service = Apply<SF::Service, F, Req, In, Res, Err>;
155 type InitError = SF::InitError;
156 type Future = ApplyServiceFactoryResponse<SF, F, Fut, Req, In, Res, Err>;
157
158 fn new_service(&self, cfg: SF::Config) -> Self::Future {
159 let svc = self.factory.new_service(cfg);
160 ApplyServiceFactoryResponse::new(svc, self.wrap_fn.clone())
161 }
162}
163
164pin_project! {
165 pub struct ApplyServiceFactoryResponse<SF, F, Fut, Req, In, Res, Err>
166 where
167 SF: ServiceFactory<In, Error = Err>,
168 F: Fn(Req, &SF::Service) -> Fut,
169 Fut: Future<Output = Result<Res, Err>>,
170 {
171 #[pin]
172 fut: SF::Future,
173 wrap_fn: Option<F>,
174 _phantom: PhantomData<fn(Req) -> Res>,
175 }
176}
177
178impl<SF, F, Fut, Req, In, Res, Err> ApplyServiceFactoryResponse<SF, F, Fut, Req, In, Res, Err>
179where
180 SF: ServiceFactory<In, Error = Err>,
181 F: Fn(Req, &SF::Service) -> Fut,
182 Fut: Future<Output = Result<Res, Err>>,
183{
184 fn new(fut: SF::Future, wrap_fn: F) -> Self {
185 Self {
186 fut,
187 wrap_fn: Some(wrap_fn),
188 _phantom: PhantomData,
189 }
190 }
191}
192
193impl<SF, F, Fut, Req, In, Res, Err> Future
194 for ApplyServiceFactoryResponse<SF, F, Fut, Req, In, Res, Err>
195where
196 SF: ServiceFactory<In, Error = Err>,
197 F: Fn(Req, &SF::Service) -> Fut,
198 Fut: Future<Output = Result<Res, Err>>,
199{
200 type Output = Result<Apply<SF::Service, F, Req, In, Res, Err>, SF::InitError>;
201
202 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
203 let this = self.project();
204
205 let svc = ready!(this.fut.poll(cx))?;
206 Poll::Ready(Ok(Apply::new(svc, this.wrap_fn.take().unwrap())))
207 }
208}
209
210#[cfg(test)]
211mod tests {
212 use core::task::Poll;
213
214 use futures_util::future::lazy;
215
216 use super::*;
217 use crate::{
218 ok,
219 pipeline::{pipeline, pipeline_factory},
220 Ready, Service, ServiceFactory,
221 };
222
223 #[derive(Clone)]
224 struct Srv;
225
226 impl Service<()> for Srv {
227 type Response = ();
228 type Error = ();
229 type Future = Ready<Result<(), ()>>;
230
231 crate::always_ready!();
232
233 fn call(&self, _: ()) -> Self::Future {
234 ok(())
235 }
236 }
237
238 #[actix_rt::test]
239 async fn test_call() {
240 let srv = pipeline(apply_fn(Srv, |req: &'static str, srv| {
241 let fut = srv.call(());
242 async move {
243 fut.await.unwrap();
244 Ok((req, ()))
245 }
246 }));
247
248 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
249
250 let res = srv.call("srv").await;
251 assert!(res.is_ok());
252 assert_eq!(res.unwrap(), ("srv", ()));
253 }
254
255 #[actix_rt::test]
256 async fn test_new_service() {
257 let new_srv = pipeline_factory(apply_fn_factory(
258 || ok::<_, ()>(Srv),
259 |req: &'static str, srv| {
260 let fut = srv.call(());
261 async move {
262 fut.await.unwrap();
263 Ok((req, ()))
264 }
265 },
266 ));
267
268 let srv = new_srv.new_service(()).await.unwrap();
269
270 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
271
272 let res = srv.call("srv").await;
273 assert!(res.is_ok());
274 assert_eq!(res.unwrap(), ("srv", ()));
275 }
276}