1use std::fmt;
2use std::str::FromStr;
3
4use serde_with::DeserializeFromStr;
5use thiserror::Error;
6
7#[derive(Debug, Clone, PartialEq, DeserializeFromStr, Default)]
9pub enum XtbErrorCode {
10 #[default]
12 BE001,
13 BE002,
15 BE003,
17 BE004,
19 BE005,
21 BE006,
23 BE007,
25 BE008,
27 BE009,
29 BE010,
31 BE011,
33 BE012,
35 BE013,
37 BE014,
39 BE016,
41 BE017,
43 BE018,
45 BE019,
47 BE094,
49 BE095,
51 BE096,
53 BE097,
55 BE098,
57 BE101,
59 BE102,
61 BE103,
63 BE104,
65 BE105,
67 BE106,
69 BE110,
71 BE115,
73 BE116,
75 BE117,
77 BE118,
79 BE200,
81 EX000,
83 EX001,
85 EX002,
87 BE000,
89 EX003,
91 EX004,
93 EX005,
95 EX006,
97 EX007,
99 EX008,
101 EX009,
103 EX010,
105 EX011,
107 OtherError(u8),
109 InternalServerError(u16)
111}
112
113impl FromStr for XtbErrorCode {
114 type Err = XtbErrorCodeError;
115
116 fn from_str(s: &str) -> Result<XtbErrorCode, Self::Err> {
117 match s {
118 "BE001" => Ok(XtbErrorCode::BE001),
119 "BE002" => Ok(XtbErrorCode::BE002),
120 "BE003" => Ok(XtbErrorCode::BE003),
121 "BE004" => Ok(XtbErrorCode::BE004),
122 "BE005" => Ok(XtbErrorCode::BE005),
123 "BE006" => Ok(XtbErrorCode::BE006),
124 "BE007" => Ok(XtbErrorCode::BE007),
125 "BE008" => Ok(XtbErrorCode::BE008),
126 "BE009" => Ok(XtbErrorCode::BE009),
127 "BE010" => Ok(XtbErrorCode::BE010),
128 "BE011" => Ok(XtbErrorCode::BE011),
129 "BE012" => Ok(XtbErrorCode::BE012),
130 "BE013" => Ok(XtbErrorCode::BE013),
131 "BE014" => Ok(XtbErrorCode::BE014),
132 "BE016" => Ok(XtbErrorCode::BE016),
133 "BE017" => Ok(XtbErrorCode::BE017),
134 "BE018" => Ok(XtbErrorCode::BE018),
135 "BE019" => Ok(XtbErrorCode::BE019),
136 "BE094" => Ok(XtbErrorCode::BE094),
137 "BE095" => Ok(XtbErrorCode::BE095),
138 "BE096" => Ok(XtbErrorCode::BE096),
139 "BE097" => Ok(XtbErrorCode::BE097),
140 "BE098" => Ok(XtbErrorCode::BE098),
141 "BE101" => Ok(XtbErrorCode::BE101),
142 "BE102" => Ok(XtbErrorCode::BE102),
143 "BE103" => Ok(XtbErrorCode::BE103),
144 "BE104" => Ok(XtbErrorCode::BE104),
145 "BE105" => Ok(XtbErrorCode::BE105),
146 "BE106" => Ok(XtbErrorCode::BE106),
147 "BE110" => Ok(XtbErrorCode::BE110),
148 "BE115" => Ok(XtbErrorCode::BE115),
149 "BE116" => Ok(XtbErrorCode::BE116),
150 "BE117" => Ok(XtbErrorCode::BE117),
151 "BE118" => Ok(XtbErrorCode::BE118),
152 "BE200" => Ok(XtbErrorCode::BE200),
153 "EX000" => Ok(XtbErrorCode::EX000),
154 "EX001" => Ok(XtbErrorCode::EX001),
155 "EX002" => Ok(XtbErrorCode::EX002),
156 "BE000" => Ok(XtbErrorCode::BE000),
157 "EX003" => Ok(XtbErrorCode::EX003),
158 "EX004" => Ok(XtbErrorCode::EX004),
159 "EX005" => Ok(XtbErrorCode::EX005),
160 "EX006" => Ok(XtbErrorCode::EX006),
161 "EX007" => Ok(XtbErrorCode::EX007),
162 "EX008" => Ok(XtbErrorCode::EX008),
163 "EX009" => Ok(XtbErrorCode::EX009),
164 "EX010" => Ok(XtbErrorCode::EX010),
165 "EX011" => Ok(XtbErrorCode::EX011),
166 v @ ("BE020" | "BE021" | "BE022" | "BE023" | "BE024" | "BE025" | "BE026" | "BE027" | "BE028" | "BE029" | "BE030" | "BE031" | "BE032" | "BE033" | "BE034" | "BE035" | "BE036" | "BE037" | "BE099") => parse_other_error(v),
167 v if v.starts_with("SE") => parse_se_error(v),
168 v => Err(XtbErrorCodeError::UnsupportedErrorCode(v.to_owned())),
169 }
170 }
171}
172
173
174#[derive(Debug, PartialEq, Error)]
175pub enum XtbErrorCodeError {
176 #[error("The error code '{0}' is not supported by the 'xtb_client' library")]
177 UnsupportedErrorCode(String),
178}
179
180
181
182fn parse_other_error(err_str: &str) -> Result<XtbErrorCode, XtbErrorCodeError> {
183 if !err_str.starts_with("BE0") || err_str.len() != 5 {
184 Err(XtbErrorCodeError::UnsupportedErrorCode(err_str.to_owned()))
185 } else {
186 let digits = &err_str[3..];
187 let c = u8::from_str(digits).map_err(|_| XtbErrorCodeError::UnsupportedErrorCode(err_str.to_owned()))?;
188 Ok(XtbErrorCode::OtherError(c))
189 }
190}
191
192
193fn parse_se_error(err_str: &str) -> Result<XtbErrorCode, XtbErrorCodeError> {
194 if !err_str.starts_with("SE") || err_str.len() != 5 {
195 Err(XtbErrorCodeError::UnsupportedErrorCode(err_str.to_owned()))
196 } else {
197 let digits = &err_str[2..];
198 let c = u16::from_str(digits).map_err(|_| XtbErrorCodeError::UnsupportedErrorCode(err_str.to_owned()))?;
199 Ok(XtbErrorCode::InternalServerError(c))
200 }
201}
202
203
204impl fmt::Display for XtbErrorCode {
205 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
206 match *self {
207 XtbErrorCode::BE001 => f.write_str("BE001"),
208 XtbErrorCode::BE002 => f.write_str("BE002"),
209 XtbErrorCode::BE003 => f.write_str("BE003"),
210 XtbErrorCode::BE004 => f.write_str("BE004"),
211 XtbErrorCode::BE005 => f.write_str("BE005"),
212 XtbErrorCode::BE006 => f.write_str("BE006"),
213 XtbErrorCode::BE007 => f.write_str("BE007"),
214 XtbErrorCode::BE008 => f.write_str("BE008"),
215 XtbErrorCode::BE009 => f.write_str("BE009"),
216 XtbErrorCode::BE010 => f.write_str("BE010"),
217 XtbErrorCode::BE011 => f.write_str("BE011"),
218 XtbErrorCode::BE012 => f.write_str("BE012"),
219 XtbErrorCode::BE013 => f.write_str("BE013"),
220 XtbErrorCode::BE014 => f.write_str("BE014"),
221 XtbErrorCode::BE016 => f.write_str("BE016"),
222 XtbErrorCode::BE017 => f.write_str("BE017"),
223 XtbErrorCode::BE018 => f.write_str("BE018"),
224 XtbErrorCode::BE019 => f.write_str("BE019"),
225 XtbErrorCode::BE094 => f.write_str("BE094"),
226 XtbErrorCode::BE095 => f.write_str("BE095"),
227 XtbErrorCode::BE096 => f.write_str("BE096"),
228 XtbErrorCode::BE097 => f.write_str("BE097"),
229 XtbErrorCode::BE098 => f.write_str("BE098"),
230 XtbErrorCode::BE101 => f.write_str("BE101"),
231 XtbErrorCode::BE102 => f.write_str("BE102"),
232 XtbErrorCode::BE103 => f.write_str("BE103"),
233 XtbErrorCode::BE104 => f.write_str("BE104"),
234 XtbErrorCode::BE105 => f.write_str("BE105"),
235 XtbErrorCode::BE106 => f.write_str("BE106"),
236 XtbErrorCode::BE110 => f.write_str("BE110"),
237 XtbErrorCode::BE115 => f.write_str("BE115"),
238 XtbErrorCode::BE116 => f.write_str("BE116"),
239 XtbErrorCode::BE117 => f.write_str("BE117"),
240 XtbErrorCode::BE118 => f.write_str("BE118"),
241 XtbErrorCode::BE200 => f.write_str("BE200"),
242 XtbErrorCode::EX000 => f.write_str("EX000"),
243 XtbErrorCode::EX001 => f.write_str("EX001"),
244 XtbErrorCode::EX002 => f.write_str("EX002"),
245 XtbErrorCode::BE000 => f.write_str("BE000"),
246 XtbErrorCode::EX003 => f.write_str("EX003"),
247 XtbErrorCode::EX004 => f.write_str("EX004"),
248 XtbErrorCode::EX005 => f.write_str("EX005"),
249 XtbErrorCode::EX006 => f.write_str("EX006"),
250 XtbErrorCode::EX007 => f.write_str("EX007"),
251 XtbErrorCode::EX008 => f.write_str("EX008"),
252 XtbErrorCode::EX009 => f.write_str("EX009"),
253 XtbErrorCode::EX010 => f.write_str("EX010"),
254 XtbErrorCode::EX011 => f.write_str("EX011"),
255 XtbErrorCode::OtherError(c) => f.write_str(&format!("BE{:03}", c)),
256 XtbErrorCode::InternalServerError(c) => f.write_str(&format!("SE{:03}", c)),
257 }
258 }
259}
260
261
262#[cfg(test)]
263mod tests {
264 mod other_error_parser {
265 use rstest::rstest;
266
267 use crate::schema::api_errors::{parse_other_error, XtbErrorCode, XtbErrorCodeError};
268
269 #[rstest]
270 #[case("BE020", 20)]
271 #[case("BE021", 21)]
272 #[case("BE022", 22)]
273 #[case("BE023", 23)]
274 #[case("BE024", 24)]
275 #[case("BE025", 25)]
276 #[case("BE026", 26)]
277 #[case("BE027", 27)]
278 #[case("BE028", 28)]
279 #[case("BE029", 29)]
280 #[case("BE030", 30)]
281 #[case("BE031", 31)]
282 #[case("BE032", 32)]
283 #[case("BE033", 33)]
284 #[case("BE034", 34)]
285 #[case("BE035", 35)]
286 #[case("BE036", 36)]
287 #[case("BE037", 37)]
288 #[case("BE099", 99)]
289 fn parse_valid_value(#[case] input: &str, #[case] expected_code: u8) {
290 assert_eq!(parse_other_error(input), Ok(XtbErrorCode::OtherError(expected_code)));
291 }
292
293 #[rstest]
294 #[case("BE100")]
295 #[case("BE120")]
296 #[case("BEA20")]
297 #[case("BE030A")]
298 #[case("BE0300")]
299 fn parse_invalid_value(#[case] input: &str) {
300 assert_eq!(parse_other_error(input), Err(XtbErrorCodeError::UnsupportedErrorCode(input.to_owned())));
301 }
302 }
303
304 mod se_error_parser {
305 use rstest::rstest;
306
307 use crate::schema::api_errors::{parse_se_error, XtbErrorCode, XtbErrorCodeError};
308
309 #[rstest]
310 #[case("SE000", 0)]
311 #[case("SE099", 99)]
312 #[case("SE100", 100)]
313 #[case("SE555", 555)]
314 #[case("SE999", 999)]
315 fn parse_valid_value(#[case] input: &str, #[case] expected_code: u16) {
316 assert_eq!(parse_se_error(input), Ok(XtbErrorCode::InternalServerError(expected_code)));
317 }
318
319 #[rstest]
320 #[case("SEE000")]
321 #[case("SEABC")]
322 #[case("SE0000")]
323 fn parse_invalid_value(#[case] input: &str) {
324 assert_eq!(parse_se_error(input), Err(XtbErrorCodeError::UnsupportedErrorCode(input.to_owned())));
325 }
326 }
327
328 mod xtb_error_operations {
329 use std::str::FromStr;
330
331 use rstest::rstest;
332 use rstest_reuse::{self, *};
333 use serde_json::from_str;
334
335 use crate::schema::api_errors::XtbErrorCode;
336
337 #[template]
338 #[rstest]
339 #[case("BE001", XtbErrorCode::BE001)]
340 #[case("BE002", XtbErrorCode::BE002)]
341 #[case("BE003", XtbErrorCode::BE003)]
342 #[case("BE004", XtbErrorCode::BE004)]
343 #[case("BE005", XtbErrorCode::BE005)]
344 #[case("BE006", XtbErrorCode::BE006)]
345 #[case("BE007", XtbErrorCode::BE007)]
346 #[case("BE008", XtbErrorCode::BE008)]
347 #[case("BE009", XtbErrorCode::BE009)]
348 #[case("BE010", XtbErrorCode::BE010)]
349 #[case("BE011", XtbErrorCode::BE011)]
350 #[case("BE012", XtbErrorCode::BE012)]
351 #[case("BE013", XtbErrorCode::BE013)]
352 #[case("BE014", XtbErrorCode::BE014)]
353 #[case("BE016", XtbErrorCode::BE016)]
354 #[case("BE017", XtbErrorCode::BE017)]
355 #[case("BE018", XtbErrorCode::BE018)]
356 #[case("BE019", XtbErrorCode::BE019)]
357 #[case("BE094", XtbErrorCode::BE094)]
358 #[case("BE095", XtbErrorCode::BE095)]
359 #[case("BE096", XtbErrorCode::BE096)]
360 #[case("BE097", XtbErrorCode::BE097)]
361 #[case("BE098", XtbErrorCode::BE098)]
362 #[case("BE101", XtbErrorCode::BE101)]
363 #[case("BE102", XtbErrorCode::BE102)]
364 #[case("BE103", XtbErrorCode::BE103)]
365 #[case("BE104", XtbErrorCode::BE104)]
366 #[case("BE105", XtbErrorCode::BE105)]
367 #[case("BE106", XtbErrorCode::BE106)]
368 #[case("BE110", XtbErrorCode::BE110)]
369 #[case("BE115", XtbErrorCode::BE115)]
370 #[case("BE116", XtbErrorCode::BE116)]
371 #[case("BE117", XtbErrorCode::BE117)]
372 #[case("BE118", XtbErrorCode::BE118)]
373 #[case("BE200", XtbErrorCode::BE200)]
374 #[case("EX000", XtbErrorCode::EX000)]
375 #[case("EX001", XtbErrorCode::EX001)]
376 #[case("EX002", XtbErrorCode::EX002)]
377 #[case("BE000", XtbErrorCode::BE000)]
378 #[case("EX003", XtbErrorCode::EX003)]
379 #[case("EX004", XtbErrorCode::EX004)]
380 #[case("EX005", XtbErrorCode::EX005)]
381 #[case("EX006", XtbErrorCode::EX006)]
382 #[case("EX007", XtbErrorCode::EX007)]
383 #[case("EX008", XtbErrorCode::EX008)]
384 #[case("EX009", XtbErrorCode::EX009)]
385 #[case("EX010", XtbErrorCode::EX010)]
386 #[case("EX011", XtbErrorCode::EX011)]
387
388 #[case("BE020", XtbErrorCode::OtherError(20u8))]
389 #[case("BE021", XtbErrorCode::OtherError(21u8))]
390 #[case("BE022", XtbErrorCode::OtherError(22u8))]
391 #[case("BE023", XtbErrorCode::OtherError(23u8))]
392 #[case("BE024", XtbErrorCode::OtherError(24u8))]
393 #[case("BE025", XtbErrorCode::OtherError(25u8))]
394 #[case("BE026", XtbErrorCode::OtherError(26u8))]
395 #[case("BE027", XtbErrorCode::OtherError(27u8))]
396 #[case("BE028", XtbErrorCode::OtherError(28u8))]
397 #[case("BE029", XtbErrorCode::OtherError(29u8))]
398 #[case("BE030", XtbErrorCode::OtherError(30u8))]
399 #[case("BE031", XtbErrorCode::OtherError(31u8))]
400 #[case("BE032", XtbErrorCode::OtherError(32u8))]
401 #[case("BE033", XtbErrorCode::OtherError(33u8))]
402 #[case("BE034", XtbErrorCode::OtherError(34u8))]
403 #[case("BE035", XtbErrorCode::OtherError(35u8))]
404 #[case("BE036", XtbErrorCode::OtherError(36u8))]
405 #[case("BE037", XtbErrorCode::OtherError(37u8))]
406 #[case("BE099", XtbErrorCode::OtherError(99u8))]
407
408 #[case("SE000", XtbErrorCode::InternalServerError(0u16))]
409 #[case("SE099", XtbErrorCode::InternalServerError(99u16))]
410 #[case("SE100", XtbErrorCode::InternalServerError(100u16))]
411 #[case("SE555", XtbErrorCode::InternalServerError(555u16))]
412 #[case("SE999", XtbErrorCode::InternalServerError(999u16))]
413 fn variant_test_template(#[case] input: &str, #[case] variant: XtbErrorCode) {}
414
415 #[apply(variant_test_template)]
416 fn parse_from_str(#[case] input: &str, #[case] variant: XtbErrorCode) {
417 assert_eq!(XtbErrorCode::from_str(input), Ok(variant))
418 }
419
420 #[apply(variant_test_template)]
421 fn convert_to_str(#[case] input: &str, #[case] variant: XtbErrorCode) {
422 assert_eq!(format!("{}", variant), input.to_owned())
423 }
424
425 #[apply(variant_test_template)]
426 fn deserialize(#[case] input: &str, #[case] variant: XtbErrorCode) {
427 let deserialized: XtbErrorCode = from_str(&format!("\"{}\"", input)).unwrap();
428 assert_eq!(deserialized, variant)
429 }
430 }
431}