1use std::{fmt, future::Future, marker::PhantomData};
2
3use crate::{IntoService, IntoServiceFactory, Service, ServiceCtx, ServiceFactory};
4
5#[inline]
6pub fn fn_service<F, Fut, Req, Res, Err, Cfg>(
8 f: F,
9) -> FnServiceFactory<F, Fut, Req, Res, Err, Cfg>
10where
11 F: Fn(Req) -> Fut + Clone,
12 Fut: Future<Output = Result<Res, Err>>,
13{
14 FnServiceFactory::new(f)
15}
16
17#[inline]
18pub fn fn_factory<F, Srv, Fut, Req, Err>(f: F) -> FnServiceNoConfig<F, Srv, Fut, Req, Err>
54where
55 F: Fn() -> Fut,
56 Srv: Service<Req>,
57 Fut: Future<Output = Result<Srv, Err>>,
58{
59 FnServiceNoConfig::new(f)
60}
61
62#[inline]
63pub fn fn_factory_with_config<F, Fut, Cfg, Srv, Req, Err>(
94 f: F,
95) -> FnServiceConfig<F, Fut, Cfg, Srv, Req, Err>
96where
97 F: Fn(Cfg) -> Fut,
98 Fut: Future<Output = Result<Srv, Err>>,
99 Srv: Service<Req>,
100{
101 FnServiceConfig { f, _t: PhantomData }
102}
103
104pub struct FnService<F, Req> {
105 f: F,
106 _t: PhantomData<Req>,
107}
108
109impl<F, Req> Clone for FnService<F, Req>
110where
111 F: Clone,
112{
113 fn clone(&self) -> Self {
114 Self {
115 f: self.f.clone(),
116 _t: PhantomData,
117 }
118 }
119}
120
121impl<F, Req> fmt::Debug for FnService<F, Req> {
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 f.debug_struct("FnService")
124 .field("f", &std::any::type_name::<F>())
125 .finish()
126 }
127}
128
129impl<F, Fut, Req, Res, Err> Service<Req> for FnService<F, Req>
130where
131 F: Fn(Req) -> Fut,
132 Fut: Future<Output = Result<Res, Err>>,
133{
134 type Response = Res;
135 type Error = Err;
136
137 #[inline]
138 async fn call(&self, req: Req, _: ServiceCtx<'_, Self>) -> Result<Res, Err> {
139 (self.f)(req).await
140 }
141}
142
143impl<F, Fut, Req, Res, Err> IntoService<FnService<F, Req>, Req> for F
144where
145 F: Fn(Req) -> Fut,
146 Fut: Future<Output = Result<Res, Err>>,
147{
148 #[inline]
149 fn into_service(self) -> FnService<F, Req> {
150 FnService {
151 f: self,
152 _t: PhantomData,
153 }
154 }
155}
156
157pub struct FnServiceFactory<F, Fut, Req, Res, Err, Cfg>
158where
159 F: Fn(Req) -> Fut,
160 Fut: Future<Output = Result<Res, Err>>,
161{
162 f: F,
163 _t: PhantomData<(Req, Cfg)>,
164}
165
166impl<F, Fut, Req, Res, Err, Cfg> FnServiceFactory<F, Fut, Req, Res, Err, Cfg>
167where
168 F: Fn(Req) -> Fut + Clone,
169 Fut: Future<Output = Result<Res, Err>>,
170{
171 fn new(f: F) -> Self {
172 FnServiceFactory { f, _t: PhantomData }
173 }
174}
175
176impl<F, Fut, Req, Res, Err, Cfg> Clone for FnServiceFactory<F, Fut, Req, Res, Err, Cfg>
177where
178 F: Fn(Req) -> Fut + Clone,
179 Fut: Future<Output = Result<Res, Err>>,
180{
181 #[inline]
182 fn clone(&self) -> Self {
183 Self {
184 f: self.f.clone(),
185 _t: PhantomData,
186 }
187 }
188}
189
190impl<F, Fut, Req, Res, Err, Cfg> fmt::Debug for FnServiceFactory<F, Fut, Req, Res, Err, Cfg>
191where
192 F: Fn(Req) -> Fut,
193 Fut: Future<Output = Result<Res, Err>>,
194{
195 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196 f.debug_struct("FnServiceFactory")
197 .field("f", &std::any::type_name::<F>())
198 .finish()
199 }
200}
201
202impl<F, Fut, Req, Res, Err> Service<Req> for FnServiceFactory<F, Fut, Req, Res, Err, ()>
203where
204 F: Fn(Req) -> Fut,
205 Fut: Future<Output = Result<Res, Err>>,
206{
207 type Response = Res;
208 type Error = Err;
209
210 #[inline]
211 async fn call(&self, req: Req, _: ServiceCtx<'_, Self>) -> Result<Res, Err> {
212 (self.f)(req).await
213 }
214}
215
216impl<F, Fut, Req, Res, Err, Cfg> ServiceFactory<Req, Cfg>
217 for FnServiceFactory<F, Fut, Req, Res, Err, Cfg>
218where
219 F: Fn(Req) -> Fut + Clone,
220 Fut: Future<Output = Result<Res, Err>>,
221{
222 type Response = Res;
223 type Error = Err;
224
225 type Service = FnService<F, Req>;
226 type InitError = ();
227
228 #[inline]
229 async fn create(&self, _: Cfg) -> Result<Self::Service, Self::InitError> {
230 Ok(FnService {
231 f: self.f.clone(),
232 _t: PhantomData,
233 })
234 }
235}
236
237impl<F, Fut, Req, Res, Err, Cfg>
238 IntoServiceFactory<FnServiceFactory<F, Fut, Req, Res, Err, Cfg>, Req, Cfg> for F
239where
240 F: Fn(Req) -> Fut + Clone,
241 Fut: Future<Output = Result<Res, Err>>,
242{
243 #[inline]
244 fn into_factory(self) -> FnServiceFactory<F, Fut, Req, Res, Err, Cfg> {
245 FnServiceFactory::new(self)
246 }
247}
248
249pub struct FnServiceConfig<F, Fut, Cfg, Srv, Req, Err>
251where
252 F: Fn(Cfg) -> Fut,
253 Fut: Future<Output = Result<Srv, Err>>,
254 Srv: Service<Req>,
255{
256 f: F,
257 _t: PhantomData<(Fut, Cfg, Srv, Req, Err)>,
258}
259
260impl<F, Fut, Cfg, Srv, Req, Err> Clone for FnServiceConfig<F, Fut, Cfg, Srv, Req, Err>
261where
262 F: Fn(Cfg) -> Fut + Clone,
263 Fut: Future<Output = Result<Srv, Err>>,
264 Srv: Service<Req>,
265{
266 #[inline]
267 fn clone(&self) -> Self {
268 FnServiceConfig {
269 f: self.f.clone(),
270 _t: PhantomData,
271 }
272 }
273}
274
275impl<F, Fut, Cfg, Srv, Req, Err> fmt::Debug for FnServiceConfig<F, Fut, Cfg, Srv, Req, Err>
276where
277 F: Fn(Cfg) -> Fut,
278 Fut: Future<Output = Result<Srv, Err>>,
279 Srv: Service<Req>,
280{
281 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
282 f.debug_struct("FnServiceConfig")
283 .field("f", &std::any::type_name::<F>())
284 .finish()
285 }
286}
287
288impl<F, Fut, Cfg, Srv, Req, Err> ServiceFactory<Req, Cfg>
289 for FnServiceConfig<F, Fut, Cfg, Srv, Req, Err>
290where
291 F: Fn(Cfg) -> Fut,
292 Fut: Future<Output = Result<Srv, Err>>,
293 Srv: Service<Req>,
294{
295 type Response = Srv::Response;
296 type Error = Srv::Error;
297
298 type Service = Srv;
299 type InitError = Err;
300
301 #[inline]
302 async fn create(&self, cfg: Cfg) -> Result<Self::Service, Self::InitError> {
303 (self.f)(cfg).await
304 }
305}
306
307pub struct FnServiceNoConfig<F, S, R, Req, E>
309where
310 F: Fn() -> R,
311 S: Service<Req>,
312 R: Future<Output = Result<S, E>>,
313{
314 f: F,
315 _t: PhantomData<Req>,
316}
317
318impl<F, S, R, Req, E> FnServiceNoConfig<F, S, R, Req, E>
319where
320 F: Fn() -> R,
321 R: Future<Output = Result<S, E>>,
322 S: Service<Req>,
323{
324 fn new(f: F) -> Self {
325 Self { f, _t: PhantomData }
326 }
327}
328
329impl<F, S, R, Req, E, C> ServiceFactory<Req, C> for FnServiceNoConfig<F, S, R, Req, E>
330where
331 F: Fn() -> R,
332 R: Future<Output = Result<S, E>>,
333 S: Service<Req>,
334 C: 'static,
335{
336 type Response = S::Response;
337 type Error = S::Error;
338 type Service = S;
339 type InitError = E;
340
341 #[inline]
342 async fn create(&self, _: C) -> Result<S, E> {
343 (self.f)().await
344 }
345}
346
347impl<F, S, R, Req, E> Clone for FnServiceNoConfig<F, S, R, Req, E>
348where
349 F: Fn() -> R + Clone,
350 R: Future<Output = Result<S, E>>,
351 S: Service<Req>,
352{
353 #[inline]
354 fn clone(&self) -> Self {
355 Self::new(self.f.clone())
356 }
357}
358
359impl<F, S, R, Req, E> fmt::Debug for FnServiceNoConfig<F, S, R, Req, E>
360where
361 F: Fn() -> R,
362 R: Future<Output = Result<S, E>>,
363 S: Service<Req>,
364{
365 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
366 f.debug_struct("FnServiceNoConfig")
367 .field("f", &std::any::type_name::<F>())
368 .finish()
369 }
370}
371
372#[cfg(test)]
373mod tests {
374 use ntex_util::future::lazy;
375 use std::task::Poll;
376
377 use super::*;
378 use crate::Pipeline;
379
380 #[ntex::test]
381 async fn test_fn_service() {
382 let new_srv = fn_service(|()| async { Ok::<_, ()>("srv") }).clone();
383 let _ = format!("{:?}", new_srv);
384
385 let srv = Pipeline::new(new_srv.create(()).await.unwrap()).bind();
386 let res = srv.call(()).await;
387 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
388 assert!(res.is_ok());
389 assert_eq!(res.unwrap(), "srv");
390 let _ = format!("{:?}", srv);
391
392 let srv2 = Pipeline::new(new_srv.clone()).bind();
393 let res = srv2.call(()).await;
394 assert!(res.is_ok());
395 assert_eq!(res.unwrap(), "srv");
396 let _ = format!("{:?}", srv2);
397
398 assert_eq!(lazy(|cx| srv2.poll_shutdown(cx)).await, Poll::Ready(()));
399 }
400
401 #[ntex::test]
402 async fn test_fn_service_service() {
403 let srv = Pipeline::new(
404 fn_service(|()| async { Ok::<_, ()>("srv") })
405 .clone()
406 .create(&())
407 .await
408 .unwrap()
409 .clone(),
410 )
411 .bind();
412
413 let res = srv.call(()).await;
414 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
415 assert!(res.is_ok());
416 assert_eq!(res.unwrap(), "srv");
417 assert_eq!(lazy(|cx| srv.poll_shutdown(cx)).await, Poll::Ready(()));
418 }
419
420 #[ntex::test]
421 async fn test_fn_service_with_config() {
422 let new_srv = fn_factory_with_config(|cfg: &usize| {
423 let cfg = *cfg;
424 async move {
425 Ok::<_, ()>(fn_service(
426 move |()| async move { Ok::<_, ()>(("srv", cfg)) },
427 ))
428 }
429 })
430 .clone();
431
432 let srv = Pipeline::new(new_srv.create(&1).await.unwrap()).bind();
433 let res = srv.call(()).await;
434 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
435 assert!(res.is_ok());
436 assert_eq!(res.unwrap(), ("srv", 1));
437 }
438}