headless_lms_credit_registration/
error.rs1use std::fmt::Display;
5use std::panic::Location;
6
7use backtrace::Backtrace;
8use headless_lms_base::error::backend_error::BackendError;
9use headless_lms_models::ModelError;
10use headless_lms_utils::error::is_db_disconnect;
11use headless_lms_utils::error::util_error::UtilError;
12use tracing_error::SpanTrace;
13
14pub type CreditRegistrationResult<T> = Result<T, CreditRegistrationError>;
16
17#[derive(Debug, PartialEq, Eq)]
19pub enum CreditRegistrationErrorType {
20 Model,
23 Database,
25}
26
27pub struct CreditRegistrationError {
31 error_type: <CreditRegistrationError as BackendError>::ErrorType,
32 message: String,
33 source: Option<anyhow::Error>,
34 span_trace: Box<SpanTrace>,
35 backtrace: Box<Backtrace>,
36 location: Option<&'static Location<'static>>,
37}
38
39impl std::error::Error for CreditRegistrationError {
40 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
41 self.source
42 .as_deref()
43 .map(|e| e as &(dyn std::error::Error + 'static))
44 }
45
46 fn cause(&self) -> Option<&dyn std::error::Error> {
47 self.source()
48 }
49}
50
51headless_lms_base::impl_clean_debug!(
52 CreditRegistrationError,
53 [CreditRegistrationError, ModelError, UtilError]
54);
55
56impl Display for CreditRegistrationError {
57 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58 write!(
59 f,
60 "CreditRegistrationError {:?} {:?}",
61 self.error_type, self.message
62 )
63 }
64}
65
66impl BackendError for CreditRegistrationError {
67 type ErrorType = CreditRegistrationErrorType;
68
69 fn backtrace(&self) -> Option<&Backtrace> {
70 Some(&self.backtrace)
71 }
72
73 fn error_type(&self) -> &Self::ErrorType {
74 &self.error_type
75 }
76
77 fn message(&self) -> &str {
78 &self.message
79 }
80
81 fn span_trace(&self) -> &SpanTrace {
82 &self.span_trace
83 }
84
85 fn location(&self) -> Option<&'static Location<'static>> {
86 self.location
87 }
88
89 fn new_with_traces_and_location<M: Into<String>, S: Into<Option<anyhow::Error>>>(
90 error_type: Self::ErrorType,
91 message: M,
92 source_error: S,
93 backtrace: Backtrace,
94 span_trace: SpanTrace,
95 location: Option<&'static Location<'static>>,
96 ) -> Self {
97 Self {
98 error_type,
99 message: message.into(),
100 source: source_error.into(),
101 span_trace: Box::new(span_trace),
102 backtrace: Box::new(backtrace),
103 location,
104 }
105 }
106}
107
108impl CreditRegistrationError {
109 pub fn into_model_error(mut self) -> Result<ModelError, Self> {
113 if self.error_type != CreditRegistrationErrorType::Model {
114 return Err(self);
115 }
116 match self.source.take().map(|source| source.downcast()) {
117 Some(Ok(model_error)) => Ok(model_error),
118 Some(Err(source)) => {
119 self.source = Some(source);
120 Err(self)
121 }
122 None => Err(self),
123 }
124 }
125
126 pub fn cause_chain(&self) -> String {
130 let mut chain = self.message.clone();
131 let mut cause = std::error::Error::source(self);
132 while let Some(error) = cause {
133 let text = error.to_string();
134 if !chain.contains(&text) {
135 chain.push_str(": ");
136 chain.push_str(&text);
137 }
138 cause = error.source();
139 }
140 chain
141 }
142
143 pub fn is_db_disconnect(&self) -> bool {
146 is_db_disconnect(self)
147 }
148}
149
150impl From<ModelError> for CreditRegistrationError {
151 #[track_caller]
152 fn from(err: ModelError) -> Self {
153 Self::new(
154 CreditRegistrationErrorType::Model,
155 err.to_string(),
156 Some(err.into()),
157 )
158 }
159}
160
161impl From<sqlx::Error> for CreditRegistrationError {
162 #[track_caller]
163 fn from(err: sqlx::Error) -> Self {
164 Self::new(
165 CreditRegistrationErrorType::Database,
166 err.to_string(),
167 Some(err.into()),
168 )
169 }
170}