1use serde::{Deserialize, Serialize};
7use thiserror::Error;
8
9pub type Result<T> = std::result::Result<T, ParseError>;
11
12#[derive(Debug, Error, Clone, Serialize, Deserialize)]
14pub enum ParseError {
15 #[error("Missing required block: {block} (at line {line}, column {column}): {message}")]
16 MissingRequiredBlock {
17 block: String,
18 message: String,
19 line: usize,
20 column: usize,
21 },
22
23 #[error("Invalid block format (at line {line}, column {column}): {message}")]
24 InvalidBlockFormat {
25 message: String,
26 line: usize,
27 column: usize,
28 },
29
30 #[error("Unknown block number: {block_number} (at line {line}, column {column})")]
31 UnknownBlockNumber {
32 block_number: String,
33 line: usize,
34 column: usize,
35 },
36
37 #[error("No blocks found in message: {message}")]
38 NoBlocksFound { message: String },
39
40 #[error("Field parse error: {tag} - {message}")]
41 FieldParseError { tag: String, message: String },
42
43 #[error("Unknown field: {tag} in block {block}")]
44 UnknownField { tag: String, block: String },
45
46 #[error("Invalid field format: {tag} (expected {expected}, got {actual})")]
47 InvalidFieldFormat {
48 tag: String,
49 expected: String,
50 actual: String,
51 },
52
53 #[error("Missing required field: {tag} for message type {message_type}")]
54 MissingRequiredField { tag: String, message_type: String },
55
56 #[error("Invalid field length: {tag} (max {max_length}, got {actual_length})")]
57 InvalidFieldLength {
58 tag: String,
59 max_length: usize,
60 actual_length: usize,
61 },
62
63 #[error("Invalid currency code: {code}")]
64 InvalidCurrencyCode { code: String },
65
66 #[error("Amount parse error: {message}")]
67 AmountParseError { message: String },
68
69 #[error("Date parse error: {message}")]
70 DateParseError { message: String },
71
72 #[error("Time parse error: {message}")]
73 TimeParseError { message: String },
74
75 #[error("Wrong message type: expected {expected}, got {actual}")]
76 WrongMessageType { expected: String, actual: String },
77
78 #[error("Unsupported message type: {message_type}")]
79 UnsupportedMessageType { message_type: String },
80
81 #[error("Invalid message structure: {message}")]
82 InvalidMessageStructure { message: String },
83
84 #[error("Regex error: {message}")]
85 RegexError { message: String },
86
87 #[error("IO error: {message}")]
88 IoError { message: String },
89
90 #[error("Serialization error: {message}")]
91 SerializationError { message: String },
92
93 #[error("Validation error: {message}")]
94 ValidationError { message: String },
95
96 #[error("Format rule error: {message}")]
97 FormatRuleError { message: String },
98
99 #[error("JSON error: {message}")]
100 JsonError { message: String },
101}
102
103#[derive(Debug, Error, Clone, Serialize, Deserialize)]
105pub enum FieldParseError {
106 #[error("Invalid field usage: {0}")]
107 InvalidUsage(String),
108
109 #[error("Unknown field option: {option} for field {tag}")]
110 UnknownOption { tag: String, option: String },
111
112 #[error("Invalid field option: {option} for field {field}. Valid options: {valid_options:?}")]
113 InvalidFieldOption {
114 field: String,
115 option: String,
116 valid_options: Vec<String>,
117 },
118
119 #[error("Invalid field length: {field} (max {max_length}, got {actual_length})")]
120 InvalidLength {
121 field: String,
122 max_length: usize,
123 actual_length: usize,
124 },
125
126 #[error("Invalid field format: {field} - {message}")]
127 InvalidFormat { field: String, message: String },
128
129 #[error("Missing required data: {field} - {message}")]
130 MissingData { field: String, message: String },
131
132 #[error("Parse error: {message}")]
133 ParseError { message: String },
134}
135
136#[derive(Debug, Error, Clone, Serialize, Deserialize)]
138pub enum ValidationError {
139 #[error("Validation failed for field {tag}: {message}")]
140 FieldValidationFailed { tag: String, message: String },
141
142 #[error("Format rule validation failed: {rule} - {message}")]
143 FormatRuleValidationFailed { rule: String, message: String },
144
145 #[error("Business rule validation failed: {rule} - {message}")]
146 BusinessRuleValidationFailed { rule: String, message: String },
147
148 #[error("Cross-field validation failed: fields {fields:?} - {message}")]
149 CrossFieldValidationFailed {
150 fields: Vec<String>,
151 message: String,
152 },
153
154 #[error("Message structure validation failed: {message}")]
155 MessageStructureValidationFailed { message: String },
156}
157
158impl From<regex::Error> for ParseError {
160 fn from(err: regex::Error) -> Self {
161 ParseError::RegexError {
162 message: err.to_string(),
163 }
164 }
165}
166
167impl From<std::io::Error> for ParseError {
169 fn from(err: std::io::Error) -> Self {
170 ParseError::IoError {
171 message: err.to_string(),
172 }
173 }
174}
175
176impl From<FieldParseError> for ParseError {
178 fn from(err: FieldParseError) -> Self {
179 ParseError::FieldParseError {
180 tag: "unknown".to_string(),
181 message: err.to_string(),
182 }
183 }
184}
185
186impl From<ValidationError> for ParseError {
188 fn from(err: ValidationError) -> Self {
189 ParseError::ValidationError {
190 message: err.to_string(),
191 }
192 }
193}
194
195impl From<serde_json::Error> for ParseError {
197 fn from(err: serde_json::Error) -> Self {
198 ParseError::JsonError {
199 message: err.to_string(),
200 }
201 }
202}
203
204impl ParseError {
206 pub fn missing_required_field(tag: &str) -> Self {
207 ParseError::MissingRequiredField {
208 tag: tag.to_string(),
209 message_type: "unknown".to_string(),
210 }
211 }
212
213 pub fn missing_required_field_for_type(tag: &str, message_type: &str) -> Self {
214 ParseError::MissingRequiredField {
215 tag: tag.to_string(),
216 message_type: message_type.to_string(),
217 }
218 }
219
220 pub fn invalid_field_format(tag: &str, expected: &str, actual: &str) -> Self {
221 ParseError::InvalidFieldFormat {
222 tag: tag.to_string(),
223 expected: expected.to_string(),
224 actual: actual.to_string(),
225 }
226 }
227
228 pub fn field_parse_error(tag: &str, message: &str) -> Self {
229 ParseError::FieldParseError {
230 tag: tag.to_string(),
231 message: message.to_string(),
232 }
233 }
234}
235
236impl FieldParseError {
237 pub fn invalid_length(field: &str, max_length: usize, actual_length: usize) -> Self {
238 FieldParseError::InvalidLength {
239 field: field.to_string(),
240 max_length,
241 actual_length,
242 }
243 }
244
245 pub fn invalid_format(field: &str, message: &str) -> Self {
246 FieldParseError::InvalidFormat {
247 field: field.to_string(),
248 message: message.to_string(),
249 }
250 }
251
252 pub fn missing_data(field: &str, message: &str) -> Self {
253 FieldParseError::MissingData {
254 field: field.to_string(),
255 message: message.to_string(),
256 }
257 }
258}
259
260impl ValidationError {
261 pub fn field_validation_failed(tag: &str, message: &str) -> Self {
262 ValidationError::FieldValidationFailed {
263 tag: tag.to_string(),
264 message: message.to_string(),
265 }
266 }
267
268 pub fn format_rule_validation_failed(rule: &str, message: &str) -> Self {
269 ValidationError::FormatRuleValidationFailed {
270 rule: rule.to_string(),
271 message: message.to_string(),
272 }
273 }
274
275 pub fn business_rule_validation_failed(rule: &str, message: &str) -> Self {
276 ValidationError::BusinessRuleValidationFailed {
277 rule: rule.to_string(),
278 message: message.to_string(),
279 }
280 }
281}
282
283#[derive(Debug, Clone, Serialize, Deserialize)]
285pub struct ErrorContext {
286 pub error: ParseError,
287 pub line: Option<usize>,
288 pub column: Option<usize>,
289 pub field_tag: Option<String>,
290 pub message_type: Option<String>,
291 pub raw_content: Option<String>,
292}
293
294impl ErrorContext {
295 pub fn new(error: ParseError) -> Self {
296 Self {
297 error,
298 line: None,
299 column: None,
300 field_tag: None,
301 message_type: None,
302 raw_content: None,
303 }
304 }
305
306 pub fn with_location(mut self, line: usize, column: usize) -> Self {
307 self.line = Some(line);
308 self.column = Some(column);
309 self
310 }
311
312 pub fn with_field(mut self, field_tag: String) -> Self {
313 self.field_tag = Some(field_tag);
314 self
315 }
316
317 pub fn with_message_type(mut self, message_type: String) -> Self {
318 self.message_type = Some(message_type);
319 self
320 }
321
322 pub fn with_raw_content(mut self, raw_content: String) -> Self {
323 self.raw_content = Some(raw_content);
324 self
325 }
326}
327
328#[derive(Debug, Clone, Serialize, Deserialize)]
330pub struct ErrorCollection {
331 pub errors: Vec<ErrorContext>,
332 pub warnings: Vec<String>,
333}
334
335impl ErrorCollection {
336 pub fn new() -> Self {
337 Self {
338 errors: Vec::new(),
339 warnings: Vec::new(),
340 }
341 }
342
343 pub fn add_error(&mut self, error: ErrorContext) {
344 self.errors.push(error);
345 }
346
347 pub fn add_warning(&mut self, warning: String) {
348 self.warnings.push(warning);
349 }
350
351 pub fn has_errors(&self) -> bool {
352 !self.errors.is_empty()
353 }
354
355 pub fn has_warnings(&self) -> bool {
356 !self.warnings.is_empty()
357 }
358
359 pub fn error_count(&self) -> usize {
360 self.errors.len()
361 }
362
363 pub fn warning_count(&self) -> usize {
364 self.warnings.len()
365 }
366}
367
368impl Default for ErrorCollection {
369 fn default() -> Self {
370 Self::new()
371 }
372}
373
374pub use ParseError as MTError;
377pub type MTResult<T> = Result<T>;
378
379#[cfg(test)]
380mod tests {
381 use super::*;
382
383 #[test]
384 fn test_error_creation() {
385 let error = ParseError::missing_required_field("20");
386 assert!(matches!(error, ParseError::MissingRequiredField { .. }));
387 }
388
389 #[test]
390 fn test_error_context() {
391 let error = ParseError::FieldParseError {
392 tag: "20".to_string(),
393 message: "Invalid format".to_string(),
394 };
395 let context = ErrorContext::new(error)
396 .with_location(5, 10)
397 .with_field("20".to_string())
398 .with_message_type("103".to_string());
399
400 assert_eq!(context.line, Some(5));
401 assert_eq!(context.column, Some(10));
402 assert_eq!(context.field_tag, Some("20".to_string()));
403 assert_eq!(context.message_type, Some("103".to_string()));
404 }
405
406 #[test]
407 fn test_error_collection() {
408 let mut collection = ErrorCollection::new();
409 assert!(!collection.has_errors());
410
411 let error = ErrorContext::new(ParseError::missing_required_field("20"));
412 collection.add_error(error);
413 collection.add_warning("This is a test warning".to_string());
414
415 assert!(collection.has_errors());
416 assert!(collection.has_warnings());
417 assert_eq!(collection.error_count(), 1);
418 assert_eq!(collection.warning_count(), 1);
419 }
420}