async_svc/
map.rs

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}