1use serde::{Deserialize, Serialize};
26use std::any::Any;
27use std::fmt::{self, Display, Formatter};
28use thiserror::Error;
29
30pub type Result<T> = std::result::Result<T, ParseError>;
35
36pub type SwiftValidationResult<T> = std::result::Result<T, SwiftValidationError>;
38
39#[derive(Debug, Serialize, Deserialize)]
41pub struct ParseErrorCollection {
42 pub errors: Vec<ParseError>,
44 #[serde(skip)]
46 pub partial_result: Option<Box<dyn Any>>,
47}
48
49#[derive(Debug, Clone)]
51pub struct FieldParseResult<T> {
52 pub value: Option<T>,
54 pub error: Option<ParseError>,
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize)]
60pub enum ParseResult<T> {
61 Success(T),
63 PartialSuccess(T, Vec<ParseError>),
65 Failure(Vec<ParseError>),
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct ParserConfig {
72 pub fail_fast: bool,
74 pub validate_optional_fields: bool,
76 pub collect_all_errors: bool,
78}
79
80impl Default for ParserConfig {
81 fn default() -> Self {
82 Self {
83 fail_fast: false,
84 validate_optional_fields: true,
85 collect_all_errors: true,
86 }
87 }
88}
89
90impl Display for ParseErrorCollection {
91 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
92 writeln!(f, "Found {} parsing errors:", self.errors.len())?;
93 for (idx, error) in self.errors.iter().enumerate() {
94 writeln!(f, "\n{}. {}", idx + 1, error)?;
95 }
96 Ok(())
97 }
98}
99
100impl std::error::Error for ParseErrorCollection {}
101
102#[derive(Debug, Clone, Serialize, Deserialize)]
104pub struct InvalidFieldFormatError {
105 pub field_tag: String,
107 pub component_name: String,
109 pub value: String,
111 pub format_spec: String,
113 pub position: Option<usize>,
115 pub inner_error: String,
117}
118
119#[derive(Error, Debug, Clone, Serialize, Deserialize)]
121pub enum ParseError {
122 #[error("Wrong message type: expected {expected}, got {actual}")]
123 WrongMessageType { expected: String, actual: String },
124
125 #[error("Unsupported message type: {message_type}")]
126 UnsupportedMessageType { message_type: String },
127
128 #[error("Field validation failed: {errors:?}")]
129 ValidationFailed { errors: Vec<ValidationError> },
130
131 #[error("IO error: {message}")]
132 IoError { message: String },
133
134 #[error(transparent)]
135 SwiftValidation(Box<SwiftValidationError>),
136
137 #[error("Serialization error: {message}")]
138 SerializationError { message: String },
139
140 #[error("Invalid message format: {message}")]
142 InvalidFormat { message: String },
143
144 #[error("Invalid field format - Field: {}, Component: {}, Value: '{}', Expected: {}", .0.field_tag, .0.component_name, .0.value, .0.format_spec)]
146 InvalidFieldFormat(Box<InvalidFieldFormatError>),
147
148 #[error("Missing required field {field_tag} ({field_name}) in {message_type}")]
150 MissingRequiredField {
151 field_tag: String,
153 field_name: String,
155 message_type: String,
157 position_in_block4: Option<usize>,
159 },
160
161 #[error(
163 "Failed to parse field {field_tag} of type {field_type} at line {position}: {original_error}"
164 )]
165 FieldParsingFailed {
166 field_tag: String,
168 field_type: String,
170 position: usize,
172 original_error: String,
174 },
175
176 #[error(
178 "Component parse error in field {field_tag}: {component_name} (index {component_index})"
179 )]
180 ComponentParseError {
181 field_tag: String,
183 component_index: usize,
185 component_name: String,
187 expected_format: String,
189 actual_value: String,
191 },
192
193 #[error("Invalid block {block} structure: {message}")]
195 InvalidBlockStructure {
196 block: String,
198 message: String,
200 },
201
202 #[error("Multiple parsing errors found ({} errors)", .0.len())]
204 MultipleErrors(Vec<ParseError>),
205}
206
207#[derive(Error, Debug, Clone, Serialize, Deserialize)]
209pub enum ValidationError {
210 #[error("Field {field_tag} format validation failed: {message}")]
211 FormatValidation { field_tag: String, message: String },
212
213 #[error("Field {field_tag} length validation failed: expected {expected}, got {actual}")]
214 LengthValidation {
215 field_tag: String,
216 expected: String,
217 actual: usize,
218 },
219
220 #[error("Field {field_tag} pattern validation failed: {message}")]
221 PatternValidation { field_tag: String, message: String },
222
223 #[error("Field {field_tag} value validation failed: {message}")]
224 ValueValidation { field_tag: String, message: String },
225
226 #[error("Business rule validation failed: {rule_name} - {message}")]
227 BusinessRuleValidation { rule_name: String, message: String },
228}
229
230#[derive(Error, Debug, Clone, Serialize, Deserialize)]
235pub enum SwiftValidationError {
236 #[error(transparent)]
239 Format(Box<SwiftFormatError>),
240
241 #[error(transparent)]
244 Business(Box<SwiftBusinessError>),
245
246 #[error(transparent)]
249 Content(Box<SwiftContentError>),
250
251 #[error(transparent)]
254 Relation(Box<SwiftRelationError>),
255
256 #[error(transparent)]
259 General(Box<SwiftGeneralError>),
260}
261
262#[derive(Error, Debug, Clone, Serialize, Deserialize)]
264#[error("Format Error {code}: Field {field} contains '{value}', expected {expected}. {message}")]
265pub struct SwiftFormatError {
266 pub code: String,
268 pub field: String,
270 pub value: String,
272 pub expected: String,
274 pub message: String,
276 pub context: Option<String>,
278}
279
280#[derive(Error, Debug, Clone, Serialize, Deserialize)]
282#[error("Business Rule Violation {code}: {message} (Field: {field})")]
283pub struct SwiftBusinessError {
284 pub code: String,
286 pub field: String,
288 pub related_fields: Vec<String>,
290 pub message: String,
292 pub rule_description: String,
294 pub context: Option<String>,
296}
297
298#[derive(Error, Debug, Clone, Serialize, Deserialize)]
300#[error("Content Validation Error {code}: {message} (Field: {field})")]
301pub struct SwiftContentError {
302 pub code: String,
304 pub field: String,
306 pub content: String,
308 pub message: String,
310 pub requirements: String,
312 pub context: Option<String>,
314}
315
316#[derive(Error, Debug, Clone, Serialize, Deserialize)]
318#[error("Relation Validation Error {code}: {message} (Field: {field})")]
319pub struct SwiftRelationError {
320 pub code: String,
322 pub field: String,
324 pub related_fields: Vec<String>,
326 pub instruction_context: Option<String>,
328 pub message: String,
330 pub rule_description: String,
332 pub context: Option<String>,
334}
335
336#[derive(Error, Debug, Clone, Serialize, Deserialize)]
338#[error("General Validation Error {code}: {message} (Field: {field})")]
339pub struct SwiftGeneralError {
340 pub code: String,
342 pub field: String,
344 pub value: String,
346 pub message: String,
348 pub category: Option<String>,
350 pub context: Option<String>,
352}
353
354impl From<std::io::Error> for ParseError {
355 fn from(err: std::io::Error) -> Self {
356 ParseError::IoError {
357 message: err.to_string(),
358 }
359 }
360}
361
362impl ParseError {
363 pub fn debug_report(&self) -> String {
365 match self {
366 ParseError::InvalidFieldFormat(err) => {
367 format!(
368 "Field Parsing Error:\n\
369 ├─ Field Tag: {}\n\
370 ├─ Component: {}\n\
371 ├─ Value: '{}'\n\
372 ├─ Expected Format: {}\n\
373 ├─ Position in Message: {}\n\
374 ├─ Details: {}\n\
375 └─ Hint: Check SWIFT format specification for field {}",
376 err.field_tag,
377 err.component_name,
378 err.value,
379 err.format_spec,
380 err.position
381 .map_or("unknown".to_string(), |p| p.to_string()),
382 err.inner_error,
383 err.field_tag
384 )
385 }
386 ParseError::MissingRequiredField {
387 field_tag,
388 field_name,
389 message_type,
390 position_in_block4,
391 } => {
392 format!(
393 "Missing Required Field:\n\
394 ├─ Field Tag: {}\n\
395 ├─ Field Name: {}\n\
396 ├─ Message Type: {}\n\
397 ├─ Expected Position: {}\n\
398 └─ Hint: {} requires field {} to be present",
399 field_tag,
400 field_name,
401 message_type,
402 position_in_block4.map_or("unknown".to_string(), |p| p.to_string()),
403 message_type,
404 field_tag
405 )
406 }
407 ParseError::ComponentParseError {
408 field_tag,
409 component_index,
410 component_name,
411 expected_format,
412 actual_value,
413 } => {
414 format!(
415 "Component Parse Error:\n\
416 ├─ Field Tag: {field_tag}\n\
417 ├─ Component: {component_name} (index {component_index})\n\
418 ├─ Expected Format: {expected_format}\n\
419 ├─ Actual Value: '{actual_value}'\n\
420 └─ Hint: Component '{component_name}' must match format '{expected_format}'"
421 )
422 }
423 ParseError::FieldParsingFailed {
424 field_tag,
425 field_type,
426 position,
427 original_error,
428 } => {
429 let line_num = if *position > 0xFFFF {
430 position >> 16
432 } else {
433 *position
435 };
436 format!(
437 "Field Parsing Failed:\n\
438 ├─ Field Tag: {field_tag}\n\
439 ├─ Field Type: {field_type}\n\
440 ├─ Line Number: {line_num}\n\
441 ├─ Error: {original_error}\n\
442 └─ Hint: Check the field value matches the expected type"
443 )
444 }
445 ParseError::InvalidBlockStructure { block, message } => {
446 format!(
447 "Block Structure Error:\n\
448 ├─ Block: {block}\n\
449 ├─ Error: {message}\n\
450 └─ Hint: Ensure block {block} follows SWIFT message structure"
451 )
452 }
453 ParseError::MultipleErrors(errors) => {
454 let mut output = format!("Multiple Parsing Errors ({} total):\n", errors.len());
455 for (idx, error) in errors.iter().enumerate() {
456 output.push_str(&format!("\n{}. {}\n", idx + 1, error.debug_report()));
457 }
458 output
459 }
460 _ => format!("{self}"),
462 }
463 }
464
465 pub fn brief_message(&self) -> String {
467 match self {
468 ParseError::InvalidFieldFormat(err) => {
469 format!(
470 "Field {} component '{}' format error",
471 err.field_tag, err.component_name
472 )
473 }
474 ParseError::MissingRequiredField {
475 field_tag,
476 message_type,
477 ..
478 } => {
479 format!("Required field {field_tag} missing in {message_type}")
480 }
481 ParseError::ComponentParseError {
482 field_tag,
483 component_name,
484 ..
485 } => {
486 format!("Field {field_tag} component '{component_name}' parse error")
487 }
488 ParseError::FieldParsingFailed {
489 field_tag,
490 field_type,
491 position,
492 ..
493 } => {
494 let line_num = if *position > 0xFFFF {
495 position >> 16
496 } else {
497 *position
498 };
499 format!("Field {field_tag} (type {field_type}) parsing failed at line {line_num}")
500 }
501 ParseError::InvalidBlockStructure { block, .. } => {
502 format!("Block {block} structure invalid")
503 }
504 ParseError::MultipleErrors(errors) => {
505 format!("{} parsing errors found", errors.len())
506 }
507 _ => self.to_string(),
508 }
509 }
510
511 pub fn format_with_context(&self, original_message: &str) -> String {
513 match self {
514 ParseError::FieldParsingFailed { position, .. } => {
515 let lines: Vec<&str> = original_message.lines().collect();
517 let line_num = if *position > 0xFFFF {
518 position >> 16
519 } else {
520 *position
521 };
522 let mut output = self.debug_report();
523
524 if line_num > 0 && line_num <= lines.len() {
525 output.push_str("\n\nContext:\n");
526 let start = line_num.saturating_sub(3);
528 let end = (line_num + 2).min(lines.len());
529
530 for (i, line) in lines.iter().enumerate().take(end).skip(start) {
531 if i == line_num - 1 {
532 output.push_str(&format!(">>> {} │ {}\n", i + 1, line));
533 } else {
534 output.push_str(&format!(" {} │ {}\n", i + 1, line));
535 }
536 }
537 }
538 output
539 }
540 ParseError::InvalidFieldFormat(err) if err.position.is_some() => {
541 let lines: Vec<&str> = original_message.lines().collect();
542 let pos = err.position.unwrap();
543 let line_num = pos >> 16;
544 let mut output = self.debug_report();
545
546 if line_num > 0 && line_num <= lines.len() {
547 output.push_str("\n\nContext:\n");
548 let start = line_num.saturating_sub(3);
549 let end = (line_num + 2).min(lines.len());
550
551 for (i, line) in lines.iter().enumerate().take(end).skip(start) {
552 if i == line_num - 1 {
553 output.push_str(&format!(">>> {} │ {}\n", i + 1, line));
554 } else {
555 output.push_str(&format!(" {} │ {}\n", i + 1, line));
556 }
557 }
558 }
559 output
560 }
561 _ => self.debug_report(),
562 }
563 }
564}
565
566impl From<serde_json::Error> for ParseError {
567 fn from(err: serde_json::Error) -> Self {
568 ParseError::SerializationError {
569 message: err.to_string(),
570 }
571 }
572}
573
574pub mod error_codes {
579 pub mod format {
581 pub const T08: &str = "T08"; pub const T26: &str = "T26"; pub const T27: &str = "T27"; pub const T28: &str = "T28"; pub const T29: &str = "T29"; pub const T40: &str = "T40"; pub const T43: &str = "T43"; pub const T45: &str = "T45"; pub const T50: &str = "T50"; pub const T52: &str = "T52"; pub const T56: &str = "T56"; pub const T73: &str = "T73"; }
595
596 pub mod business {
598 pub const C02: &str = "C02"; pub const C03: &str = "C03"; pub const C08: &str = "C08"; pub const C81: &str = "C81"; }
604
605 pub mod content {
607 pub const D17: &str = "D17"; pub const D18: &str = "D18"; pub const D19: &str = "D19"; pub const D20: &str = "D20"; pub const D22: &str = "D22"; pub const D49: &str = "D49"; pub const D50: &str = "D50"; pub const D51: &str = "D51"; pub const D75: &str = "D75"; pub const D79: &str = "D79"; pub const D93: &str = "D93"; }
620
621 pub mod relation {
623 pub const E01: &str = "E01"; pub const E02: &str = "E02"; pub const E03: &str = "E03"; pub const E04: &str = "E04"; pub const E05: &str = "E05"; pub const E06: &str = "E06"; pub const E07: &str = "E07"; pub const E09: &str = "E09"; pub const E10: &str = "E10"; pub const E13: &str = "E13"; pub const E15: &str = "E15"; pub const E16: &str = "E16"; pub const E17: &str = "E17"; pub const E18: &str = "E18"; pub const E44: &str = "E44"; pub const E45: &str = "E45"; }
641
642 pub mod general {
644 pub const G001: &str = "G001"; pub const G050: &str = "G050"; pub const G100: &str = "G100"; }
649}
650
651impl SwiftValidationError {
653 pub fn error_code(&self) -> &str {
655 match self {
656 SwiftValidationError::Format(err) => &err.code,
657 SwiftValidationError::Business(err) => &err.code,
658 SwiftValidationError::Content(err) => &err.code,
659 SwiftValidationError::Relation(err) => &err.code,
660 SwiftValidationError::General(err) => &err.code,
661 }
662 }
663
664 pub fn format_error(
666 code: &str,
667 field: &str,
668 value: &str,
669 expected: &str,
670 message: &str,
671 ) -> Self {
672 SwiftValidationError::Format(Box::new(SwiftFormatError {
673 code: code.to_string(),
674 field: field.to_string(),
675 value: value.to_string(),
676 expected: expected.to_string(),
677 message: message.to_string(),
678 context: None,
679 }))
680 }
681
682 pub fn business_error(
684 code: &str,
685 field: &str,
686 related_fields: Vec<String>,
687 message: &str,
688 rule_description: &str,
689 ) -> Self {
690 SwiftValidationError::Business(Box::new(SwiftBusinessError {
691 code: code.to_string(),
692 field: field.to_string(),
693 related_fields,
694 message: message.to_string(),
695 rule_description: rule_description.to_string(),
696 context: None,
697 }))
698 }
699
700 pub fn content_error(
702 code: &str,
703 field: &str,
704 content: &str,
705 message: &str,
706 requirements: &str,
707 ) -> Self {
708 SwiftValidationError::Content(Box::new(SwiftContentError {
709 code: code.to_string(),
710 field: field.to_string(),
711 content: content.to_string(),
712 message: message.to_string(),
713 requirements: requirements.to_string(),
714 context: None,
715 }))
716 }
717
718 pub fn relation_error(
720 code: &str,
721 field: &str,
722 related_fields: Vec<String>,
723 message: &str,
724 rule_description: &str,
725 ) -> Self {
726 SwiftValidationError::Relation(Box::new(SwiftRelationError {
727 code: code.to_string(),
728 field: field.to_string(),
729 related_fields,
730 instruction_context: None,
731 message: message.to_string(),
732 rule_description: rule_description.to_string(),
733 context: None,
734 }))
735 }
736
737 pub fn general_error(
739 code: &str,
740 field: &str,
741 value: &str,
742 message: &str,
743 category: Option<&str>,
744 ) -> Self {
745 SwiftValidationError::General(Box::new(SwiftGeneralError {
746 code: code.to_string(),
747 field: field.to_string(),
748 value: value.to_string(),
749 message: message.to_string(),
750 category: category.map(|s| s.to_string()),
751 context: None,
752 }))
753 }
754
755 pub fn code(&self) -> &str {
757 match self {
758 SwiftValidationError::Format(err) => &err.code,
759 SwiftValidationError::Business(err) => &err.code,
760 SwiftValidationError::Content(err) => &err.code,
761 SwiftValidationError::Relation(err) => &err.code,
762 SwiftValidationError::General(err) => &err.code,
763 }
764 }
765
766 pub fn field(&self) -> &str {
768 match self {
769 SwiftValidationError::Format(err) => &err.field,
770 SwiftValidationError::Business(err) => &err.field,
771 SwiftValidationError::Content(err) => &err.field,
772 SwiftValidationError::Relation(err) => &err.field,
773 SwiftValidationError::General(err) => &err.field,
774 }
775 }
776
777 pub fn message(&self) -> &str {
779 match self {
780 SwiftValidationError::Format(err) => &err.message,
781 SwiftValidationError::Business(err) => &err.message,
782 SwiftValidationError::Content(err) => &err.message,
783 SwiftValidationError::Relation(err) => &err.message,
784 SwiftValidationError::General(err) => &err.message,
785 }
786 }
787}
788
789impl From<SwiftValidationError> for ValidationError {
791 fn from(swift_error: SwiftValidationError) -> Self {
792 match swift_error {
793 SwiftValidationError::Format(err) => ValidationError::FormatValidation {
794 field_tag: err.field,
795 message: format!("{}: {}", err.code, err.message),
796 },
797 SwiftValidationError::Business(err) => ValidationError::BusinessRuleValidation {
798 rule_name: err.code,
799 message: err.message,
800 },
801 SwiftValidationError::Content(err) => ValidationError::ValueValidation {
802 field_tag: err.field,
803 message: format!("{}: {}", err.code, err.message),
804 },
805 SwiftValidationError::Relation(err) => ValidationError::BusinessRuleValidation {
806 rule_name: err.code,
807 message: err.message,
808 },
809 SwiftValidationError::General(err) => ValidationError::FormatValidation {
810 field_tag: err.field,
811 message: format!("{}: {}", err.code, err.message),
812 },
813 }
814 }
815}
816
817impl From<SwiftValidationError> for ParseError {
819 fn from(validation_error: SwiftValidationError) -> Self {
820 ParseError::SwiftValidation(Box::new(validation_error))
821 }
822}
823
824impl From<ValidationError> for SwiftValidationError {
826 fn from(validation_error: ValidationError) -> Self {
827 match validation_error {
828 ValidationError::FormatValidation { field_tag, message } => {
829 SwiftValidationError::format_error("T00", &field_tag, "", "", &message)
830 }
831 ValidationError::LengthValidation {
832 field_tag,
833 expected,
834 actual,
835 } => SwiftValidationError::format_error(
836 "T00",
837 &field_tag,
838 &actual.to_string(),
839 &expected,
840 "Length validation failed",
841 ),
842 ValidationError::PatternValidation { field_tag, message } => {
843 SwiftValidationError::format_error("T00", &field_tag, "", "", &message)
844 }
845 ValidationError::ValueValidation { field_tag, message } => {
846 SwiftValidationError::content_error("D00", &field_tag, "", &message, "")
847 }
848 ValidationError::BusinessRuleValidation { rule_name, message } => {
849 SwiftValidationError::business_error(&rule_name, "", vec![], &message, "")
850 }
851 }
852 }
853}