orion_error/traits/
conversion.rs1use crate::{core::convert_error, core::DomainReason, StructError};
2
3pub trait ConvErr<T, R: DomainReason>: Sized {
43 fn conv_err(self) -> Result<T, StructError<R>>;
44
45 #[deprecated(since = "0.9.0", note = "renamed to conv_err")]
47 fn err_conv(self) -> Result<T, StructError<R>> {
48 self.conv_err()
49 }
50}
51
52pub trait ConvStructError<R: DomainReason>: Sized {
56 fn conv(self) -> StructError<R>;
57}
58
59impl<T, R1, R2> ConvErr<T, R2> for Result<T, StructError<R1>>
60where
61 R1: DomainReason,
62 R2: DomainReason + From<R1>,
63{
64 fn conv_err(self) -> Result<T, StructError<R2>> {
65 match self {
66 Ok(o) => Ok(o),
67 Err(e) => Err(convert_error::<R1, R2>(e)),
68 }
69 }
70}
71
72impl<R1, R2> ConvStructError<R2> for StructError<R1>
73where
74 R1: DomainReason,
75 R2: DomainReason + From<R1>,
76{
77 fn conv(self) -> StructError<R2> {
78 convert_error::<R1, R2>(self)
79 }
80}
81
82pub trait ToStructError<R>
87where
88 R: DomainReason,
89{
90 fn to_err(self) -> StructError<R>;
91 fn err_result<T>(self) -> Result<T, StructError<R>>;
92}
93impl<R> ToStructError<R> for R
94where
95 R: DomainReason,
96{
97 fn to_err(self) -> StructError<R> {
98 StructError::from(self)
99 }
100 fn err_result<T>(self) -> Result<T, StructError<R>> {
101 Err(StructError::from(self))
102 }
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108 use crate::reason::ErrorCode;
109 use crate::{core::DomainReason, OperationContext, StructError, UnifiedReason};
110
111 #[derive(Debug, Clone, PartialEq, thiserror::Error)]
113 enum TestReason {
114 #[error("test error")]
115 TestError,
116 #[error("{0}")]
117 General(UnifiedReason),
118 }
119
120 impl ErrorCode for TestReason {
121 fn error_code(&self) -> i32 {
122 match self {
123 TestReason::TestError => 1001,
124 TestReason::General(uvs) => uvs.error_code(),
125 }
126 }
127 }
128
129 impl DomainReason for TestReason {}
130
131 impl From<UnifiedReason> for TestReason {
132 fn from(uvs: UnifiedReason) -> Self {
133 TestReason::General(uvs)
134 }
135 }
136
137 #[derive(Debug, Clone, PartialEq, thiserror::Error)]
139 enum AnotherReason {
140 #[error("another error")]
141 AnotherError,
142 #[error("{0}")]
143 General(UnifiedReason),
144 }
145
146 impl ErrorCode for AnotherReason {
147 fn error_code(&self) -> i32 {
148 match self {
149 AnotherReason::AnotherError => 2001,
150 AnotherReason::General(uvs) => uvs.error_code(),
151 }
152 }
153 }
154
155 impl DomainReason for AnotherReason {}
156
157 impl From<UnifiedReason> for AnotherReason {
158 fn from(uvs: UnifiedReason) -> Self {
159 AnotherReason::General(uvs)
160 }
161 }
162
163 impl From<TestReason> for AnotherReason {
164 fn from(test: TestReason) -> Self {
165 match test {
166 TestReason::TestError => AnotherReason::AnotherError,
167 TestReason::General(uvs) => AnotherReason::General(uvs),
168 }
169 }
170 }
171
172 #[test]
173 fn test_error_conv_trait() {
174 let original_result: Result<i32, StructError<TestReason>> =
176 Err(TestReason::TestError.to_err());
177
178 let converted_result: Result<i32, StructError<AnotherReason>> = original_result.conv_err();
179
180 assert!(converted_result.is_err());
181 let converted_error = converted_result.unwrap_err();
182 assert_eq!(converted_error.reason().error_code(), 2001);
183
184 let success_result: Result<i32, StructError<TestReason>> = Ok(42);
186 let converted_success: Result<i32, StructError<AnotherReason>> = success_result.conv_err();
187
188 assert!(converted_success.is_ok());
189 assert_eq!(converted_success.unwrap(), 42);
190 }
191
192 #[test]
193 fn test_conv_struct_error_trait() {
194 let original_error: StructError<TestReason> = TestReason::TestError.to_err();
196
197 let converted_error: StructError<AnotherReason> = original_error.conv();
198
199 assert_eq!(converted_error.reason().error_code(), 2001);
200
201 let uvs_error: StructError<TestReason> =
203 TestReason::General(UnifiedReason::network_error()).to_err();
204
205 let converted_uvs_error: StructError<AnotherReason> = uvs_error.conv();
206
207 assert_eq!(converted_uvs_error.reason().error_code(), 202);
208 }
209
210 #[test]
211 fn test_to_struct_error_trait() {
212 let reason = TestReason::TestError;
214 let error: StructError<TestReason> = reason.to_err();
215
216 assert_eq!(error.reason().error_code(), 1001);
217
218 let reason2 = TestReason::TestError;
220 let result: Result<String, StructError<TestReason>> = reason2.err_result();
221
222 assert!(result.is_err());
223 let error_from_result = result.unwrap_err();
224 assert_eq!(error_from_result.reason().error_code(), 1001);
225
226 let uvs_reason1 = UnifiedReason::validation_error();
228 let uvs_error: StructError<UnifiedReason> = uvs_reason1.to_err();
229
230 assert_eq!(uvs_error.reason().error_code(), 100);
231
232 let uvs_reason2 = UnifiedReason::validation_error();
233 let uvs_result: Result<i32, StructError<UnifiedReason>> = uvs_reason2.err_result();
234 assert!(uvs_result.is_err());
235 assert_eq!(uvs_result.unwrap_err().reason().error_code(), 100);
236 }
237
238 #[test]
239 fn test_upcast_preserves_source() {
240 let source = std::io::Error::other("db unavailable");
241 let original: Result<i32, StructError<TestReason>> =
242 Err(StructError::from(TestReason::TestError).with_std_source(source));
243
244 let converted: Result<i32, StructError<AnotherReason>> = original.conv_err();
245 let err = converted.unwrap_err();
246
247 assert_eq!(err.reason().error_code(), 2001);
248 assert_eq!(err.source_ref().unwrap().to_string(), "db unavailable");
249 }
250
251 #[test]
252 fn test_upcast_preserves_context_metadata() {
253 let original: Result<i32, StructError<TestReason>> =
254 Err(StructError::from(TestReason::TestError).with_context(
255 OperationContext::doing("load sink defaults")
256 .with_meta("config.kind", "sink_defaults"),
257 ));
258
259 let converted: Result<i32, StructError<AnotherReason>> = original.conv_err();
260 let err = converted.unwrap_err();
261
262 assert_eq!(
263 err.context_metadata().get_str("config.kind"),
264 Some("sink_defaults")
265 );
266 }
267}