1use once_cell::sync::Lazy;
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9
10use crate::errors::{ParseError, Result, ValidationError};
11use 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
23pub trait SwiftField: Clone + std::fmt::Debug + Serialize + for<'de> Deserialize<'de> {
25 const TAG: &'static str;
27
28 fn parse(content: &str) -> Result<Self>
30 where
31 Self: Sized;
32
33 fn to_swift_string(&self) -> String;
35
36 fn validate(&self, rules: &FormatRules) -> std::result::Result<(), ValidationError>;
38
39 fn tag(&self) -> &'static str {
41 Self::TAG
42 }
43
44 fn options() -> Vec<&'static str> {
46 vec![]
47 }
48
49 fn is_mandatory_for_message_type(message_type: &str) -> bool {
51 crate::utils::is_field_mandatory(Self::TAG, message_type)
53 }
54
55 fn description() -> &'static str;
57}
58
59#[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 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 if let Ok(container) = parse_field_from_registry(tag, content) {
163 Ok(container)
164 } else {
165 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#[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
218pub use crate::validator::FormatRules;
220
221type FieldParserFn = fn(&str) -> Result<SwiftFieldContainer>;
223
224static FIELD_REGISTRY: Lazy<std::sync::Mutex<HashMap<String, FieldParserFn>>> =
226 Lazy::new(|| std::sync::Mutex::new(HashMap::new()));
227
228pub 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
235pub 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#[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>, }
257
258impl SwiftMessage {
259 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 pub fn get_field(&self, tag: &str) -> Option<&SwiftFieldContainer> {
290 self.fields.get(tag)
291 }
292
293 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 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(_) => {} }
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}