1use serde::{Deserialize, Serialize};
69use std::any::Any;
70use std::fmt::{self, Display, Formatter};
71use thiserror::Error;
72
73pub type Result<T> = std::result::Result<T, ParseError>;
78
79pub type SwiftValidationResult<T> = std::result::Result<T, SwiftValidationError>;
81
82#[derive(Debug, Serialize, Deserialize)]
84pub struct ParseErrorCollection {
85 pub errors: Vec<ParseError>,
87 #[serde(skip)]
89 pub partial_result: Option<Box<dyn Any>>,
90}
91
92#[derive(Debug, Clone)]
94pub struct FieldParseResult<T> {
95 pub value: Option<T>,
97 pub error: Option<ParseError>,
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize)]
103pub enum ParseResult<T> {
104 Success(T),
106 PartialSuccess(T, Vec<ParseError>),
108 Failure(Vec<ParseError>),
110}
111
112#[derive(Debug, Clone, Serialize, Deserialize)]
114pub struct ParserConfig {
115 pub fail_fast: bool,
117 pub validate_optional_fields: bool,
119 pub collect_all_errors: bool,
121}
122
123impl Default for ParserConfig {
124 fn default() -> Self {
125 Self {
126 fail_fast: false,
127 validate_optional_fields: true,
128 collect_all_errors: true,
129 }
130 }
131}
132
133impl Display for ParseErrorCollection {
134 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
135 writeln!(f, "Found {} parsing errors:", self.errors.len())?;
136 for (idx, error) in self.errors.iter().enumerate() {
137 writeln!(f, "\n{}. {}", idx + 1, error)?;
138 }
139 Ok(())
140 }
141}
142
143impl std::error::Error for ParseErrorCollection {}
144
145#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct InvalidFieldFormatError {
148 pub field_tag: String,
150 pub component_name: String,
152 pub value: String,
154 pub format_spec: String,
156 pub position: Option<usize>,
158 pub inner_error: String,
160}
161
162#[derive(Error, Debug, Clone, Serialize, Deserialize)]
164pub enum ParseError {
165 #[error("Wrong message type: expected {expected}, got {actual}")]
166 WrongMessageType { expected: String, actual: String },
167
168 #[error("Unsupported message type: {message_type}")]
169 UnsupportedMessageType { message_type: String },
170
171 #[error("Field validation failed: {errors:?}")]
172 ValidationFailed { errors: Vec<ValidationError> },
173
174 #[error("IO error: {message}")]
175 IoError { message: String },
176
177 #[error(transparent)]
178 SwiftValidation(Box<SwiftValidationError>),
179
180 #[error("Serialization error: {message}")]
181 SerializationError { message: String },
182
183 #[error("Invalid message format: {message}")]
185 InvalidFormat { message: String },
186
187 #[error("Invalid field format - Field: {}, Component: {}, Value: '{}', Expected: {}", .0.field_tag, .0.component_name, .0.value, .0.format_spec)]
189 InvalidFieldFormat(Box<InvalidFieldFormatError>),
190
191 #[error("Missing required field {field_tag} ({field_name}) in {message_type}")]
193 MissingRequiredField {
194 field_tag: String,
196 field_name: String,
198 message_type: String,
200 position_in_block4: Option<usize>,
202 },
203
204 #[error("Failed to parse field {field_tag} of type {field_type} at line {position}: {original_error}")]
206 FieldParsingFailed {
207 field_tag: String,
209 field_type: String,
211 position: usize,
213 original_error: String,
215 },
216
217 #[error(
219 "Component parse error in field {field_tag}: {component_name} (index {component_index})"
220 )]
221 ComponentParseError {
222 field_tag: String,
224 component_index: usize,
226 component_name: String,
228 expected_format: String,
230 actual_value: String,
232 },
233
234 #[error("Invalid block {block} structure: {message}")]
236 InvalidBlockStructure {
237 block: String,
239 message: String,
241 },
242
243 #[error("Multiple parsing errors found ({} errors)", .0.len())]
245 MultipleErrors(Vec<ParseError>),
246}
247
248#[derive(Error, Debug, Clone, Serialize, Deserialize)]
250pub enum ValidationError {
251 #[error("Field {field_tag} format validation failed: {message}")]
252 FormatValidation { field_tag: String, message: String },
253
254 #[error("Field {field_tag} length validation failed: expected {expected}, got {actual}")]
255 LengthValidation {
256 field_tag: String,
257 expected: String,
258 actual: usize,
259 },
260
261 #[error("Field {field_tag} pattern validation failed: {message}")]
262 PatternValidation { field_tag: String, message: String },
263
264 #[error("Field {field_tag} value validation failed: {message}")]
265 ValueValidation { field_tag: String, message: String },
266
267 #[error("Business rule validation failed: {rule_name} - {message}")]
268 BusinessRuleValidation { rule_name: String, message: String },
269}
270
271#[derive(Error, Debug, Clone, Serialize, Deserialize)]
276pub enum SwiftValidationError {
277 #[error(transparent)]
280 Format(Box<SwiftFormatError>),
281
282 #[error(transparent)]
285 Business(Box<SwiftBusinessError>),
286
287 #[error(transparent)]
290 Content(Box<SwiftContentError>),
291
292 #[error(transparent)]
295 Relation(Box<SwiftRelationError>),
296
297 #[error(transparent)]
300 General(Box<SwiftGeneralError>),
301}
302
303#[derive(Error, Debug, Clone, Serialize, Deserialize)]
305#[error("Format Error {code}: Field {field} contains '{value}', expected {expected}. {message}")]
306pub struct SwiftFormatError {
307 pub code: String,
309 pub field: String,
311 pub value: String,
313 pub expected: String,
315 pub message: String,
317 pub context: Option<String>,
319}
320
321#[derive(Error, Debug, Clone, Serialize, Deserialize)]
323#[error("Business Rule Violation {code}: {message} (Field: {field})")]
324pub struct SwiftBusinessError {
325 pub code: String,
327 pub field: String,
329 pub related_fields: Vec<String>,
331 pub message: String,
333 pub rule_description: String,
335 pub context: Option<String>,
337}
338
339#[derive(Error, Debug, Clone, Serialize, Deserialize)]
341#[error("Content Validation Error {code}: {message} (Field: {field})")]
342pub struct SwiftContentError {
343 pub code: String,
345 pub field: String,
347 pub content: String,
349 pub message: String,
351 pub requirements: String,
353 pub context: Option<String>,
355}
356
357#[derive(Error, Debug, Clone, Serialize, Deserialize)]
359#[error("Relation Validation Error {code}: {message} (Field: {field})")]
360pub struct SwiftRelationError {
361 pub code: String,
363 pub field: String,
365 pub related_fields: Vec<String>,
367 pub instruction_context: Option<String>,
369 pub message: String,
371 pub rule_description: String,
373 pub context: Option<String>,
375}
376
377#[derive(Error, Debug, Clone, Serialize, Deserialize)]
379#[error("General Validation Error {code}: {message} (Field: {field})")]
380pub struct SwiftGeneralError {
381 pub code: String,
383 pub field: String,
385 pub value: String,
387 pub message: String,
389 pub category: Option<String>,
391 pub context: Option<String>,
393}
394
395impl From<std::io::Error> for ParseError {
396 fn from(err: std::io::Error) -> Self {
397 ParseError::IoError {
398 message: err.to_string(),
399 }
400 }
401}
402
403impl ParseError {
404 pub fn debug_report(&self) -> String {
406 match self {
407 ParseError::InvalidFieldFormat(err) => {
408 format!(
409 "Field Parsing Error:\n\
410 ├─ Field Tag: {}\n\
411 ├─ Component: {}\n\
412 ├─ Value: '{}'\n\
413 ├─ Expected Format: {}\n\
414 ├─ Position in Message: {}\n\
415 ├─ Details: {}\n\
416 └─ Hint: Check SWIFT format specification for field {}",
417 err.field_tag,
418 err.component_name,
419 err.value,
420 err.format_spec,
421 err.position
422 .map_or("unknown".to_string(), |p| p.to_string()),
423 err.inner_error,
424 err.field_tag
425 )
426 }
427 ParseError::MissingRequiredField {
428 field_tag,
429 field_name,
430 message_type,
431 position_in_block4,
432 } => {
433 format!(
434 "Missing Required Field:\n\
435 ├─ Field Tag: {}\n\
436 ├─ Field Name: {}\n\
437 ├─ Message Type: {}\n\
438 ├─ Expected Position: {}\n\
439 └─ Hint: {} requires field {} to be present",
440 field_tag,
441 field_name,
442 message_type,
443 position_in_block4.map_or("unknown".to_string(), |p| p.to_string()),
444 message_type,
445 field_tag
446 )
447 }
448 ParseError::ComponentParseError {
449 field_tag,
450 component_index,
451 component_name,
452 expected_format,
453 actual_value,
454 } => {
455 format!(
456 "Component Parse Error:\n\
457 ├─ Field Tag: {field_tag}\n\
458 ├─ Component: {component_name} (index {component_index})\n\
459 ├─ Expected Format: {expected_format}\n\
460 ├─ Actual Value: '{actual_value}'\n\
461 └─ Hint: Component '{component_name}' must match format '{expected_format}'"
462 )
463 }
464 ParseError::FieldParsingFailed {
465 field_tag,
466 field_type,
467 position,
468 original_error,
469 } => {
470 let line_num = if *position > 0xFFFF {
471 position >> 16
473 } else {
474 *position
476 };
477 format!(
478 "Field Parsing Failed:\n\
479 ├─ Field Tag: {field_tag}\n\
480 ├─ Field Type: {field_type}\n\
481 ├─ Line Number: {line_num}\n\
482 ├─ Error: {original_error}\n\
483 └─ Hint: Check the field value matches the expected type"
484 )
485 }
486 ParseError::InvalidBlockStructure { block, message } => {
487 format!(
488 "Block Structure Error:\n\
489 ├─ Block: {block}\n\
490 ├─ Error: {message}\n\
491 └─ Hint: Ensure block {block} follows SWIFT message structure"
492 )
493 }
494 ParseError::MultipleErrors(errors) => {
495 let mut output = format!("Multiple Parsing Errors ({} total):\n", errors.len());
496 for (idx, error) in errors.iter().enumerate() {
497 output.push_str(&format!("\n{}. {}\n", idx + 1, error.debug_report()));
498 }
499 output
500 }
501 _ => format!("{self}"),
503 }
504 }
505
506 pub fn brief_message(&self) -> String {
508 match self {
509 ParseError::InvalidFieldFormat(err) => {
510 format!(
511 "Field {} component '{}' format error",
512 err.field_tag, err.component_name
513 )
514 }
515 ParseError::MissingRequiredField {
516 field_tag,
517 message_type,
518 ..
519 } => {
520 format!("Required field {field_tag} missing in {message_type}")
521 }
522 ParseError::ComponentParseError {
523 field_tag,
524 component_name,
525 ..
526 } => {
527 format!("Field {field_tag} component '{component_name}' parse error")
528 }
529 ParseError::FieldParsingFailed {
530 field_tag,
531 field_type,
532 position,
533 ..
534 } => {
535 let line_num = if *position > 0xFFFF {
536 position >> 16
537 } else {
538 *position
539 };
540 format!("Field {field_tag} (type {field_type}) parsing failed at line {line_num}")
541 }
542 ParseError::InvalidBlockStructure { block, .. } => {
543 format!("Block {block} structure invalid")
544 }
545 ParseError::MultipleErrors(errors) => {
546 format!("{} parsing errors found", errors.len())
547 }
548 _ => self.to_string(),
549 }
550 }
551
552 pub fn format_with_context(&self, original_message: &str) -> String {
554 match self {
555 ParseError::FieldParsingFailed { position, .. } => {
556 let lines: Vec<&str> = original_message.lines().collect();
558 let line_num = if *position > 0xFFFF {
559 position >> 16
560 } else {
561 *position
562 };
563 let mut output = self.debug_report();
564
565 if line_num > 0 && line_num <= lines.len() {
566 output.push_str("\n\nContext:\n");
567 let start = line_num.saturating_sub(3);
569 let end = (line_num + 2).min(lines.len());
570
571 for (i, line) in lines.iter().enumerate().take(end).skip(start) {
572 if i == line_num - 1 {
573 output.push_str(&format!(">>> {} │ {}\n", i + 1, line));
574 } else {
575 output.push_str(&format!(" {} │ {}\n", i + 1, line));
576 }
577 }
578 }
579 output
580 }
581 ParseError::InvalidFieldFormat(err) if err.position.is_some() => {
582 let lines: Vec<&str> = original_message.lines().collect();
583 let pos = err.position.unwrap();
584 let line_num = pos >> 16;
585 let mut output = self.debug_report();
586
587 if line_num > 0 && line_num <= lines.len() {
588 output.push_str("\n\nContext:\n");
589 let start = line_num.saturating_sub(3);
590 let end = (line_num + 2).min(lines.len());
591
592 for (i, line) in lines.iter().enumerate().take(end).skip(start) {
593 if i == line_num - 1 {
594 output.push_str(&format!(">>> {} │ {}\n", i + 1, line));
595 } else {
596 output.push_str(&format!(" {} │ {}\n", i + 1, line));
597 }
598 }
599 }
600 output
601 }
602 _ => self.debug_report(),
603 }
604 }
605}
606
607impl From<serde_json::Error> for ParseError {
608 fn from(err: serde_json::Error) -> Self {
609 ParseError::SerializationError {
610 message: err.to_string(),
611 }
612 }
613}
614
615pub mod error_codes {
620 pub mod format {
622 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"; }
636
637 pub mod business {
639 pub const C02: &str = "C02"; pub const C03: &str = "C03"; pub const C08: &str = "C08"; pub const C81: &str = "C81"; }
645
646 pub mod content {
648 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"; }
661
662 pub mod relation {
664 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"; }
682
683 pub mod general {
685 pub const G001: &str = "G001"; pub const G050: &str = "G050"; pub const G100: &str = "G100"; }
690}
691
692impl SwiftValidationError {
694 pub fn format_error(
696 code: &str,
697 field: &str,
698 value: &str,
699 expected: &str,
700 message: &str,
701 ) -> Self {
702 SwiftValidationError::Format(Box::new(SwiftFormatError {
703 code: code.to_string(),
704 field: field.to_string(),
705 value: value.to_string(),
706 expected: expected.to_string(),
707 message: message.to_string(),
708 context: None,
709 }))
710 }
711
712 pub fn business_error(
714 code: &str,
715 field: &str,
716 related_fields: Vec<String>,
717 message: &str,
718 rule_description: &str,
719 ) -> Self {
720 SwiftValidationError::Business(Box::new(SwiftBusinessError {
721 code: code.to_string(),
722 field: field.to_string(),
723 related_fields,
724 message: message.to_string(),
725 rule_description: rule_description.to_string(),
726 context: None,
727 }))
728 }
729
730 pub fn content_error(
732 code: &str,
733 field: &str,
734 content: &str,
735 message: &str,
736 requirements: &str,
737 ) -> Self {
738 SwiftValidationError::Content(Box::new(SwiftContentError {
739 code: code.to_string(),
740 field: field.to_string(),
741 content: content.to_string(),
742 message: message.to_string(),
743 requirements: requirements.to_string(),
744 context: None,
745 }))
746 }
747
748 pub fn relation_error(
750 code: &str,
751 field: &str,
752 related_fields: Vec<String>,
753 message: &str,
754 rule_description: &str,
755 ) -> Self {
756 SwiftValidationError::Relation(Box::new(SwiftRelationError {
757 code: code.to_string(),
758 field: field.to_string(),
759 related_fields,
760 instruction_context: None,
761 message: message.to_string(),
762 rule_description: rule_description.to_string(),
763 context: None,
764 }))
765 }
766
767 pub fn general_error(
769 code: &str,
770 field: &str,
771 value: &str,
772 message: &str,
773 category: Option<&str>,
774 ) -> Self {
775 SwiftValidationError::General(Box::new(SwiftGeneralError {
776 code: code.to_string(),
777 field: field.to_string(),
778 value: value.to_string(),
779 message: message.to_string(),
780 category: category.map(|s| s.to_string()),
781 context: None,
782 }))
783 }
784
785 pub fn code(&self) -> &str {
787 match self {
788 SwiftValidationError::Format(err) => &err.code,
789 SwiftValidationError::Business(err) => &err.code,
790 SwiftValidationError::Content(err) => &err.code,
791 SwiftValidationError::Relation(err) => &err.code,
792 SwiftValidationError::General(err) => &err.code,
793 }
794 }
795
796 pub fn field(&self) -> &str {
798 match self {
799 SwiftValidationError::Format(err) => &err.field,
800 SwiftValidationError::Business(err) => &err.field,
801 SwiftValidationError::Content(err) => &err.field,
802 SwiftValidationError::Relation(err) => &err.field,
803 SwiftValidationError::General(err) => &err.field,
804 }
805 }
806
807 pub fn message(&self) -> &str {
809 match self {
810 SwiftValidationError::Format(err) => &err.message,
811 SwiftValidationError::Business(err) => &err.message,
812 SwiftValidationError::Content(err) => &err.message,
813 SwiftValidationError::Relation(err) => &err.message,
814 SwiftValidationError::General(err) => &err.message,
815 }
816 }
817}
818
819impl From<SwiftValidationError> for ValidationError {
821 fn from(swift_error: SwiftValidationError) -> Self {
822 match swift_error {
823 SwiftValidationError::Format(err) => ValidationError::FormatValidation {
824 field_tag: err.field,
825 message: format!("{}: {}", err.code, err.message),
826 },
827 SwiftValidationError::Business(err) => ValidationError::BusinessRuleValidation {
828 rule_name: err.code,
829 message: err.message,
830 },
831 SwiftValidationError::Content(err) => ValidationError::ValueValidation {
832 field_tag: err.field,
833 message: format!("{}: {}", err.code, err.message),
834 },
835 SwiftValidationError::Relation(err) => ValidationError::BusinessRuleValidation {
836 rule_name: err.code,
837 message: err.message,
838 },
839 SwiftValidationError::General(err) => ValidationError::FormatValidation {
840 field_tag: err.field,
841 message: format!("{}: {}", err.code, err.message),
842 },
843 }
844 }
845}
846
847impl From<SwiftValidationError> for ParseError {
849 fn from(validation_error: SwiftValidationError) -> Self {
850 ParseError::SwiftValidation(Box::new(validation_error))
851 }
852}
853
854impl From<ValidationError> for SwiftValidationError {
856 fn from(validation_error: ValidationError) -> Self {
857 match validation_error {
858 ValidationError::FormatValidation { field_tag, message } => {
859 SwiftValidationError::format_error("T00", &field_tag, "", "", &message)
860 }
861 ValidationError::LengthValidation {
862 field_tag,
863 expected,
864 actual,
865 } => SwiftValidationError::format_error(
866 "T00",
867 &field_tag,
868 &actual.to_string(),
869 &expected,
870 "Length validation failed",
871 ),
872 ValidationError::PatternValidation { field_tag, message } => {
873 SwiftValidationError::format_error("T00", &field_tag, "", "", &message)
874 }
875 ValidationError::ValueValidation { field_tag, message } => {
876 SwiftValidationError::content_error("D00", &field_tag, "", &message, "")
877 }
878 ValidationError::BusinessRuleValidation { rule_name, message } => {
879 SwiftValidationError::business_error(&rule_name, "", vec![], &message, "")
880 }
881 }
882 }
883}