1use std::collections::{HashMap, HashSet};
46
47use crate::errors::{ParseError, ParserConfig, Result, SwiftValidationError};
48use crate::headers::{ApplicationHeader, BasicHeader, Trailer, UserHeader};
49use crate::messages::{
50 MT101, MT103, MT104, MT107, MT110, MT111, MT112, MT190, MT191, MT192, MT196, MT199, MT200,
51 MT202, MT204, MT205, MT210, MT290, MT291, MT292, MT296, MT299, MT900, MT910, MT920, MT935,
52 MT940, MT941, MT942, MT950,
53};
54use crate::swift_error_codes::t_series;
55use crate::{ParsedSwiftMessage, SwiftMessage, SwiftMessageBody};
56
57type FieldParseResult = Result<HashMap<String, Vec<(String, usize)>>>;
62
63#[derive(Debug, Clone)]
65pub struct ParsingContext {
66 pub current_field: Option<String>,
68 pub current_component: Option<String>,
70 pub message_type: String,
72 pub original_message: String,
74}
75
76impl ParsingContext {
77 pub fn new(message_type: String, original_message: String) -> Self {
79 Self {
80 current_field: None,
81 current_component: None,
82 message_type,
83 original_message,
84 }
85 }
86
87 pub fn with_field(&self, field: String) -> Self {
89 let mut ctx = self.clone();
90 ctx.current_field = Some(field);
91 ctx.current_component = None;
92 ctx
93 }
94
95 pub fn with_component(&self, component: String) -> Self {
97 let mut ctx = self.clone();
98 ctx.current_component = Some(component);
99 ctx
100 }
101}
102
103#[derive(Debug, Clone)]
132pub struct FieldConsumptionTracker {
133 consumed_indices: HashMap<String, HashSet<usize>>,
135}
136
137impl Default for FieldConsumptionTracker {
138 fn default() -> Self {
139 Self::new()
140 }
141}
142
143impl FieldConsumptionTracker {
144 pub fn new() -> Self {
146 Self {
147 consumed_indices: HashMap::new(),
148 }
149 }
150
151 pub fn mark_consumed(&mut self, tag: &str, index: usize) {
153 use std::collections::hash_map::Entry;
155 match self.consumed_indices.entry(tag.to_string()) {
156 Entry::Occupied(mut e) => {
157 e.get_mut().insert(index);
158 }
159 Entry::Vacant(e) => {
160 let mut set = HashSet::new();
161 set.insert(index);
162 e.insert(set);
163 }
164 }
165 }
166
167 pub fn get_next_available<'a>(
169 &self,
170 tag: &str,
171 values: &'a [(String, usize)],
172 ) -> Option<(&'a str, usize)> {
173 let consumed_set = self.consumed_indices.get(tag);
174
175 values
177 .iter()
178 .find(|(_, pos)| consumed_set.is_none_or(|set| !set.contains(pos)))
179 .map(|(value, pos)| (value.as_str(), *pos))
180 }
181}
182
183pub fn find_field_with_variant_sequential_constrained(
202 fields: &HashMap<String, Vec<(String, usize)>>,
203 base_tag: &str,
204 tracker: &mut FieldConsumptionTracker,
205 valid_variants: Option<&[&str]>,
206) -> Option<(String, Option<String>, usize)> {
207 if let Some(values) = fields.get(base_tag)
209 && let Some((value, pos)) = tracker.get_next_available(base_tag, values)
210 {
211 tracker.mark_consumed(base_tag, pos);
212 return Some((value.to_string(), None, pos));
213 }
214
215 let mut variant_candidates: Vec<(&String, &Vec<(String, usize)>)> = fields
218 .iter()
219 .filter(|(tag, _)| {
220 tag.starts_with(base_tag)
221 && tag.len() == base_tag.len() + 1
222 && tag
223 .chars()
224 .last()
225 .is_some_and(|c| c.is_ascii_alphabetic() && c.is_ascii_uppercase())
226 })
227 .collect();
228
229 variant_candidates.sort_by_key(|(tag, values)| {
231 values
232 .iter()
233 .filter(|(_, pos)| {
234 tracker
235 .consumed_indices
236 .get(*tag)
237 .is_none_or(|set| !set.contains(pos))
238 })
239 .map(|(_, pos)| *pos)
240 .min()
241 .unwrap_or(usize::MAX)
242 });
243
244 for (tag, values) in variant_candidates {
245 let variant_char = tag.chars().last().unwrap();
246 let variant_str = variant_char.to_string();
247
248 if let Some(valid) = valid_variants
250 && !valid.contains(&variant_str.as_str())
251 {
252 continue; }
254
255 if let Some((value, pos)) = tracker.get_next_available(tag, values) {
256 tracker.mark_consumed(tag, pos);
257 return Some((value.to_string(), Some(variant_str), pos));
258 }
259 }
260
261 None
262}
263
264pub struct SwiftParser {
290 config: ParserConfig,
291}
292
293impl Default for SwiftParser {
294 fn default() -> Self {
295 Self::new()
296 }
297}
298
299impl SwiftParser {
300 pub fn new() -> Self {
302 Self {
303 config: ParserConfig::default(),
304 }
305 }
306
307 pub fn with_config(config: ParserConfig) -> Self {
309 Self { config }
310 }
311
312 pub fn parse_with_errors<T: SwiftMessageBody>(
314 &self,
315 raw_message: &str,
316 ) -> Result<crate::errors::ParseResult<SwiftMessage<T>>> {
317 let block1 = Self::extract_block(raw_message, 1)?;
318 let block2 = Self::extract_block(raw_message, 2)?;
319 let block3 = Self::extract_block(raw_message, 3)?;
320 let block4 = Self::extract_block(raw_message, 4)?;
321 let block5 = Self::extract_block(raw_message, 5)?;
322
323 let basic_header = BasicHeader::parse(&block1.unwrap_or_default())?;
325 let application_header = ApplicationHeader::parse(&block2.unwrap_or_default())?;
326 let user_header = block3.map(|b| UserHeader::parse(&b)).transpose()?;
327 let trailer = block5.map(|b| Trailer::parse(&b)).transpose()?;
328
329 let message_type = application_header.message_type.clone();
331
332 if message_type != T::message_type() {
334 return Err(ParseError::SwiftValidation(Box::new(
335 SwiftValidationError::format_error(
336 t_series::T03,
337 "MESSAGE_TYPE",
338 &message_type,
339 T::message_type(),
340 &format!(
341 "Message type mismatch: expected {}, got {}",
342 T::message_type(),
343 message_type
344 ),
345 ),
346 )));
347 }
348
349 let field_map_with_positions = Self::parse_block4_fields(&block4.unwrap_or_default())?;
351
352 let parse_result = T::from_fields_with_config(field_map_with_positions, &self.config)?;
354
355 match parse_result {
356 crate::errors::ParseResult::Success(fields) => {
357 Ok(crate::errors::ParseResult::Success(SwiftMessage {
358 basic_header,
359 application_header,
360 user_header,
361 trailer,
362 message_type,
363 fields,
364 }))
365 }
366 crate::errors::ParseResult::PartialSuccess(fields, errors) => {
367 Ok(crate::errors::ParseResult::PartialSuccess(
368 SwiftMessage {
369 basic_header,
370 application_header,
371 user_header,
372 trailer,
373 message_type,
374 fields,
375 },
376 errors,
377 ))
378 }
379 crate::errors::ParseResult::Failure(errors) => {
380 Ok(crate::errors::ParseResult::Failure(errors))
381 }
382 }
383 }
384 pub fn parse<T: SwiftMessageBody>(raw_message: &str) -> Result<SwiftMessage<T>> {
386 Self::new().parse_message(raw_message)
387 }
388
389 pub fn parse_message<T: SwiftMessageBody>(&self, raw_message: &str) -> Result<SwiftMessage<T>> {
391 let block1 = Self::extract_block(raw_message, 1)?;
392 let block2 = Self::extract_block(raw_message, 2)?;
393 let block3 = Self::extract_block(raw_message, 3)?;
394 let block4 = Self::extract_block(raw_message, 4)?;
395 let block5 = Self::extract_block(raw_message, 5)?;
396
397 let basic_header = BasicHeader::parse(&block1.unwrap_or_default())?;
399 let application_header = ApplicationHeader::parse(&block2.unwrap_or_default())?;
400 let user_header = block3.map(|b| UserHeader::parse(&b)).transpose()?;
401 let trailer = block5.map(|b| Trailer::parse(&b)).transpose()?;
402
403 let message_type = application_header.message_type.clone();
405
406 if message_type != T::message_type() {
408 return Err(ParseError::SwiftValidation(Box::new(
409 SwiftValidationError::format_error(
410 t_series::T03,
411 "MESSAGE_TYPE",
412 &message_type,
413 T::message_type(),
414 &format!(
415 "Message type mismatch: expected {}, got {}",
416 T::message_type(),
417 message_type
418 ),
419 ),
420 )));
421 }
422
423 let field_map_with_positions = Self::parse_block4_fields(&block4.unwrap_or_default())?;
425
426 let parse_result = T::from_fields_with_config(field_map_with_positions, &self.config)?;
428
429 match parse_result {
430 crate::errors::ParseResult::Success(fields) => Ok(SwiftMessage {
431 basic_header,
432 application_header,
433 user_header,
434 trailer,
435 message_type,
436 fields,
437 }),
438 crate::errors::ParseResult::PartialSuccess(fields, errors) => {
439 eprintln!("Warning: Parsed with {} non-critical errors", errors.len());
442 for error in &errors {
443 eprintln!(" - {error}");
444 }
445 Ok(SwiftMessage {
446 basic_header,
447 application_header,
448 user_header,
449 trailer,
450 message_type,
451 fields,
452 })
453 }
454 crate::errors::ParseResult::Failure(errors) => {
455 Err(ParseError::MultipleErrors(errors))
457 }
458 }
459 }
460
461 pub fn parse_auto(raw_message: &str) -> Result<ParsedSwiftMessage> {
463 Self::new().parse_message_auto(raw_message)
464 }
465
466 pub fn parse_message_auto(&self, raw_message: &str) -> Result<ParsedSwiftMessage> {
468 let block2 = Self::extract_block(raw_message, 2)?;
470
471 let application_header = ApplicationHeader::parse(&block2.unwrap_or_default())?;
473 let message_type = &application_header.message_type;
474
475 match message_type.as_str() {
477 "101" => {
478 let parsed = self.parse_message::<MT101>(raw_message)?;
479 Ok(ParsedSwiftMessage::MT101(Box::new(parsed)))
480 }
481 "103" => {
482 let parsed = self.parse_message::<MT103>(raw_message)?;
483 Ok(ParsedSwiftMessage::MT103(Box::new(parsed)))
484 }
485 "104" => {
486 let parsed = self.parse_message::<MT104>(raw_message)?;
487 Ok(ParsedSwiftMessage::MT104(Box::new(parsed)))
488 }
489 "107" => {
490 let parsed = self.parse_message::<MT107>(raw_message)?;
491 Ok(ParsedSwiftMessage::MT107(Box::new(parsed)))
492 }
493 "110" => {
494 let parsed = self.parse_message::<MT110>(raw_message)?;
495 Ok(ParsedSwiftMessage::MT110(Box::new(parsed)))
496 }
497 "111" => {
498 let parsed = self.parse_message::<MT111>(raw_message)?;
499 Ok(ParsedSwiftMessage::MT111(Box::new(parsed)))
500 }
501 "112" => {
502 let parsed = self.parse_message::<MT112>(raw_message)?;
503 Ok(ParsedSwiftMessage::MT112(Box::new(parsed)))
504 }
505 "190" => {
506 let parsed = self.parse_message::<MT190>(raw_message)?;
507 Ok(ParsedSwiftMessage::MT190(Box::new(parsed)))
508 }
509 "191" => {
510 let parsed = self.parse_message::<MT191>(raw_message)?;
511 Ok(ParsedSwiftMessage::MT191(Box::new(parsed)))
512 }
513 "200" => {
514 let parsed = self.parse_message::<MT200>(raw_message)?;
515 Ok(ParsedSwiftMessage::MT200(Box::new(parsed)))
516 }
517 "202" => {
518 let parsed = self.parse_message::<MT202>(raw_message)?;
519 Ok(ParsedSwiftMessage::MT202(Box::new(parsed)))
520 }
521 "204" => {
522 let parsed = self.parse_message::<MT204>(raw_message)?;
523 Ok(ParsedSwiftMessage::MT204(Box::new(parsed)))
524 }
525 "205" => {
526 let parsed = self.parse_message::<MT205>(raw_message)?;
527 Ok(ParsedSwiftMessage::MT205(Box::new(parsed)))
528 }
529 "210" => {
530 let parsed = self.parse_message::<MT210>(raw_message)?;
531 Ok(ParsedSwiftMessage::MT210(Box::new(parsed)))
532 }
533 "290" => {
534 let parsed = self.parse_message::<MT290>(raw_message)?;
535 Ok(ParsedSwiftMessage::MT290(Box::new(parsed)))
536 }
537 "291" => {
538 let parsed = self.parse_message::<MT291>(raw_message)?;
539 Ok(ParsedSwiftMessage::MT291(Box::new(parsed)))
540 }
541 "900" => {
542 let parsed = self.parse_message::<MT900>(raw_message)?;
543 Ok(ParsedSwiftMessage::MT900(Box::new(parsed)))
544 }
545 "910" => {
546 let parsed = self.parse_message::<MT910>(raw_message)?;
547 Ok(ParsedSwiftMessage::MT910(Box::new(parsed)))
548 }
549 "920" => {
550 let parsed = self.parse_message::<MT920>(raw_message)?;
551 Ok(ParsedSwiftMessage::MT920(Box::new(parsed)))
552 }
553 "935" => {
554 let parsed = self.parse_message::<MT935>(raw_message)?;
555 Ok(ParsedSwiftMessage::MT935(Box::new(parsed)))
556 }
557 "940" => {
558 let parsed = self.parse_message::<MT940>(raw_message)?;
559 Ok(ParsedSwiftMessage::MT940(Box::new(parsed)))
560 }
561 "941" => {
562 let parsed = self.parse_message::<MT941>(raw_message)?;
563 Ok(ParsedSwiftMessage::MT941(Box::new(parsed)))
564 }
565 "942" => {
566 let parsed = self.parse_message::<MT942>(raw_message)?;
567 Ok(ParsedSwiftMessage::MT942(Box::new(parsed)))
568 }
569 "950" => {
570 let parsed = self.parse_message::<MT950>(raw_message)?;
571 Ok(ParsedSwiftMessage::MT950(Box::new(parsed)))
572 }
573 "192" => {
574 let parsed = self.parse_message::<MT192>(raw_message)?;
575 Ok(ParsedSwiftMessage::MT192(Box::new(parsed)))
576 }
577 "196" => {
578 let parsed = self.parse_message::<MT196>(raw_message)?;
579 Ok(ParsedSwiftMessage::MT196(Box::new(parsed)))
580 }
581 "292" => {
582 let parsed = self.parse_message::<MT292>(raw_message)?;
583 Ok(ParsedSwiftMessage::MT292(Box::new(parsed)))
584 }
585 "296" => {
586 let parsed = self.parse_message::<MT296>(raw_message)?;
587 Ok(ParsedSwiftMessage::MT296(Box::new(parsed)))
588 }
589 "199" => {
590 let parsed = self.parse_message::<MT199>(raw_message)?;
591 Ok(ParsedSwiftMessage::MT199(Box::new(parsed)))
592 }
593 "299" => {
594 let parsed = self.parse_message::<MT299>(raw_message)?;
595 Ok(ParsedSwiftMessage::MT299(Box::new(parsed)))
596 }
597 _ => Err(ParseError::UnsupportedMessageType {
598 message_type: message_type.clone(),
599 }),
600 }
601 }
602
603 pub fn extract_block(raw_message: &str, block_index: u8) -> Result<Option<String>> {
605 if !(1..=5).contains(&block_index) {
607 return Err(ParseError::SwiftValidation(Box::new(
608 crate::errors::SwiftValidationError::format_error(
609 crate::swift_error_codes::t_series::T01,
610 "BLOCK_INDEX",
611 &block_index.to_string(),
612 "1-5",
613 &format!("Invalid block index: {block_index}"),
614 ),
615 )));
616 }
617
618 let block_marker = format!("{{{block_index}:");
619
620 if let Some(start) = raw_message.find(&block_marker) {
621 let content_start = start + block_marker.len();
622
623 match block_index {
624 1 | 2 => {
625 if let Some(end) = raw_message[start..].find('}') {
627 let end = start + end;
628 Ok(Some(raw_message[content_start..end].to_string()))
629 } else {
630 Ok(None)
631 }
632 }
633 3 | 5 => {
634 if let Some(end) = Self::find_matching_brace(&raw_message[start..]) {
636 let end = start + end;
637 Ok(Some(raw_message[content_start..end].to_string()))
638 } else {
639 Ok(None)
640 }
641 }
642 4 => {
643 if let Some(end) = raw_message[start..].find("-}") {
645 let end = start + end;
646 Ok(Some(raw_message[content_start..end].to_string()))
647 } else {
648 Ok(None)
649 }
650 }
651 _ => Err(ParseError::SwiftValidation(Box::new(
652 crate::errors::SwiftValidationError::format_error(
653 crate::swift_error_codes::t_series::T02,
654 "BLOCK",
655 &block_index.to_string(),
656 "1-5",
657 &format!("Invalid block index: {block_index}"),
658 ),
659 ))),
660 }
661 } else {
662 Ok(None)
663 }
664 }
665
666 fn parse_block4_fields(block4: &str) -> FieldParseResult {
668 crate::parser::parse_block4_fields(block4)
670 }
671
672 fn find_matching_brace(text: &str) -> Option<usize> {
675 let mut chars = text.char_indices();
676
677 let mut brace_count = if let Some((_, '{')) = chars.next() {
679 1
680 } else {
681 return None;
682 };
683
684 for (i, ch) in chars {
685 match ch {
686 '{' => brace_count += 1,
687 '}' => {
688 brace_count -= 1;
689 if brace_count == 0 {
690 return Some(i);
691 }
692 }
693 _ => {}
694 }
695 }
696
697 None
698 }
699}
700
701pub fn parse_swift_message_from_string(value: &str) -> Result<HashMap<String, Vec<String>>> {
704 let mut field_map = HashMap::new();
711
712 for line in value.lines() {
714 if line.trim().is_empty() {
715 continue;
716 }
717
718 if let Some(colon_pos) = line.find(':')
720 && let Some(second_colon) = line[colon_pos + 1..].find(':')
721 {
722 let second_colon_pos = colon_pos + 1 + second_colon;
723 let field_tag = line[colon_pos + 1..second_colon_pos].to_string();
724 let _field_value = line[second_colon_pos + 1..].to_string();
725
726 field_map
727 .entry(field_tag)
728 .or_insert_with(Vec::new)
729 .push(format!(":{}", &line[colon_pos + 1..]));
730 }
731 }
732
733 Ok(field_map)
734}
735
736pub fn parse_sequences<T>(
742 fields: &HashMap<String, Vec<(String, usize)>>,
743 tracker: &mut FieldConsumptionTracker,
744) -> Result<Vec<T>>
745where
746 T: crate::SwiftMessageBody,
747{
748 let message_type = std::any::type_name::<T>();
750
751 if message_type.contains("MT104Transaction") {
752 use crate::parser::sequence_parser::{get_sequence_config, split_into_sequences};
754
755 let config = get_sequence_config("MT104");
756 let parsed_sequences = split_into_sequences(fields, &config)?;
757
758 return parse_sequence_b_items::<T>(&parsed_sequences.sequence_b, tracker);
760 }
761
762 if message_type.contains("MT204Transaction") {
763 let field_20_count = fields.get("20").map(|v| v.len()).unwrap_or(0);
768 if field_20_count <= 1 {
769 return Ok(Vec::new()); }
771
772 let num_transactions = field_20_count - 1; let mut transactions = Vec::new();
776
777 for i in 0..num_transactions {
778 let mut tx_fields = HashMap::new();
779
780 if let Some(field_20_values) = fields.get("20")
782 && i + 1 < field_20_values.len()
783 {
784 tx_fields.insert("20".to_string(), vec![field_20_values[i + 1].clone()]);
785 }
786
787 if let Some(field_21_values) = fields.get("21")
789 && i < field_21_values.len()
790 {
791 tx_fields.insert("21".to_string(), vec![field_21_values[i].clone()]);
792 }
793
794 if let Some(field_32b_values) = fields.get("32B")
796 && i < field_32b_values.len()
797 {
798 tx_fields.insert("32B".to_string(), vec![field_32b_values[i].clone()]);
799 }
800
801 for variant in ["53", "53A", "53B", "53D"] {
803 if let Some(field_53_values) = fields.get(variant)
804 && i < field_53_values.len()
805 {
806 tx_fields.insert(variant.to_string(), vec![field_53_values[i].clone()]);
807 break; }
809 }
810
811 if let Some(field_72_values) = fields.get("72") {
813 if i + 2 < field_72_values.len() {
816 tx_fields.insert("72".to_string(), vec![field_72_values[i + 2].clone()]);
817 }
818 }
819
820 if let Ok(transaction) = T::from_fields(tx_fields) {
822 transactions.push(transaction);
823 }
824 }
825
826 return Ok(transactions);
827 }
828
829 let mut all_fields: Vec<(String, String, usize)> = Vec::new();
831 for (tag, values) in fields {
832 for (value, pos) in values {
833 if tracker
835 .consumed_indices
836 .get(tag)
837 .is_none_or(|set| !set.contains(pos))
838 {
839 all_fields.push((tag.clone(), value.clone(), *pos));
840 }
841 }
842 }
843 all_fields.sort_by_key(|(_, _, pos)| *pos);
844
845 let (primary_marker, secondary_marker) = if message_type.contains("MT920Sequence") {
847 ("12", None)
848 } else if message_type.contains("MT935RateChange") {
849 ("23", Some("25"))
850 } else if message_type.contains("MT940StatementLine")
851 || message_type.contains("MT942StatementLine")
852 {
853 ("61", None)
854 } else {
855 ("21", None)
856 };
857
858 let mut sequences = Vec::new();
859 let mut current_sequence_fields: HashMap<String, Vec<(String, usize)>> = HashMap::new();
860 let mut in_sequence = false;
861
862 for (tag, value, pos) in all_fields {
863 let is_sequence_start = (tag == primary_marker
865 || secondary_marker.is_some_and(|m| tag == m))
866 && !tag.ends_with("R")
867 && !tag.ends_with("F")
868 && !tag.ends_with("C")
869 && !tag.ends_with("D");
870
871 if is_sequence_start {
872 if in_sequence && !current_sequence_fields.is_empty() {
874 if let Ok(sequence_item) = T::from_fields(current_sequence_fields.clone()) {
875 sequences.push(sequence_item);
876 }
877 current_sequence_fields.clear();
878 }
879 in_sequence = true;
880 }
881
882 if in_sequence {
884 current_sequence_fields
885 .entry(tag.clone())
886 .or_default()
887 .push((value, pos));
888
889 tracker.mark_consumed(&tag, pos);
891 }
892 }
893
894 if in_sequence && !current_sequence_fields.is_empty() {
896 match T::from_fields(current_sequence_fields) {
897 Ok(sequence_item) => {
898 sequences.push(sequence_item);
899 }
900 Err(_e) => {
901 #[cfg(debug_assertions)]
902 eprintln!("DEBUG: Failed to parse final sequence item: {_e:?}");
903 }
904 }
905 }
906
907 Ok(sequences)
908}
909
910fn parse_sequence_b_items<T>(
912 fields: &HashMap<String, Vec<(String, usize)>>,
913 tracker: &mut FieldConsumptionTracker,
914) -> Result<Vec<T>>
915where
916 T: crate::SwiftMessageBody,
917{
918 let mut sequences = Vec::new();
919
920 let mut all_fields: Vec<(String, String, usize)> = Vec::new();
922 for (tag, values) in fields {
923 for (value, pos) in values {
924 all_fields.push((tag.clone(), value.clone(), *pos));
925 }
926 }
927 all_fields.sort_by_key(|(_, _, pos)| *pos);
928
929 let message_type = std::any::type_name::<T>();
931 let sequence_start_tag = if message_type.contains("MT204Transaction") {
932 "20" } else {
934 "21" };
936 let mut current_sequence_fields: HashMap<String, Vec<(String, usize)>> = HashMap::new();
937 let mut in_sequence = false;
938
939 for (tag, value, pos) in all_fields {
940 if tag == sequence_start_tag
942 && !tag.ends_with("R")
943 && !tag.ends_with("F")
944 && !tag.ends_with("C")
945 && !tag.ends_with("D")
946 {
947 if in_sequence && !current_sequence_fields.is_empty() {
949 if let Ok(sequence_item) = T::from_fields(current_sequence_fields.clone()) {
950 sequences.push(sequence_item);
951 }
952 current_sequence_fields.clear();
953 }
954 in_sequence = true;
955 }
956
957 if in_sequence {
959 current_sequence_fields
960 .entry(tag.clone())
961 .or_default()
962 .push((value, pos));
963
964 tracker.mark_consumed(&tag, pos);
966 }
967 }
968
969 if in_sequence && !current_sequence_fields.is_empty() {
971 match T::from_fields(current_sequence_fields) {
972 Ok(sequence_item) => {
973 sequences.push(sequence_item);
974 }
975 Err(_e) => {
976 #[cfg(debug_assertions)]
977 eprintln!("DEBUG: Failed to parse final sequence item: {_e:?}");
978 }
979 }
980 }
981
982 Ok(sequences)
983}
984
985pub fn serialize_swift_message_to_string(fields: &HashMap<String, Vec<String>>) -> String {
988 let mut result = String::new();
993
994 for field_values in fields.values() {
996 for field_value in field_values {
997 result.push_str(field_value);
999 result.push('\n');
1000 }
1001 }
1002
1003 if result.ends_with('\n') {
1005 result.pop();
1006 }
1007
1008 result
1009}