swift_mt_message/parser/
sequence_parser.rs1use crate::errors::Result;
11use std::collections::HashMap;
12
13pub type FieldMap = HashMap<String, Vec<(String, usize)>>;
15
16#[derive(Debug, Clone)]
18pub struct SequenceConfig {
19 pub sequence_b_marker: String,
21 pub sequence_c_fields: Vec<String>,
23 pub has_sequence_c: bool,
25}
26
27impl Default for SequenceConfig {
28 fn default() -> Self {
29 Self {
30 sequence_b_marker: "21".to_string(),
31 sequence_c_fields: vec![],
32 has_sequence_c: false,
33 }
34 }
35}
36
37#[derive(Debug)]
39pub struct ParsedSequences {
40 pub sequence_a: FieldMap,
42 pub sequence_b: FieldMap,
44 pub sequence_c: FieldMap,
46}
47
48pub fn split_into_sequences(fields: &FieldMap, config: &SequenceConfig) -> Result<ParsedSequences> {
50 let mut seq_a = HashMap::new();
51 let mut seq_b = HashMap::new();
52 let mut seq_c = HashMap::new();
53
54 let mut all_fields: Vec<(&str, &(String, usize))> = Vec::new();
56 for (tag, values) in fields {
57 for value in values {
58 all_fields.push((tag.as_str(), value));
59 }
60 }
61 all_fields.sort_by_key(|(_, (_, pos))| *pos);
62
63 let mut first_b_marker_pos = None;
65 let mut _last_b_marker_pos = None;
66
67 let secondary_marker = if config.sequence_b_marker == "23" {
69 Some("25")
70 } else {
71 None
72 };
73
74 let sequence_a_fields = ["72", "77E", "79"];
76
77 for (tag, (_, pos)) in &all_fields {
78 if is_sequence_b_marker(tag, &config.sequence_b_marker)
79 || (secondary_marker.is_some() && *tag == secondary_marker.unwrap())
80 {
81 if first_b_marker_pos.is_none() {
82 first_b_marker_pos = Some(*pos);
83 }
84 _last_b_marker_pos = Some(*pos);
85 }
86 }
87
88 let sequence_b_start_idx = all_fields.iter().position(|(tag, _)| {
91 is_sequence_b_marker(tag, &config.sequence_b_marker)
92 || (secondary_marker.is_some() && *tag == secondary_marker.unwrap())
93 });
94
95 let mut sequence_c_start_idx: Option<usize> = None;
99
100 if config.has_sequence_c && sequence_b_start_idx.is_some() {
101 if config.sequence_b_marker == "61" {
104 let seq_c_markers = config
107 .sequence_c_fields
108 .iter()
109 .filter(|f| *f != "86")
110 .collect::<Vec<_>>();
111
112 if let Some(seq_b_start) = sequence_b_start_idx {
113 for (i, (tag, _)) in all_fields.iter().enumerate().skip(seq_b_start) {
114 let base_tag = tag.trim_end_matches(char::is_alphabetic);
115 if seq_c_markers.iter().any(|marker| base_tag == *marker) {
116 sequence_c_start_idx = Some(i);
117 break;
118 }
119 }
120 }
121 } else {
122 let transaction_end_fields = ["59", "70", "71A", "77B", "36"];
125
126 let mut last_trans_end_idx: Option<usize> = None;
128 for (i, (tag, _)) in all_fields.iter().enumerate() {
129 let base_tag = tag.trim_end_matches(char::is_alphabetic);
130 if transaction_end_fields.contains(&base_tag) {
131 last_trans_end_idx = Some(i);
132 }
133 }
134
135 if let Some(last_end) = last_trans_end_idx {
137 for (i, (tag, _)) in all_fields.iter().enumerate().skip(last_end + 1) {
138 if config.sequence_c_fields.contains(&tag.to_string()) {
139 sequence_c_start_idx = Some(i);
140 break;
141 }
142 }
143 } else {
144 if let Some(seq_b_start) = sequence_b_start_idx {
147 for (i, (tag, _)) in all_fields.iter().enumerate().skip(seq_b_start) {
148 if config.sequence_c_fields.contains(&tag.to_string()) {
149 sequence_c_start_idx = Some(i);
150 break;
151 }
152 }
153 }
154 }
155 }
156 }
157
158 for (i, (tag, (value, pos))) in all_fields.iter().enumerate() {
160 if sequence_a_fields.contains(tag) {
162 seq_a
163 .entry(tag.to_string())
164 .or_insert_with(Vec::new)
165 .push((value.clone(), *pos));
166 continue;
167 }
168
169 if let Some(seq_b_start) = sequence_b_start_idx {
170 if i < seq_b_start {
171 seq_a
173 .entry(tag.to_string())
174 .or_insert_with(Vec::new)
175 .push((value.clone(), *pos));
176 } else if let Some(seq_c_start) = sequence_c_start_idx {
177 if i >= seq_c_start {
178 seq_c
180 .entry(tag.to_string())
181 .or_insert_with(Vec::new)
182 .push((value.clone(), *pos));
183 } else {
184 seq_b
186 .entry(tag.to_string())
187 .or_insert_with(Vec::new)
188 .push((value.clone(), *pos));
189 }
190 } else {
191 seq_b
193 .entry(tag.to_string())
194 .or_insert_with(Vec::new)
195 .push((value.clone(), *pos));
196 }
197 } else {
198 seq_a
200 .entry(tag.to_string())
201 .or_insert_with(Vec::new)
202 .push((value.clone(), *pos));
203 }
204 }
205
206 Ok(ParsedSequences {
207 sequence_a: seq_a,
208 sequence_b: seq_b,
209 sequence_c: seq_c,
210 })
211}
212
213pub fn parse_repetitive_sequence<T>(fields: &FieldMap, marker_field: &str) -> Result<Vec<FieldMap>>
215where
216 T: crate::SwiftMessageBody,
217{
218 let mut items = Vec::new();
219
220 let mut all_fields: Vec<(String, String, usize)> = Vec::new();
222 for (tag, values) in fields {
223 for (value, pos) in values {
224 all_fields.push((tag.clone(), value.clone(), *pos));
225 }
226 }
227 all_fields.sort_by_key(|(_, _, pos)| *pos);
228
229 let mut current_item_fields: HashMap<String, Vec<(String, usize)>> = HashMap::new();
231 let mut in_item = false;
232
233 for (tag, value, pos) in all_fields {
234 if is_sequence_b_marker(&tag, marker_field) {
236 if in_item && !current_item_fields.is_empty() {
238 items.push(current_item_fields.clone());
239 current_item_fields.clear();
240 }
241 in_item = true;
242 }
243
244 if in_item {
246 current_item_fields
247 .entry(tag)
248 .or_default()
249 .push((value, pos));
250 }
251 }
252
253 if in_item && !current_item_fields.is_empty() {
255 items.push(current_item_fields);
256 }
257
258 Ok(items)
259}
260
261fn is_sequence_b_marker(tag: &str, marker: &str) -> bool {
263 if tag == marker {
265 return true;
266 }
267
268 if marker == "21" && tag == "21" {
270 return true;
271 }
272
273 false
274}
275
276pub fn get_sequence_config(message_type: &str) -> SequenceConfig {
278 match message_type {
279 "MT101" => SequenceConfig {
280 sequence_b_marker: "21".to_string(),
281 sequence_c_fields: vec![],
282 has_sequence_c: false,
283 },
284 "MT104" => SequenceConfig {
285 sequence_b_marker: "21".to_string(),
286 sequence_c_fields: vec![
287 "32B".to_string(),
288 "19".to_string(),
289 "71F".to_string(),
290 "71G".to_string(),
291 "53".to_string(),
292 ],
293 has_sequence_c: true,
294 },
295 "MT107" => SequenceConfig {
296 sequence_b_marker: "21".to_string(),
297 sequence_c_fields: vec![],
298 has_sequence_c: false,
299 },
300 _ => SequenceConfig::default(),
301 }
302}