actix_service/
map_err.rs

1use core::{
2    future::Future,
3    marker::PhantomData,
4    pin::Pin,
5    task::{Context, Poll},
6};
7
8use pin_project_lite::pin_project;
9
10use super::{Service, ServiceFactory};
11
12/// Service for the `map_err` combinator, changing the type of a service's error.
13///
14/// This is created by the `ServiceExt::map_err` method.
15pub struct MapErr<S, Req, F, E> {
16    service: S,
17    mapper: F,
18    _t: PhantomData<fn(Req) -> E>,
19}
20
21impl<S, Req, F, E> MapErr<S, Req, F, E> {
22    /// Create new `MapErr` combinator
23    pub(crate) fn new(service: S, mapper: F) -> Self
24    where
25        S: Service<Req>,
26        F: Fn(S::Error) -> E,
27    {
28        Self {
29            service,
30            mapper,
31            _t: PhantomData,
32        }
33    }
34}
35
36impl<S, Req, F, E> Clone for MapErr<S, Req, F, E>
37where
38    S: Clone,
39    F: Clone,
40{
41    fn clone(&self) -> Self {
42        MapErr {
43            service: self.service.clone(),
44            mapper: self.mapper.clone(),
45            _t: PhantomData,
46        }
47    }
48}
49
50impl<A, Req, F, E> Service<Req> for MapErr<A, Req, F, E>
51where
52    A: Service<Req>,
53    F: Fn(A::Error) -> E + Clone,
54{
55    type Response = A::Response;
56    type Error = E;
57    type Future = MapErrFuture<A, Req, F, E>;
58
59    fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
60        self.service.poll_ready(ctx).map_err(&self.mapper)
61    }
62
63    fn call(&self, req: Req) -> Self::Future {
64        MapErrFuture::new(self.service.call(req), self.mapper.clone())
65    }
66}
67
68pin_project! {
69    pub struct MapErrFuture<A, Req, F, E>
70    where
71        A: Service<Req>,
72        F: Fn(A::Error) -> E,
73    {
74        f: F,
75        #[pin]
76        fut: A::Future,
77    }
78}
79
80impl<A, Req, F, E> MapErrFuture<A, Req, F, E>
81where
82    A: Service<Req>,
83    F: Fn(A::Error) -> E,
84{
85    fn new(fut: A::Future, f: F) -> Self {
86        MapErrFuture { f, fut }
87    }
88}
89
90impl<A, Req, F, E> Future for MapErrFuture<A, Req, F, E>
91where
92    A: Service<Req>,
93    F: Fn(A::Error) -> E,
94{
95    type Output = Result<A::Response, E>;
96
97    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
98        let this = self.project();
99        this.fut.poll(cx).map_err(this.f)
100    }
101}
102
103/// Factory for the `map_err` combinator, changing the type of a new
104/// service's error.
105///
106/// This is created by the `NewServiceExt::map_err` method.
107pub struct MapErrServiceFactory<SF, Req, F, E>
108where
109    SF: ServiceFactory<Req>,
110    F: Fn(SF::Error) -> E + Clone,
111{
112    a: SF,
113    f: F,
114    e: PhantomData<fn(Req) -> E>,
115}
116
117impl<SF, Req, F, E> MapErrServiceFactory<SF, Req, F, E>
118where
119    SF: ServiceFactory<Req>,
120    F: Fn(SF::Error) -> E + Clone,
121{
122    /// Create new `MapErr` new service instance
123    pub(crate) fn new(a: SF, f: F) -> Self {
124        Self {
125            a,
126            f,
127            e: PhantomData,
128        }
129    }
130}
131
132impl<SF, Req, F, E> Clone for MapErrServiceFactory<SF, Req, F, E>
133where
134    SF: ServiceFactory<Req> + Clone,
135    F: Fn(SF::Error) -> E + Clone,
136{
137    fn clone(&self) -> Self {
138        Self {
139            a: self.a.clone(),
140            f: self.f.clone(),
141            e: PhantomData,
142        }
143    }
144}
145
146impl<SF, Req, F, E> ServiceFactory<Req> for MapErrServiceFactory<SF, Req, F, E>
147where
148    SF: ServiceFactory<Req>,
149    F: Fn(SF::Error) -> E + Clone,
150{
151    type Response = SF::Response;
152    type Error = E;
153
154    type Config = SF::Config;
155    type Service = MapErr<SF::Service, Req, F, E>;
156    type InitError = SF::InitError;
157    type Future = MapErrServiceFuture<SF, Req, F, E>;
158
159    fn new_service(&self, cfg: SF::Config) -> Self::Future {
160        MapErrServiceFuture::new(self.a.new_service(cfg), self.f.clone())
161    }
162}
163
164pin_project! {
165    pub struct MapErrServiceFuture<SF, Req, F, E>
166    where
167        SF: ServiceFactory<Req>,
168        F: Fn(SF::Error) -> E,
169    {
170        #[pin]
171        fut: SF::Future,
172        mapper: F,
173    }
174}
175
176impl<SF, Req, F, E> MapErrServiceFuture<SF, Req, F, E>
177where
178    SF: ServiceFactory<Req>,
179    F: Fn(SF::Error) -> E,
180{
181    fn new(fut: SF::Future, mapper: F) -> Self {
182        MapErrServiceFuture { fut, mapper }
183    }
184}
185
186impl<SF, Req, F, E> Future for MapErrServiceFuture<SF, Req, F, E>
187where
188    SF: ServiceFactory<Req>,
189    F: Fn(SF::Error) -> E + Clone,
190{
191    type Output = Result<MapErr<SF::Service, Req, F, E>, SF::InitError>;
192
193    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
194        let this = self.project();
195        if let Poll::Ready(svc) = this.fut.poll(cx)? {
196            Poll::Ready(Ok(MapErr::new(svc, this.mapper.clone())))
197        } else {
198            Poll::Pending
199        }
200    }
201}
202
203#[cfg(test)]
204mod tests {
205    use futures_util::future::lazy;
206
207    use super::*;
208    use crate::{err, ok, IntoServiceFactory, Ready, ServiceExt, ServiceFactoryExt};
209
210    struct Srv;
211
212    impl Service<()> for Srv {
213        type Response = ();
214        type Error = ();
215        type Future = Ready<Result<(), ()>>;
216
217        fn poll_ready(&self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
218            Poll::Ready(Err(()))
219        }
220
221        fn call(&self, _: ()) -> Self::Future {
222            err(())
223        }
224    }
225
226    #[actix_rt::test]
227    async fn test_poll_ready() {
228        let srv = Srv.map_err(|_| "error");
229        let res = lazy(|cx| srv.poll_ready(cx)).await;
230        assert_eq!(res, Poll::Ready(Err("error")));
231    }
232
233    #[actix_rt::test]
234    async fn test_call() {
235        let srv = Srv.map_err(|_| "error");
236        let res = srv.call(()).await;
237        assert!(res.is_err());
238        assert_eq!(res.err().unwrap(), "error");
239    }
240
241    #[actix_rt::test]
242    async fn test_new_service() {
243        let new_srv = (|| ok::<_, ()>(Srv)).into_factory().map_err(|_| "error");
244        let srv = new_srv.new_service(&()).await.unwrap();
245        let res = srv.call(()).await;
246        assert!(res.is_err());
247        assert_eq!(res.err().unwrap(), "error");
248    }
249}