axum_resp_result/resp_result/
mod.rs

1#[cfg(feature = "tracing")]
2use std::any::type_name;
3use std::fmt::Debug;
4
5use crate::resp_error::RespError;
6
7pub mod serde;
8pub mod to_response;
9mod try_macro;
10#[cfg(feature = "nightly_try_v2")]
11mod try_op;
12
13pub use to_response::Nil;
14
15#[cfg(feature = "tracing")]
16use trace::{event, Level};
17
18/// resp result for more flexible control the response body
19///
20/// - [`Result`] will become `500` using as web framework response type when `Err(_)`, the action usually not I expect
21/// - using non-Result type as web framework response type cannot using `?`, the code will fill with `if let` or `match`
22///
23/// that why I need a [`RespResult`] which can
24/// - control respond code or other message when it become [`RespResult::Err`], not always `500`
25/// - impl the [`Try`](std::ops::Try) thus can using friendly `?` to simplify code
26///
27/// > note: because the [`Try`](std::ops::Try) not stable yet, this crate need `Nightly` rust
28pub enum RespResult<T, E> {
29    /// the respond is success with response body `T`
30    Success(T),
31    /// the respond is failure with response error `E`
32    Err(E),
33}
34
35impl<T: std::fmt::Debug, E: RespError> Debug for RespResult<T, E> {
36    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37        match self {
38            Self::Success(arg0) => f.debug_tuple("Success").field(arg0).finish(),
39            Self::Err(arg0) => f.debug_tuple("Err").field(&arg0.log_message()).finish(),
40        }
41    }
42}
43
44impl<T: std::fmt::Display, E: RespError> std::fmt::Display for RespResult<T, E> {
45    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46        match self {
47            RespResult::Success(data) => write!(f, "RespResult Ok[{data}]"),
48            RespResult::Err(err) => write!(f, "RespResult Err[{}]", err.log_message()),
49        }
50    }
51}
52
53impl<T, E> RespResult<T, E> {
54    #[inline]
55    /// map currently `T` into `N`,
56    ///
57    /// this method is similar to the same name method of [`Result`]
58    pub fn map<N, F>(self, f: F) -> RespResult<N, E>
59    where
60        F: FnOnce(T) -> N,
61    {
62        #[cfg(feature = "tracing")]
63        event!(
64            Level::TRACE,
65            event = "Mapping",
66            from = type_name::<T>(),
67            to = type_name::<N>()
68        );
69        match self {
70            RespResult::Success(data) => RespResult::Success(f(data)),
71            RespResult::Err(e) => RespResult::Err(e),
72        }
73    }
74
75    #[inline]
76    /// map currently `E` into `N`,
77    ///
78    /// this method is similar to the same name method of [`Result`]
79    pub fn map_err<N, F>(self, f: F) -> RespResult<T, N>
80    where
81        F: FnOnce(E) -> N,
82    {
83        #[cfg(feature = "tracing")]
84        event!(
85            Level::TRACE,
86            event = "Mapping Error",
87            from = type_name::<E>(),
88            to = type_name::<N>()
89        );
90        match self {
91            RespResult::Success(data) => RespResult::Success(data),
92            RespResult::Err(e) => RespResult::Err(f(e)),
93        }
94    }
95
96    #[inline]
97    /// this method is similar to the same name method of [`Result`]
98    pub fn and_then<N, F>(self, f: F) -> RespResult<N, E>
99    where
100        F: FnOnce(T) -> RespResult<N, E>,
101    {
102        match self {
103            RespResult::Success(data) => f(data),
104            RespResult::Err(e) => RespResult::Err(e),
105        }
106    }
107
108    #[inline]
109    /// this method is similar to the same name method of [`Result`]
110    pub fn or_else<N, F>(self, f: F) -> RespResult<T, N>
111    where
112        F: FnOnce(E) -> RespResult<T, N>,
113    {
114        match self {
115            RespResult::Success(data) => RespResult::Success(data),
116            RespResult::Err(e) => f(e),
117        }
118    }
119}
120
121impl<T, E> From<Result<T, E>> for RespResult<T, E>
122where
123    E: RespError,
124{
125    #[inline]
126    fn from(r: Result<T, E>) -> Self {
127        match r {
128            Ok(data) => Self::ok(data),
129            Err(err) => Self::err(err),
130        }
131    }
132}
133
134impl<T, E> RespResult<T, E> {
135    #[inline]
136    /// create an success [`RespResult`]
137    pub fn ok(data: T) -> Self {
138        Self::Success(data)
139    }
140    #[inline]
141    /// create an error [`RespResult`]
142    pub fn err(err: E) -> Self
143    where
144        E: RespError,
145    {
146        Self::Err(err)
147    }
148}