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(
206 "Failed to parse field {field_tag} of type {field_type} at line {position}: {original_error}"
207 )]
208 FieldParsingFailed {
209 field_tag: String,
211 field_type: String,
213 position: usize,
215 original_error: String,
217 },
218
219 #[error(
221 "Component parse error in field {field_tag}: {component_name} (index {component_index})"
222 )]
223 ComponentParseError {
224 field_tag: String,
226 component_index: usize,
228 component_name: String,
230 expected_format: String,
232 actual_value: String,
234 },
235
236 #[error("Invalid block {block} structure: {message}")]
238 InvalidBlockStructure {
239 block: String,
241 message: String,
243 },
244
245 #[error("Multiple parsing errors found ({} errors)", .0.len())]
247 MultipleErrors(Vec<ParseError>),
248}
249
250#[derive(Error, Debug, Clone, Serialize, Deserialize)]
252pub enum ValidationError {
253 #[error("Field {field_tag} format validation failed: {message}")]
254 FormatValidation { field_tag: String, message: String },
255
256 #[error("Field {field_tag} length validation failed: expected {expected}, got {actual}")]
257 LengthValidation {
258 field_tag: String,
259 expected: String,
260 actual: usize,
261 },
262
263 #[error("Field {field_tag} pattern validation failed: {message}")]
264 PatternValidation { field_tag: String, message: String },
265
266 #[error("Field {field_tag} value validation failed: {message}")]
267 ValueValidation { field_tag: String, message: String },
268
269 #[error("Business rule validation failed: {rule_name} - {message}")]
270 BusinessRuleValidation { rule_name: String, message: String },
271}
272
273#[derive(Error, Debug, Clone, Serialize, Deserialize)]
278pub enum SwiftValidationError {
279 #[error(transparent)]
282 Format(Box<SwiftFormatError>),
283
284 #[error(transparent)]
287 Business(Box<SwiftBusinessError>),
288
289 #[error(transparent)]
292 Content(Box<SwiftContentError>),
293
294 #[error(transparent)]
297 Relation(Box<SwiftRelationError>),
298
299 #[error(transparent)]
302 General(Box<SwiftGeneralError>),
303}
304
305#[derive(Error, Debug, Clone, Serialize, Deserialize)]
307#[error("Format Error {code}: Field {field} contains '{value}', expected {expected}. {message}")]
308pub struct SwiftFormatError {
309 pub code: String,
311 pub field: String,
313 pub value: String,
315 pub expected: String,
317 pub message: String,
319 pub context: Option<String>,
321}
322
323#[derive(Error, Debug, Clone, Serialize, Deserialize)]
325#[error("Business Rule Violation {code}: {message} (Field: {field})")]
326pub struct SwiftBusinessError {
327 pub code: String,
329 pub field: String,
331 pub related_fields: Vec<String>,
333 pub message: String,
335 pub rule_description: String,
337 pub context: Option<String>,
339}
340
341#[derive(Error, Debug, Clone, Serialize, Deserialize)]
343#[error("Content Validation Error {code}: {message} (Field: {field})")]
344pub struct SwiftContentError {
345 pub code: String,
347 pub field: String,
349 pub content: String,
351 pub message: String,
353 pub requirements: String,
355 pub context: Option<String>,
357}
358
359#[derive(Error, Debug, Clone, Serialize, Deserialize)]
361#[error("Relation Validation Error {code}: {message} (Field: {field})")]
362pub struct SwiftRelationError {
363 pub code: String,
365 pub field: String,
367 pub related_fields: Vec<String>,
369 pub instruction_context: Option<String>,
371 pub message: String,
373 pub rule_description: String,
375 pub context: Option<String>,
377}
378
379#[derive(Error, Debug, Clone, Serialize, Deserialize)]
381#[error("General Validation Error {code}: {message} (Field: {field})")]
382pub struct SwiftGeneralError {
383 pub code: String,
385 pub field: String,
387 pub value: String,
389 pub message: String,
391 pub category: Option<String>,
393 pub context: Option<String>,
395}
396
397impl From<std::io::Error> for ParseError {
398 fn from(err: std::io::Error) -> Self {
399 ParseError::IoError {
400 message: err.to_string(),
401 }
402 }
403}
404
405impl ParseError {
406 pub fn debug_report(&self) -> String {
408 match self {
409 ParseError::InvalidFieldFormat(err) => {
410 format!(
411 "Field Parsing Error:\n\
412 ├─ Field Tag: {}\n\
413 ├─ Component: {}\n\
414 ├─ Value: '{}'\n\
415 ├─ Expected Format: {}\n\
416 ├─ Position in Message: {}\n\
417 ├─ Details: {}\n\
418 └─ Hint: Check SWIFT format specification for field {}",
419 err.field_tag,
420 err.component_name,
421 err.value,
422 err.format_spec,
423 err.position
424 .map_or("unknown".to_string(), |p| p.to_string()),
425 err.inner_error,
426 err.field_tag
427 )
428 }
429 ParseError::MissingRequiredField {
430 field_tag,
431 field_name,
432 message_type,
433 position_in_block4,
434 } => {
435 format!(
436 "Missing Required Field:\n\
437 ├─ Field Tag: {}\n\
438 ├─ Field Name: {}\n\
439 ├─ Message Type: {}\n\
440 ├─ Expected Position: {}\n\
441 └─ Hint: {} requires field {} to be present",
442 field_tag,
443 field_name,
444 message_type,
445 position_in_block4.map_or("unknown".to_string(), |p| p.to_string()),
446 message_type,
447 field_tag
448 )
449 }
450 ParseError::ComponentParseError {
451 field_tag,
452 component_index,
453 component_name,
454 expected_format,
455 actual_value,
456 } => {
457 format!(
458 "Component Parse Error:\n\
459 ├─ Field Tag: {field_tag}\n\
460 ├─ Component: {component_name} (index {component_index})\n\
461 ├─ Expected Format: {expected_format}\n\
462 ├─ Actual Value: '{actual_value}'\n\
463 └─ Hint: Component '{component_name}' must match format '{expected_format}'"
464 )
465 }
466 ParseError::FieldParsingFailed {
467 field_tag,
468 field_type,
469 position,
470 original_error,
471 } => {
472 let line_num = if *position > 0xFFFF {
473 position >> 16
475 } else {
476 *position
478 };
479 format!(
480 "Field Parsing Failed:\n\
481 ├─ Field Tag: {field_tag}\n\
482 ├─ Field Type: {field_type}\n\
483 ├─ Line Number: {line_num}\n\
484 ├─ Error: {original_error}\n\
485 └─ Hint: Check the field value matches the expected type"
486 )
487 }
488 ParseError::InvalidBlockStructure { block, message } => {
489 format!(
490 "Block Structure Error:\n\
491 ├─ Block: {block}\n\
492 ├─ Error: {message}\n\
493 └─ Hint: Ensure block {block} follows SWIFT message structure"
494 )
495 }
496 ParseError::MultipleErrors(errors) => {
497 let mut output = format!("Multiple Parsing Errors ({} total):\n", errors.len());
498 for (idx, error) in errors.iter().enumerate() {
499 output.push_str(&format!("\n{}. {}\n", idx + 1, error.debug_report()));
500 }
501 output
502 }
503 _ => format!("{self}"),
505 }
506 }
507
508 pub fn brief_message(&self) -> String {
510 match self {
511 ParseError::InvalidFieldFormat(err) => {
512 format!(
513 "Field {} component '{}' format error",
514 err.field_tag, err.component_name
515 )
516 }
517 ParseError::MissingRequiredField {
518 field_tag,
519 message_type,
520 ..
521 } => {
522 format!("Required field {field_tag} missing in {message_type}")
523 }
524 ParseError::ComponentParseError {
525 field_tag,
526 component_name,
527 ..
528 } => {
529 format!("Field {field_tag} component '{component_name}' parse error")
530 }
531 ParseError::FieldParsingFailed {
532 field_tag,
533 field_type,
534 position,
535 ..
536 } => {
537 let line_num = if *position > 0xFFFF {
538 position >> 16
539 } else {
540 *position
541 };
542 format!("Field {field_tag} (type {field_type}) parsing failed at line {line_num}")
543 }
544 ParseError::InvalidBlockStructure { block, .. } => {
545 format!("Block {block} structure invalid")
546 }
547 ParseError::MultipleErrors(errors) => {
548 format!("{} parsing errors found", errors.len())
549 }
550 _ => self.to_string(),
551 }
552 }
553
554 pub fn format_with_context(&self, original_message: &str) -> String {
556 match self {
557 ParseError::FieldParsingFailed { position, .. } => {
558 let lines: Vec<&str> = original_message.lines().collect();
560 let line_num = if *position > 0xFFFF {
561 position >> 16
562 } else {
563 *position
564 };
565 let mut output = self.debug_report();
566
567 if line_num > 0 && line_num <= lines.len() {
568 output.push_str("\n\nContext:\n");
569 let start = line_num.saturating_sub(3);
571 let end = (line_num + 2).min(lines.len());
572
573 for (i, line) in lines.iter().enumerate().take(end).skip(start) {
574 if i == line_num - 1 {
575 output.push_str(&format!(">>> {} │ {}\n", i + 1, line));
576 } else {
577 output.push_str(&format!(" {} │ {}\n", i + 1, line));
578 }
579 }
580 }
581 output
582 }
583 ParseError::InvalidFieldFormat(err) if err.position.is_some() => {
584 let lines: Vec<&str> = original_message.lines().collect();
585 let pos = err.position.unwrap();
586 let line_num = pos >> 16;
587 let mut output = self.debug_report();
588
589 if line_num > 0 && line_num <= lines.len() {
590 output.push_str("\n\nContext:\n");
591 let start = line_num.saturating_sub(3);
592 let end = (line_num + 2).min(lines.len());
593
594 for (i, line) in lines.iter().enumerate().take(end).skip(start) {
595 if i == line_num - 1 {
596 output.push_str(&format!(">>> {} │ {}\n", i + 1, line));
597 } else {
598 output.push_str(&format!(" {} │ {}\n", i + 1, line));
599 }
600 }
601 }
602 output
603 }
604 _ => self.debug_report(),
605 }
606 }
607}
608
609impl From<serde_json::Error> for ParseError {
610 fn from(err: serde_json::Error) -> Self {
611 ParseError::SerializationError {
612 message: err.to_string(),
613 }
614 }
615}
616
617pub mod error_codes {
622 pub mod format {
624 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"; }
638
639 pub mod business {
641 pub const C02: &str = "C02"; pub const C03: &str = "C03"; pub const C08: &str = "C08"; pub const C81: &str = "C81"; }
647
648 pub mod content {
650 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"; }
663
664 pub mod relation {
666 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"; }
684
685 pub mod general {
687 pub const G001: &str = "G001"; pub const G050: &str = "G050"; pub const G100: &str = "G100"; }
692}
693
694impl SwiftValidationError {
696 pub fn format_error(
698 code: &str,
699 field: &str,
700 value: &str,
701 expected: &str,
702 message: &str,
703 ) -> Self {
704 SwiftValidationError::Format(Box::new(SwiftFormatError {
705 code: code.to_string(),
706 field: field.to_string(),
707 value: value.to_string(),
708 expected: expected.to_string(),
709 message: message.to_string(),
710 context: None,
711 }))
712 }
713
714 pub fn business_error(
716 code: &str,
717 field: &str,
718 related_fields: Vec<String>,
719 message: &str,
720 rule_description: &str,
721 ) -> Self {
722 SwiftValidationError::Business(Box::new(SwiftBusinessError {
723 code: code.to_string(),
724 field: field.to_string(),
725 related_fields,
726 message: message.to_string(),
727 rule_description: rule_description.to_string(),
728 context: None,
729 }))
730 }
731
732 pub fn content_error(
734 code: &str,
735 field: &str,
736 content: &str,
737 message: &str,
738 requirements: &str,
739 ) -> Self {
740 SwiftValidationError::Content(Box::new(SwiftContentError {
741 code: code.to_string(),
742 field: field.to_string(),
743 content: content.to_string(),
744 message: message.to_string(),
745 requirements: requirements.to_string(),
746 context: None,
747 }))
748 }
749
750 pub fn relation_error(
752 code: &str,
753 field: &str,
754 related_fields: Vec<String>,
755 message: &str,
756 rule_description: &str,
757 ) -> Self {
758 SwiftValidationError::Relation(Box::new(SwiftRelationError {
759 code: code.to_string(),
760 field: field.to_string(),
761 related_fields,
762 instruction_context: None,
763 message: message.to_string(),
764 rule_description: rule_description.to_string(),
765 context: None,
766 }))
767 }
768
769 pub fn general_error(
771 code: &str,
772 field: &str,
773 value: &str,
774 message: &str,
775 category: Option<&str>,
776 ) -> Self {
777 SwiftValidationError::General(Box::new(SwiftGeneralError {
778 code: code.to_string(),
779 field: field.to_string(),
780 value: value.to_string(),
781 message: message.to_string(),
782 category: category.map(|s| s.to_string()),
783 context: None,
784 }))
785 }
786
787 pub fn code(&self) -> &str {
789 match self {
790 SwiftValidationError::Format(err) => &err.code,
791 SwiftValidationError::Business(err) => &err.code,
792 SwiftValidationError::Content(err) => &err.code,
793 SwiftValidationError::Relation(err) => &err.code,
794 SwiftValidationError::General(err) => &err.code,
795 }
796 }
797
798 pub fn field(&self) -> &str {
800 match self {
801 SwiftValidationError::Format(err) => &err.field,
802 SwiftValidationError::Business(err) => &err.field,
803 SwiftValidationError::Content(err) => &err.field,
804 SwiftValidationError::Relation(err) => &err.field,
805 SwiftValidationError::General(err) => &err.field,
806 }
807 }
808
809 pub fn message(&self) -> &str {
811 match self {
812 SwiftValidationError::Format(err) => &err.message,
813 SwiftValidationError::Business(err) => &err.message,
814 SwiftValidationError::Content(err) => &err.message,
815 SwiftValidationError::Relation(err) => &err.message,
816 SwiftValidationError::General(err) => &err.message,
817 }
818 }
819}
820
821impl From<SwiftValidationError> for ValidationError {
823 fn from(swift_error: SwiftValidationError) -> Self {
824 match swift_error {
825 SwiftValidationError::Format(err) => ValidationError::FormatValidation {
826 field_tag: err.field,
827 message: format!("{}: {}", err.code, err.message),
828 },
829 SwiftValidationError::Business(err) => ValidationError::BusinessRuleValidation {
830 rule_name: err.code,
831 message: err.message,
832 },
833 SwiftValidationError::Content(err) => ValidationError::ValueValidation {
834 field_tag: err.field,
835 message: format!("{}: {}", err.code, err.message),
836 },
837 SwiftValidationError::Relation(err) => ValidationError::BusinessRuleValidation {
838 rule_name: err.code,
839 message: err.message,
840 },
841 SwiftValidationError::General(err) => ValidationError::FormatValidation {
842 field_tag: err.field,
843 message: format!("{}: {}", err.code, err.message),
844 },
845 }
846 }
847}
848
849impl From<SwiftValidationError> for ParseError {
851 fn from(validation_error: SwiftValidationError) -> Self {
852 ParseError::SwiftValidation(Box::new(validation_error))
853 }
854}
855
856impl From<ValidationError> for SwiftValidationError {
858 fn from(validation_error: ValidationError) -> Self {
859 match validation_error {
860 ValidationError::FormatValidation { field_tag, message } => {
861 SwiftValidationError::format_error("T00", &field_tag, "", "", &message)
862 }
863 ValidationError::LengthValidation {
864 field_tag,
865 expected,
866 actual,
867 } => SwiftValidationError::format_error(
868 "T00",
869 &field_tag,
870 &actual.to_string(),
871 &expected,
872 "Length validation failed",
873 ),
874 ValidationError::PatternValidation { field_tag, message } => {
875 SwiftValidationError::format_error("T00", &field_tag, "", "", &message)
876 }
877 ValidationError::ValueValidation { field_tag, message } => {
878 SwiftValidationError::content_error("D00", &field_tag, "", &message, "")
879 }
880 ValidationError::BusinessRuleValidation { rule_name, message } => {
881 SwiftValidationError::business_error(&rule_name, "", vec![], &message, "")
882 }
883 }
884 }
885}