swift_mt_message/
field_parser.rs

1//! Generic field parser and registry system for SWIFT MT fields
2//!
3//! This module provides the core field parsing infrastructure with a generic SwiftField trait
4//! that all field types implement, plus an extensible registry system for dynamic field parsing.
5
6use once_cell::sync::Lazy;
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9
10use crate::errors::{ParseError, Result, ValidationError};
11// Import the modular field implementations
12use crate::mt_models::fields::beneficiary::Field59;
13use crate::mt_models::fields::charges::{Field71A, Field71F};
14use crate::mt_models::fields::common::{
15    Field20, Field23B, Field32A, Field33B, Field70, Field72, Field77B,
16};
17use crate::mt_models::fields::institutions::{
18    Field52, Field53, Field54, Field55, Field56, Field57,
19};
20use crate::mt_models::fields::ordering_customer::Field50;
21use crate::mt_models::fields::{Field13C, Field23E, Field26T, Field36, Field51A, Field71G};
22
23/// Generic trait that all SWIFT fields must implement
24pub trait SwiftField: Clone + std::fmt::Debug + Serialize + for<'de> Deserialize<'de> {
25    /// The field tag (e.g., "20", "50A", "50K")
26    const TAG: &'static str;
27
28    /// Parse field content from raw string
29    fn parse(content: &str) -> Result<Self>
30    where
31        Self: Sized;
32
33    /// Serialize field back to SWIFT format
34    fn to_swift_string(&self) -> String;
35
36    /// Validate field content according to SWIFT rules
37    fn validate(&self, rules: &FormatRules) -> std::result::Result<(), ValidationError>;
38
39    /// Get field tag at runtime
40    fn tag(&self) -> &'static str {
41        Self::TAG
42    }
43
44    /// Get field options if any (e.g., "A", "K", "F" for field 50)
45    fn options() -> Vec<&'static str> {
46        vec![]
47    }
48
49    /// Check if field is mandatory for a specific message type
50    fn is_mandatory_for_message_type(message_type: &str) -> bool {
51        // Use centralized configuration by default
52        crate::utils::is_field_mandatory(Self::TAG, message_type)
53    }
54
55    /// Get field description for documentation/debugging
56    fn description() -> &'static str;
57}
58
59/// Container for all possible field types
60#[derive(Debug, Clone, Serialize, Deserialize)]
61pub enum SwiftFieldContainer {
62    Field13C(Field13C),
63    Field20(Field20),
64    Field23B(Field23B),
65    Field23E(Field23E),
66    Field26T(Field26T),
67    Field32A(Field32A),
68    Field33B(Field33B),
69    Field36(Field36),
70    Field50(Field50),
71    Field51A(Field51A),
72    Field52(Field52),
73    Field53(Field53),
74    Field54(Field54),
75    Field55(Field55),
76    Field56(Field56),
77    Field57(Field57),
78    Field59(Field59),
79    Field70(Field70),
80    Field71A(Field71A),
81    Field71F(Field71F),
82    Field71G(Field71G),
83    Field72(Field72),
84    Field77B(Field77B),
85    // Add more fields as needed
86    Unknown(UnknownField),
87}
88
89impl SwiftFieldContainer {
90    pub fn tag(&self) -> &str {
91        match self {
92            SwiftFieldContainer::Field13C(f) => f.tag(),
93            SwiftFieldContainer::Field20(f) => f.tag(),
94            SwiftFieldContainer::Field23B(f) => f.tag(),
95            SwiftFieldContainer::Field23E(f) => f.tag(),
96            SwiftFieldContainer::Field26T(f) => f.tag(),
97            SwiftFieldContainer::Field32A(f) => f.tag(),
98            SwiftFieldContainer::Field33B(f) => f.tag(),
99            SwiftFieldContainer::Field36(f) => f.tag(),
100            SwiftFieldContainer::Field50(f) => f.tag(),
101            SwiftFieldContainer::Field51A(f) => f.tag(),
102            SwiftFieldContainer::Field52(f) => f.tag(),
103            SwiftFieldContainer::Field53(f) => f.tag(),
104            SwiftFieldContainer::Field54(f) => f.tag(),
105            SwiftFieldContainer::Field55(f) => f.tag(),
106            SwiftFieldContainer::Field56(f) => f.tag(),
107            SwiftFieldContainer::Field57(f) => f.tag(),
108            SwiftFieldContainer::Field59(f) => f.tag(),
109            SwiftFieldContainer::Field70(f) => f.tag(),
110            SwiftFieldContainer::Field71A(f) => f.tag(),
111            SwiftFieldContainer::Field71F(f) => f.tag(),
112            SwiftFieldContainer::Field71G(f) => f.tag(),
113            SwiftFieldContainer::Field72(f) => f.tag(),
114            SwiftFieldContainer::Field77B(f) => f.tag(),
115            SwiftFieldContainer::Unknown(f) => &f.tag,
116        }
117    }
118
119    pub fn parse(tag: &str, content: &str) -> Result<Self> {
120        match tag {
121            "13C" => Ok(SwiftFieldContainer::Field13C(Field13C::parse(content)?)),
122            "20" => Ok(SwiftFieldContainer::Field20(Field20::parse(content)?)),
123            "23B" => Ok(SwiftFieldContainer::Field23B(Field23B::parse(content)?)),
124            "23E" => Ok(SwiftFieldContainer::Field23E(Field23E::parse(content)?)),
125            "26T" => Ok(SwiftFieldContainer::Field26T(Field26T::parse(content)?)),
126            "32A" => Ok(SwiftFieldContainer::Field32A(Field32A::parse(content)?)),
127            "33B" => Ok(SwiftFieldContainer::Field33B(Field33B::parse(content)?)),
128            "36" => Ok(SwiftFieldContainer::Field36(Field36::parse(content)?)),
129            tag if tag.starts_with("50") => {
130                Ok(SwiftFieldContainer::Field50(Field50::parse(tag, content)?))
131            }
132            "51A" => Ok(SwiftFieldContainer::Field51A(Field51A::parse(content)?)),
133            tag if tag.starts_with("52") => {
134                Ok(SwiftFieldContainer::Field52(Field52::parse(tag, content)?))
135            }
136            tag if tag.starts_with("53") => {
137                Ok(SwiftFieldContainer::Field53(Field53::parse(tag, content)?))
138            }
139            tag if tag.starts_with("54") => {
140                Ok(SwiftFieldContainer::Field54(Field54::parse(tag, content)?))
141            }
142            tag if tag.starts_with("55") => {
143                Ok(SwiftFieldContainer::Field55(Field55::parse(tag, content)?))
144            }
145            tag if tag.starts_with("56") => {
146                Ok(SwiftFieldContainer::Field56(Field56::parse(tag, content)?))
147            }
148            tag if tag.starts_with("57") => {
149                Ok(SwiftFieldContainer::Field57(Field57::parse(tag, content)?))
150            }
151            tag if tag.starts_with("59") => {
152                Ok(SwiftFieldContainer::Field59(Field59::parse(tag, content)?))
153            }
154            "70" => Ok(SwiftFieldContainer::Field70(Field70::parse(content)?)),
155            "71A" => Ok(SwiftFieldContainer::Field71A(Field71A::parse(content)?)),
156            "71F" => Ok(SwiftFieldContainer::Field71F(Field71F::parse(content)?)),
157            "71G" => Ok(SwiftFieldContainer::Field71G(Field71G::parse(content)?)),
158            "72" => Ok(SwiftFieldContainer::Field72(Field72::parse(content)?)),
159            "77B" => Ok(SwiftFieldContainer::Field77B(Field77B::parse(content)?)),
160            _ => {
161                // Try the registry first
162                if let Ok(container) = parse_field_from_registry(tag, content) {
163                    Ok(container)
164                } else {
165                    // Create unknown field as fallback
166                    Ok(SwiftFieldContainer::Unknown(UnknownField {
167                        tag: tag.to_string(),
168                        content: content.to_string(),
169                    }))
170                }
171            }
172        }
173    }
174
175    pub fn to_swift_string(&self) -> String {
176        match self {
177            SwiftFieldContainer::Field13C(f) => f.to_swift_string(),
178            SwiftFieldContainer::Field20(f) => f.to_swift_string(),
179            SwiftFieldContainer::Field23B(f) => f.to_swift_string(),
180            SwiftFieldContainer::Field23E(f) => f.to_swift_string(),
181            SwiftFieldContainer::Field26T(f) => f.to_swift_string(),
182            SwiftFieldContainer::Field32A(f) => f.to_swift_string(),
183            SwiftFieldContainer::Field33B(f) => f.to_swift_string(),
184            SwiftFieldContainer::Field36(f) => f.to_swift_string(),
185            SwiftFieldContainer::Field50(f) => f.to_swift_string(),
186            SwiftFieldContainer::Field51A(f) => f.to_swift_string(),
187            SwiftFieldContainer::Field52(f) => f.to_swift_string(),
188            SwiftFieldContainer::Field53(f) => f.to_swift_string(),
189            SwiftFieldContainer::Field54(f) => f.to_swift_string(),
190            SwiftFieldContainer::Field55(f) => f.to_swift_string(),
191            SwiftFieldContainer::Field56(f) => f.to_swift_string(),
192            SwiftFieldContainer::Field57(f) => f.to_swift_string(),
193            SwiftFieldContainer::Field59(f) => f.to_swift_string(),
194            SwiftFieldContainer::Field70(f) => f.to_swift_string(),
195            SwiftFieldContainer::Field71A(f) => f.to_swift_string(),
196            SwiftFieldContainer::Field71F(f) => f.to_swift_string(),
197            SwiftFieldContainer::Field71G(f) => f.to_swift_string(),
198            SwiftFieldContainer::Field72(f) => f.to_swift_string(),
199            SwiftFieldContainer::Field77B(f) => f.to_swift_string(),
200            SwiftFieldContainer::Unknown(f) => f.to_swift_string(),
201        }
202    }
203}
204
205/// Unknown field type for unsupported fields
206#[derive(Debug, Clone, Serialize, Deserialize)]
207pub struct UnknownField {
208    pub tag: String,
209    pub content: String,
210}
211
212impl UnknownField {
213    pub fn to_swift_string(&self) -> String {
214        format!(":{}:{}", self.tag, self.content)
215    }
216}
217
218// Import FormatRules from validator module
219pub use crate::validator::FormatRules;
220
221/// Field registry type
222type FieldParserFn = fn(&str) -> Result<SwiftFieldContainer>;
223
224/// Global field registry
225static FIELD_REGISTRY: Lazy<std::sync::Mutex<HashMap<String, FieldParserFn>>> =
226    Lazy::new(|| std::sync::Mutex::new(HashMap::new()));
227
228/// Register a custom field parser
229pub fn register_field_parser(tag: &str, parser: FieldParserFn) {
230    if let Ok(mut registry) = FIELD_REGISTRY.lock() {
231        registry.insert(tag.to_string(), parser);
232    }
233}
234
235/// Parse field using the registry
236pub fn parse_field_from_registry(tag: &str, content: &str) -> Result<SwiftFieldContainer> {
237    if let Ok(registry) = FIELD_REGISTRY.lock() {
238        if let Some(parser) = registry.get(tag) {
239            return parser(content);
240        }
241    }
242
243    Err(ParseError::UnknownField {
244        tag: tag.to_string(),
245        block: "4".to_string(),
246    })
247}
248
249/// Generic message structure
250#[derive(Debug, Clone, Serialize, Deserialize)]
251pub struct SwiftMessage {
252    pub message_type: String,
253    pub blocks: crate::tokenizer::SwiftMessageBlocks,
254    pub fields: HashMap<String, SwiftFieldContainer>,
255    pub field_order: Vec<String>, // Preserve field order
256}
257
258impl SwiftMessage {
259    /// Parse a generic SWIFT message
260    pub fn parse(raw_message: &str) -> Result<Self> {
261        let blocks = crate::tokenizer::extract_blocks(raw_message)?;
262        let message_type = crate::tokenizer::extract_message_type(&blocks)?;
263
264        let parsed_fields = if let Some(block4) = &blocks.block_4 {
265            crate::tokenizer::parse_block4_fields(block4)?
266        } else {
267            Vec::new()
268        };
269
270        let mut fields = HashMap::new();
271        let mut field_order = Vec::new();
272
273        for parsed_field in parsed_fields {
274            let field_container =
275                SwiftFieldContainer::parse(&parsed_field.tag, &parsed_field.content)?;
276            fields.insert(parsed_field.tag.clone(), field_container);
277            field_order.push(parsed_field.tag);
278        }
279
280        Ok(SwiftMessage {
281            message_type,
282            blocks,
283            fields,
284            field_order,
285        })
286    }
287
288    /// Get a specific field by tag
289    pub fn get_field(&self, tag: &str) -> Option<&SwiftFieldContainer> {
290        self.fields.get(tag)
291    }
292
293    /// Get all fields in order
294    pub fn get_all_fields(&self) -> Vec<&SwiftFieldContainer> {
295        self.field_order
296            .iter()
297            .filter_map(|tag| self.fields.get(tag))
298            .collect()
299    }
300
301    /// Validate the entire message
302    pub fn validate(&self, rules: &FormatRules) -> std::result::Result<(), ValidationError> {
303        for field in self.fields.values() {
304            match field {
305                SwiftFieldContainer::Field13C(f) => f.validate(rules)?,
306                SwiftFieldContainer::Field20(f) => f.validate(rules)?,
307                SwiftFieldContainer::Field23B(f) => f.validate(rules)?,
308                SwiftFieldContainer::Field23E(f) => f.validate(rules)?,
309                SwiftFieldContainer::Field26T(f) => f.validate(rules)?,
310                SwiftFieldContainer::Field32A(f) => f.validate(rules)?,
311                SwiftFieldContainer::Field33B(f) => f.validate(rules)?,
312                SwiftFieldContainer::Field36(f) => f.validate(rules)?,
313                SwiftFieldContainer::Field50(f) => f.validate(rules)?,
314                SwiftFieldContainer::Field51A(f) => f.validate(rules)?,
315                SwiftFieldContainer::Field52(f) => f.validate(rules)?,
316                SwiftFieldContainer::Field53(f) => f.validate(rules)?,
317                SwiftFieldContainer::Field54(f) => f.validate(rules)?,
318                SwiftFieldContainer::Field55(f) => f.validate(rules)?,
319                SwiftFieldContainer::Field56(f) => f.validate(rules)?,
320                SwiftFieldContainer::Field57(f) => f.validate(rules)?,
321                SwiftFieldContainer::Field59(f) => f.validate(rules)?,
322                SwiftFieldContainer::Field70(f) => f.validate(rules)?,
323                SwiftFieldContainer::Field71A(f) => f.validate(rules)?,
324                SwiftFieldContainer::Field71F(f) => f.validate(rules)?,
325                SwiftFieldContainer::Field71G(f) => f.validate(rules)?,
326                SwiftFieldContainer::Field72(f) => f.validate(rules)?,
327                SwiftFieldContainer::Field77B(f) => f.validate(rules)?,
328                SwiftFieldContainer::Unknown(_) => {} // Skip validation for unknown fields
329            }
330        }
331        Ok(())
332    }
333}
334
335#[cfg(test)]
336mod tests {
337    use super::*;
338
339    #[test]
340    fn test_field_container_parsing() {
341        let field = SwiftFieldContainer::parse("20", "TESTREF123").unwrap();
342        match field {
343            SwiftFieldContainer::Field20(f20) => {
344                assert_eq!(f20.transaction_reference, "TESTREF123");
345            }
346            _ => panic!("Expected Field20"),
347        }
348    }
349}