axum_resp_result/extra_flag/
flag_wrap.rs

1use crate::{
2    resp_body::{LoadSerde, RespBody},
3    ExtraFlags, RespResult,
4};
5
6use super::effect::{BodyEffect, Effects};
7
8/// an wrap for adding extra flags.
9/// the [`FlagWrap`] if and only if using like following
10/// ```rust ignore
11/// RespResult<FlagWrap<T>, E>
12/// ```
13pub struct FlagWrap<T> {
14    inner: T,
15    flags: ExtraFlags,
16}
17
18impl<T> FlagWrap<T> {
19    /// crate a new [`FlagWrap`] with `data` and `flags`
20    #[inline]
21    pub fn new(data: T, flags: impl Into<ExtraFlags>) -> Self {
22        Self {
23            inner: data,
24            flags: flags.into(),
25        }
26    }
27}
28
29impl<T, E> RespResult<T, E> {
30    #[inline]
31    /// create a [`RespResult::Success`] with flags
32    pub fn flag_ok(data: T, flags: impl Into<ExtraFlags>) -> RespResult<FlagWrap<T>, E> {
33        RespResult::ok(FlagWrap::new(data, flags))
34    }
35
36    #[inline]
37    /// covert a [`RespResult::<T, E>`] into [`RespResult<FlagWrap<T>, E>`] with provide flags
38    pub fn with_flags(self, flags: impl Into<ExtraFlags>) -> RespResult<FlagWrap<T>, E> {
39        match self {
40            RespResult::Success(data) => RespResult::Success(FlagWrap::new(data, flags)),
41            RespResult::Err(err) => RespResult::Err(err),
42        }
43    }
44}
45
46impl<T, E> From<RespResult<T, E>> for RespResult<FlagWrap<T>, E> {
47    fn from(inner: RespResult<T, E>) -> Self {
48        inner.with_flags(())
49    }
50}
51
52impl<T: LoadSerde> LoadSerde for FlagWrap<T> {
53    type SerdeData = T::SerdeData;
54
55    fn load_serde(&self) -> &Self::SerdeData {
56        self.inner.load_serde()
57    }
58}
59
60impl<T> Effects for FlagWrap<T> {
61    #[inline]
62    fn body_effect(&self, body: &mut Vec<u8>) -> BodyEffect {
63        self.flags.body_effect(body)
64    }
65    #[inline]
66    fn status_effect(&self) -> Option<http::StatusCode> {
67        self.flags.status_effect()
68    }
69    #[inline]
70    fn headers_effect(&self, map: &mut http::HeaderMap) {
71        self.flags.headers_effect(map)
72    }
73}
74
75impl<T: LoadSerde> RespBody for FlagWrap<T> {}
76
77#[cfg(test)]
78mod test {
79    use http::StatusCode;
80
81    use crate::{resp_result::serde::SerializeWrap, ExtraFlag, RespError, RespResult};
82
83    struct MockErr;
84
85    impl RespError for MockErr {
86        fn log_message(&self) -> std::borrow::Cow<'_, str> {
87            "Mock Error".into()
88        }
89        #[cfg(feature = "extra-error")]
90        type ExtraMessage = String;
91
92        #[cfg(feature = "extra-error")]
93        fn extra_message(&self) -> Self::ExtraMessage {
94            "Mock".into()
95        }
96    }
97
98    #[test]
99    fn test_serde() {
100        let a = RespResult::<_, MockErr>::Success(12i32).with_flags(
101            ExtraFlag::EmptyBody
102                + ExtraFlag::status(StatusCode::NOT_MODIFIED)
103                + ExtraFlag::insert_header(http::header::ETAG, "1234567890")
104                + ExtraFlag::insert_header(
105                    http::header::CONTENT_TYPE,
106                    mime::TEXT_PLAIN_UTF_8.as_ref(),
107                ),
108        );
109
110        let s = serde_json::to_string_pretty(&SerializeWrap(&a)).unwrap();
111
112        println!("{s}")
113    }
114}