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> for ApplyFactory<SF, F, Req, In, Res, Err>
144where
145 SF: ServiceFactory<In, Error = Err>,
146 F: Fn(Req, &SF::Service) -> Fut + Clone,
147 Fut: Future<Output = Result<Res, Err>>,
148{
149 type Response = Res;
150 type Error = Err;
151
152 type Config = SF::Config;
153 type Service = Apply<SF::Service, F, Req, In, Res, Err>;
154 type InitError = SF::InitError;
155 type Future = ApplyServiceFactoryResponse<SF, F, Fut, Req, In, Res, Err>;
156
157 fn new_service(&self, cfg: SF::Config) -> Self::Future {
158 let svc = self.factory.new_service(cfg);
159 ApplyServiceFactoryResponse::new(svc, self.wrap_fn.clone())
160 }
161}
162
163pin_project! {
164 pub struct ApplyServiceFactoryResponse<SF, F, Fut, Req, In, Res, Err>
165 where
166 SF: ServiceFactory<In, Error = Err>,
167 F: Fn(Req, &SF::Service) -> Fut,
168 Fut: Future<Output = Result<Res, Err>>,
169 {
170 #[pin]
171 fut: SF::Future,
172 wrap_fn: Option<F>,
173 _phantom: PhantomData<fn(Req) -> Res>,
174 }
175}
176
177impl<SF, F, Fut, Req, In, Res, Err> ApplyServiceFactoryResponse<SF, F, Fut, Req, In, Res, Err>
178where
179 SF: ServiceFactory<In, Error = Err>,
180 F: Fn(Req, &SF::Service) -> Fut,
181 Fut: Future<Output = Result<Res, Err>>,
182{
183 fn new(fut: SF::Future, wrap_fn: F) -> Self {
184 Self {
185 fut,
186 wrap_fn: Some(wrap_fn),
187 _phantom: PhantomData,
188 }
189 }
190}
191
192impl<SF, F, Fut, Req, In, Res, Err> Future
193 for ApplyServiceFactoryResponse<SF, F, Fut, Req, In, Res, Err>
194where
195 SF: ServiceFactory<In, Error = Err>,
196 F: Fn(Req, &SF::Service) -> Fut,
197 Fut: Future<Output = Result<Res, Err>>,
198{
199 type Output = Result<Apply<SF::Service, F, Req, In, Res, Err>, SF::InitError>;
200
201 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
202 let this = self.project();
203
204 let svc = ready!(this.fut.poll(cx))?;
205 Poll::Ready(Ok(Apply::new(svc, this.wrap_fn.take().unwrap())))
206 }
207}
208
209#[cfg(test)]
210mod tests {
211 use futures_util::future::lazy;
212
213 use super::*;
214 use crate::{
215 ok,
216 pipeline::{pipeline, pipeline_factory},
217 Ready,
218 };
219
220 #[derive(Clone)]
221 struct Srv;
222
223 impl Service<()> for Srv {
224 type Response = ();
225 type Error = ();
226 type Future = Ready<Result<(), ()>>;
227
228 crate::always_ready!();
229
230 fn call(&self, _: ()) -> Self::Future {
231 ok(())
232 }
233 }
234
235 #[actix_rt::test]
236 async fn test_call() {
237 let srv = pipeline(apply_fn(Srv, |req: &'static str, srv| {
238 let fut = srv.call(());
239 async move {
240 fut.await.unwrap();
241 Ok((req, ()))
242 }
243 }));
244
245 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
246
247 let res = srv.call("srv").await;
248 assert!(res.is_ok());
249 assert_eq!(res.unwrap(), ("srv", ()));
250 }
251
252 #[actix_rt::test]
253 async fn test_new_service() {
254 let new_srv = pipeline_factory(apply_fn_factory(
255 || ok::<_, ()>(Srv),
256 |req: &'static str, srv| {
257 let fut = srv.call(());
258 async move {
259 fut.await.unwrap();
260 Ok((req, ()))
261 }
262 },
263 ));
264
265 let srv = new_srv.new_service(()).await.unwrap();
266
267 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
268
269 let res = srv.call("srv").await;
270 assert!(res.is_ok());
271 assert_eq!(res.unwrap(), ("srv", ()));
272 }
273}