resp_result/resp_result/to_response/
axum.rs

1#[cfg(all(feature = "tracing", feature = "for-axum"))]
2use trace as tracing;
3
4#[cfg(feature = "for-axum")]
5impl<T, E> axum::response::IntoResponse for crate::RespResult<T, E>
6where
7    T: crate::resp_body::RespBody,
8    E: crate::RespError,
9{
10    #[inline]
11    #[cfg_attr(
12        feature = "tracing",
13        trace::instrument(name = "axum-into-response", skip_all)
14    )]
15    fn into_response(self) -> axum::response::Response {
16        use crate::expect_ext::ExpectExt;
17
18        let respond = super::PrepareRespond::from_resp_result(&self);
19        let mut builder = axum::response::Response::builder().status(respond.status);
20
21        builder
22            .headers_mut()
23            .with_expect("RespResult 构造响应时发生异常")
24            .extend(respond.headers);
25        builder
26            .body(axum::body::boxed(axum::body::Full::from(respond.body)))
27            .with_expect("RespResult 构造响应时发生异常")
28    }
29}
30#[cfg(feature = "for-axum")]
31pub mod axum_respond_part {
32    use std::{convert::Infallible, future::Future};
33
34    use axum::response::{IntoResponse, IntoResponseParts, ResponseParts};
35
36    use crate::{resp_body, Nil, RespError, RespResult};
37
38    pub mod prefab_part_handle {
39        use crate::Nil;
40
41        pub fn no_part<T>(data: T) -> (T, Nil) {
42            (data, Nil)
43        }
44
45        pub fn no_resp<T>(data: T) -> ((), T) {
46            ((), data)
47        }
48    }
49
50    #[inline]
51    pub async fn resp_result_with_respond_part<T, E, F, Fut, R, P, Resp, Part>(
52        handle: F,
53        part_handle: P,
54    ) -> RespResultExtraPart<Resp, E, Part>
55    where
56        // handles
57        F: FnOnce() -> Fut,
58        Fut: Future<Output = R>,
59        R: Into<RespResult<T, E>>,
60        // part into respond and respond part
61        P: FnOnce(T) -> (Resp, Part),
62        Resp: resp_body::RespBody,
63        Part: IntoResponseParts,
64        E: RespError,
65    {
66        let (resp_result, part) = match handle().await.into() {
67            RespResult::Success(data) => {
68                let (resp, part) = part_handle(data);
69                (RespResult::Success(resp), Some(part))
70            }
71            RespResult::Err(err) => (RespResult::Err(err), None),
72        };
73        RespResultExtraPart {
74            inner: resp_result,
75            extra: part,
76        }
77    }
78
79    impl IntoResponseParts for Nil {
80        type Error = Infallible;
81        #[inline]
82        fn into_response_parts(self, res: ResponseParts) -> Result<ResponseParts, Self::Error> {
83            Ok(res)
84        }
85    }
86    #[derive(Debug)]
87    pub struct RespResultExtraPart<T, E, Extra>
88    where
89        T: resp_body::RespBody,
90        E: RespError,
91        Extra: IntoResponseParts,
92    {
93        inner: RespResult<T, E>,
94        extra: Option<Extra>,
95    }
96
97    impl<T, E, Extra> IntoResponse for RespResultExtraPart<T, E, Extra>
98    where
99        T: resp_body::RespBody,
100        E: RespError,
101        Extra: IntoResponseParts,
102    {
103        #[inline]
104        fn into_response(self) -> axum::response::Response {
105            (self.extra, self.inner).into_response()
106        }
107    }
108
109    impl<T, E, Extra> RespResultExtraPart<T, E, Extra>
110    where
111        T: resp_body::RespBody,
112        E: RespError,
113        Extra: IntoResponseParts,
114    {
115        #[inline]
116        pub fn map<R, F>(self, map: F) -> RespResultExtraPart<T, E, R>
117        where
118            F: FnOnce(Extra) -> R,
119            R: IntoResponseParts,
120        {
121            RespResultExtraPart {
122                inner: self.inner,
123                extra: self.extra.map(map),
124            }
125        }
126
127        #[inline]
128        pub fn map_none<F>(self, map: F) -> Self
129        where
130            F: FnOnce() -> Extra,
131        {
132            Self {
133                inner: self.inner,
134                extra: self.extra.or_else(|| Some(map())),
135            }
136        }
137    }
138
139    #[cfg(test)]
140    mod test {
141        use serde::Serialize;
142
143        use crate::RespError;
144
145        use super::resp_result_with_respond_part;
146
147        #[derive(Debug)]
148        struct MockError;
149
150        impl Serialize for MockError {
151            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
152            where
153                S: serde::Serializer,
154            {
155                serializer.serialize_str("Mock Error")
156            }
157        }
158
159        impl RespError for MockError {
160            fn log_message(&self) -> std::borrow::Cow<'_, str> {
161                "Mock Error".into()
162            }
163
164            type ExtraMessage = String;
165
166            fn extra_message(&self) -> Self::ExtraMessage {
167                String::new()
168            }
169        }
170
171        #[tokio::test]
172        async fn test_wrap() {
173            let resp = resp_result_with_respond_part(
174                || async { Result::<_, MockError>::Ok((12i32, [("auth_type", "12345")])) },
175                |(body, part)| (body, part),
176            )
177            .await;
178
179            println!("resp : {:?}", resp);
180        }
181    }
182}