1use std::{
2 future::Future,
3 marker::PhantomData,
4 pin::Pin,
5 task::{Context, Poll},
6};
7
8use futures_util::ready;
9use pin_project::pin_project;
10
11use crate::Svc;
12
13#[pin_project]
14pub struct MapSvc<S, F, Res> {
15 #[pin]
16 svc: S,
17 mapper: F,
18 _res: PhantomData<Res>,
19}
20
21impl<S, F, Res> MapSvc<S, F, Res> {
22 pub fn new(svc: S, mapper: F) -> Self {
23 Self {
24 svc,
25 mapper,
26 _res: PhantomData,
27 }
28 }
29}
30
31impl<S, Req, F, Res> Svc<Req> for MapSvc<S, F, Res>
32where
33 S: Svc<Req>,
34 F: FnMut(S::Res) -> Res + Clone,
35{
36 type Res = Res;
37 type Fut = MapSvcFut<S, F, Req, Res>;
38
39 fn exec(self: Pin<&mut Self>, req: Req) -> Self::Fut {
40 let mapper = self.mapper.clone();
41 let this = self.project();
42 MapSvcFut::new(this.svc.exec(req), mapper)
43 }
44}
45
46#[pin_project]
47pub struct MapSvcFut<S, F, Req, Res>
48where
49 S: Svc<Req>,
50 F: FnMut(S::Res) -> Res,
51{
52 mapper: F,
53 #[pin]
54 fut: S::Fut,
55}
56
57impl<S, F, Req, Res> MapSvcFut<S, F, Req, Res>
58where
59 S: Svc<Req>,
60 F: FnMut(S::Res) -> Res,
61{
62 pub fn new(fut: S::Fut, mapper: F) -> Self {
63 Self { fut, mapper }
64 }
65}
66
67impl<S, F, Req, Res> Future for MapSvcFut<S, F, Req, Res>
68where
69 S: Svc<Req>,
70 F: FnMut(S::Res) -> Res,
71{
72 type Output = Res;
73
74 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
75 let this = self.project();
76
77 let res = ready!(this.fut.poll(cx));
78 Poll::Ready((this.mapper)(res))
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use futures_util::pin_mut;
85
86 use super::*;
87 use crate::FnSvc;
88
89 #[tokio::test]
90 async fn test_map_service() {
91 async fn doubler(n: u64) -> u64 {
92 n * 2
93 }
94
95 let svc = FnSvc::new(doubler);
96 let bnf = MapSvc::new(svc, |res| res + 2);
97
98 pin_mut!(bnf);
99
100 let res = bnf.exec(42).await;
101 assert_eq!(res, 86);
102 }
103}