1use std::any::{type_name};
2use std::backtrace::{Backtrace, BacktraceStatus};
3use std::fmt::{Debug, Display};
4
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7
8#[cfg(feature = "serde")]
9#[derive(Serialize, Deserialize)]
10pub struct Error<T> {
11 code: T,
12 msg: String,
13 #[serde(skip)]
14 source: Option<Box<(dyn std::error::Error + 'static + Send + Sync)>>,
15 #[serde(skip)]
16 backtrace: Option<Backtrace>,
17}
18
19#[cfg(not(feature = "serde"))]
20pub struct Error<T> {
21 code: T,
22 msg: String,
23 source: Option<Box<(dyn std::error::Error + 'static + Send + Sync)>>,
24 backtrace: Option<Backtrace>,
25}
26
27pub type Result<T, C> = std::result::Result<T, Error<C>>;
28
29impl<T: Debug + Copy + Sync + Send + 'static> Error<T> {
30 pub fn new(code: T, msg: String) -> Self {
31 #[cfg(feature = "backtrace")]
32 let backtrace = Some(Backtrace::force_capture());
33
34 #[cfg(not(feature = "backtrace"))]
35 let backtrace = None;
36
37 Self {
38 code,
39 msg,
40 source: None,
41 backtrace,
42 }
43 }
44
45 pub fn code(&self) -> T {
46 self.code
47 }
48
49 pub fn msg(&self) -> &str {
50 &self.msg
51 }
52
53 #[cfg(feature = "backtrace")]
54 pub fn backtrace(&self) -> Option<&Backtrace> {
55 self.backtrace.as_ref()
56 }
57}
58
59impl<T: Debug + Clone + Copy> std::error::Error for Error<T> {
60 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
61 self.source.as_ref().map(|e| e.as_ref() as _)
62 }
63}
64
65impl<T: Debug> Debug for Error<T> {
66 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67 write!(f, "{}:{:?}", type_name::<T>(), self.code)?;
68 if !self.msg.is_empty() {
69 write!(f, ", msg:{}", self.msg)?;
70 }
71 if self.source.is_some() {
72 write!(f, "\nCaused by: {:?}", self.source.as_ref().unwrap())?;
73 }
74 if let Some(backtrace) = &self.backtrace {
75 if let BacktraceStatus::Captured = backtrace.status() {
76 let mut backtrace = backtrace.to_string();
77 write!(f, "\n")?;
78 if backtrace.starts_with("stack backtrace:") {
79 backtrace.replace_range(0..1, "S");
81 } else {
82 writeln!(f, "Stack backtrace:")?;
85 }
86 backtrace.truncate(backtrace.trim_end().len());
87 write!(f, "{}", backtrace)?;
88 }
89 }
90 Ok(())
91 }
92}
93
94impl<T: Debug> Display for Error<T> {
95 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96 write!(f, "{}:{:?}", type_name::<T>(), self.code)?;
97 if !self.msg.is_empty() {
98 write!(f, ", msg:{}", self.msg)?;
99 }
100 if self.source.is_some() {
101 write!(f, "\nCaused by: {:?}", self.source.as_ref().unwrap())?;
102 }
103 if let Some(backtrace) = &self.backtrace {
104 if let BacktraceStatus::Captured = backtrace.status() {
105 let mut backtrace = backtrace.to_string();
106 write!(f, "\n")?;
107 if backtrace.starts_with("stack backtrace:") {
108 backtrace.replace_range(0..1, "S");
110 } else {
111 writeln!(f, "Stack backtrace:")?;
114 }
115 backtrace.truncate(backtrace.trim_end().len());
116 write!(f, "{}", backtrace)?;
117 }
118 }
119 Ok(())
120 }
121}
122
123impl<T: Default> From<String> for Error<T> {
124 fn from(value: String) -> Self {
125 #[cfg(feature = "backtrace")]
126 let backtrace = Some(Backtrace::force_capture());
127
128 #[cfg(not(feature = "backtrace"))]
129 let backtrace = None;
130 Self {
131 code: Default::default(),
132 msg: value,
133 source: None,
134 backtrace,
135 }
136 }
137}
138
139impl<T, E: std::error::Error + 'static + Send + Sync> From<(T, String, E)> for Error<T> {
140 fn from(value: (T, String, E)) -> Self {
141 #[cfg(feature = "backtrace")]
142 let backtrace = Some(Backtrace::force_capture());
143
144 #[cfg(not(feature = "backtrace"))]
145 let backtrace = None;
146 Self {
147 code: value.0,
148 msg: value.1,
149 source: Some(Box::new(value.2)),
150 backtrace,
151 }
152 }
153}
154
155impl<T, E: std::error::Error + 'static + Send + Sync> From<(T, &str, E)> for Error<T> {
156 fn from(value: (T, &str, E)) -> Self {
157 #[cfg(feature = "backtrace")]
158 let backtrace = Some(Backtrace::force_capture());
159
160 #[cfg(not(feature = "backtrace"))]
161 let backtrace = None;
162 Self {
163 code: value.0,
164 msg: value.1.to_string(),
165 source: Some(Box::new(value.2)),
166 backtrace,
167 }
168 }
169}
170
171#[cfg(feature = "log")]
172pub use log::error as serror;
173
174#[cfg(feature = "log")]
175#[macro_export]
176macro_rules! error {
177 (target: $target:expr, $($arg:tt)+) => ($crate::serror!($target, $($arg)+));
180
181 ($($arg:tt)+) => ($crate::serror!($($arg)+))
183}
184#[cfg(not(feature = "log"))]
185#[macro_export]
186macro_rules! error {
187 (target: $target:expr, $($arg:tt)+) => ();
190
191 ($($arg:tt)+) => ()
193}
194
195#[macro_export]
196macro_rules! err {
197 ( $err: expr) => {
198 {
199 $crate::error!("{:?}", $err);
200 $crate::Error::new($err, "".to_string())
201 }
202 };
203 ( $err: expr, $($arg:tt)*) => {
204 {
205 $crate::error!("{}", format!($($arg)*));
206 $crate::Error::new($err, format!("{}", format!($($arg)*)))
207 }
208 };
209}
210
211#[macro_export]
212macro_rules! into_err {
213 ($err: expr) => {
214 |e| {
215 $crate::error!("err:{:?}", e);
216 $crate::Error::from(($err, "".to_string(), e))
217 }
218 };
219 ($err: expr, $($arg:tt)*) => {
220 |e| {
221 $crate::error!("{} err:{:?}", format!($($arg)*), e);
222 $crate::Error::from(($err, format!($($arg)*), e))
223 }
224 };
225}
226
227#[cfg(test)]
228mod test {
229 #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
230 pub enum TestCode {
231 #[default]
232 Test1,
233 Test2,
234 }
235 pub type Error = super::Error<TestCode>;
236
237 #[test]
238 fn test() {
239 use crate as sfo_result;
240 let error = sfo_result::Error::new(1, "test".to_string());
241 println!("{:?}", error);
242
243 let error = err!(1, "test");
244 println!("{:?}", error);
245
246 let error = Error::from((TestCode::Test1, "test".to_string(), error));
247 println!("{:?}", error);
248
249 }
252}