rama_core/layer/
map_result.rs

1use crate::{Context, Layer, Service};
2use rama_utils::macros::define_inner_service_accessors;
3use std::fmt;
4
5/// Maps this service's result type (`Result<Self::Response, Self::Error>`)
6/// to a different value, regardless of whether the future succeeds or
7/// fails.
8///
9/// This is similar to the [`MapResponse`] and [`MapErr`] combinators,
10/// except that the *same* function is invoked when the service's future
11/// completes, whether it completes successfully or fails. This function
12/// takes the [`Result`] returned by the service's future, and returns a
13/// [`Result`].
14///
15/// Like the standard library's [`Result::and_then`], this method can be
16/// used to implement control flow based on `Result` values. For example, it
17/// may be used to implement error recovery, by turning some [`Err`]
18/// responses from the service into [`Ok`] responses. Similarly, some
19/// successful responses from the service could be rejected, by returning an
20/// [`Err`] conditionally, depending on the value inside the [`Ok`.] Finally,
21/// this method can also be used to implement behaviors that must run when a
22/// service's future completes, regardless of whether it succeeded or failed.
23///
24/// This method can be used to change the `Response` type of the service
25/// into a different type. It can also be used to change the `Error` type
26/// of the service.
27///
28/// [`MapResponse`]: crate::layer::MapResponse
29/// [`MapErr`]: crate::layer::MapErr
30pub struct MapResult<S, F> {
31    inner: S,
32    f: F,
33}
34
35impl<S, F> fmt::Debug for MapResult<S, F>
36where
37    S: fmt::Debug,
38{
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        f.debug_struct("MapResult")
41            .field("inner", &self.inner)
42            .field("f", &format_args!("{}", std::any::type_name::<F>()))
43            .finish()
44    }
45}
46
47impl<S, F> Clone for MapResult<S, F>
48where
49    S: Clone,
50    F: Clone,
51{
52    fn clone(&self) -> Self {
53        Self {
54            inner: self.inner.clone(),
55            f: self.f.clone(),
56        }
57    }
58}
59
60/// A [`Layer`] that produces a [`MapResult`] service.
61///
62/// [`Layer`]: crate::Layer
63pub struct MapResultLayer<F> {
64    f: F,
65}
66
67impl<F> fmt::Debug for MapResultLayer<F> {
68    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69        f.debug_struct("MapResultLayer")
70            .field("f", &format_args!("{}", std::any::type_name::<F>()))
71            .finish()
72    }
73}
74
75impl<F> Clone for MapResultLayer<F>
76where
77    F: Clone,
78{
79    fn clone(&self) -> Self {
80        Self { f: self.f.clone() }
81    }
82}
83
84impl<S, F> MapResult<S, F> {
85    /// Creates a new [`MapResult`] service.
86    pub const fn new(inner: S, f: F) -> Self {
87        MapResult { f, inner }
88    }
89
90    define_inner_service_accessors!();
91}
92
93impl<S, F, State, Request, Response, Error> Service<State, Request> for MapResult<S, F>
94where
95    S: Service<State, Request>,
96    F: FnOnce(Result<S::Response, S::Error>) -> Result<Response, Error>
97        + Clone
98        + Send
99        + Sync
100        + 'static,
101    State: Clone + Send + Sync + 'static,
102    Request: Send + 'static,
103    Response: Send + 'static,
104    Error: Send + 'static,
105{
106    type Response = Response;
107    type Error = Error;
108
109    async fn serve(
110        &self,
111        ctx: Context<State>,
112        req: Request,
113    ) -> Result<Self::Response, Self::Error> {
114        let result = self.inner.serve(ctx, req).await;
115        (self.f.clone())(result)
116    }
117}
118
119impl<F> MapResultLayer<F> {
120    /// Creates a new [`MapResultLayer`] layer.
121    pub const fn new(f: F) -> Self {
122        MapResultLayer { f }
123    }
124}
125
126impl<S, F> Layer<S> for MapResultLayer<F>
127where
128    F: Clone,
129{
130    type Service = MapResult<S, F>;
131
132    fn layer(&self, inner: S) -> Self::Service {
133        MapResult {
134            f: self.f.clone(),
135            inner,
136        }
137    }
138
139    fn into_layer(self, inner: S) -> Self::Service {
140        MapResult { f: self.f, inner }
141    }
142}