1use crate::errors::{InvalidFieldFormatError, ParseError};
7use crate::traits::SwiftField;
8use std::collections::HashSet;
9
10use super::field_extractor::extract_field_content;
11
12#[derive(Debug)]
14pub struct MessageParser<'a> {
15 input: &'a str,
17 position: usize,
19 fields_seen: HashSet<String>,
21 message_type: String,
23 allow_duplicates: bool,
25}
26
27impl<'a> MessageParser<'a> {
28 pub fn new(input: &'a str, message_type: &str) -> Self {
30 Self {
31 input,
32 position: 0,
33 fields_seen: HashSet::new(),
34 message_type: message_type.to_string(),
35 allow_duplicates: false,
36 }
37 }
38
39 pub fn with_duplicates(mut self, allow: bool) -> Self {
41 self.allow_duplicates = allow;
42 self
43 }
44
45 pub fn parse_field<T: SwiftField>(&mut self, tag: &str) -> Result<T, ParseError> {
47 let field_content = self.extract_field(tag, false)?;
48
49 T::parse(&field_content).map_err(|e| {
51 ParseError::InvalidFieldFormat(Box::new(InvalidFieldFormatError {
52 field_tag: tag.to_string(),
53 component_name: "field".to_string(),
54 value: field_content,
55 format_spec: "field format".to_string(),
56 position: Some(self.position),
57 inner_error: e.to_string(),
58 }))
59 })
60 }
61
62 pub fn parse_optional_field<T: SwiftField>(
64 &mut self,
65 tag: &str,
66 ) -> Result<Option<T>, ParseError> {
67 if !self.detect_field(tag) {
70 return Ok(None);
71 }
72
73 match self.extract_field(tag, true) {
75 Ok(content) => {
76 let parsed = T::parse(&content).map_err(|e| {
77 ParseError::InvalidFieldFormat(Box::new(InvalidFieldFormatError {
78 field_tag: tag.to_string(),
79 component_name: "field".to_string(),
80 value: content,
81 format_spec: "field format".to_string(),
82 position: Some(self.position),
83 inner_error: e.to_string(),
84 }))
85 })?;
86 Ok(Some(parsed))
87 }
88 Err(_) => Ok(None), }
90 }
91
92 pub fn parse_repeated_field<T: SwiftField>(&mut self, tag: &str) -> Result<Vec<T>, ParseError> {
94 let mut results = Vec::new();
95
96 while let Ok(content) = self.extract_field(tag, true) {
98 let parsed = T::parse(&content).map_err(|e| {
99 ParseError::InvalidFieldFormat(Box::new(InvalidFieldFormatError {
100 field_tag: tag.to_string(),
101 component_name: "field".to_string(),
102 value: content,
103 format_spec: "field format".to_string(),
104 position: Some(self.position),
105 inner_error: e.to_string(),
106 }))
107 })?;
108 results.push(parsed);
109 }
110
111 Ok(results)
112 }
113
114 pub fn parse_variant_field<T: SwiftField>(&mut self, base_tag: &str) -> Result<T, ParseError> {
116 let variant = self.detect_variant(base_tag)?;
118 let full_tag = format!("{}{}", base_tag, variant);
119 let field_content = self.extract_field(&full_tag, false)?;
120
121 T::parse_with_variant(&field_content, Some(&variant), Some(base_tag)).map_err(|e| {
123 ParseError::InvalidFieldFormat(Box::new(InvalidFieldFormatError {
124 field_tag: full_tag,
125 component_name: "field".to_string(),
126 value: field_content,
127 format_spec: "field format".to_string(),
128 position: Some(self.position),
129 inner_error: e.to_string(),
130 }))
131 })
132 }
133
134 pub fn parse_optional_variant_field<T: SwiftField>(
136 &mut self,
137 base_tag: &str,
138 ) -> Result<Option<T>, ParseError> {
139 match self.detect_variant_optional(base_tag) {
140 Some(variant) => {
141 let full_tag = format!("{}{}", base_tag, variant);
142 if let Ok(content) = self.extract_field(&full_tag, true) {
143 let parsed = T::parse_with_variant(&content, Some(&variant), Some(base_tag))
144 .map_err(|e| {
145 ParseError::InvalidFieldFormat(Box::new(InvalidFieldFormatError {
146 field_tag: full_tag,
147 component_name: "field".to_string(),
148 value: content,
149 format_spec: "field format".to_string(),
150 position: Some(self.position),
151 inner_error: e.to_string(),
152 }))
153 })?;
154 Ok(Some(parsed))
155 } else {
156 Ok(None)
157 }
158 }
159 None => Ok(None), }
161 }
162
163 fn extract_field(&mut self, tag: &str, optional: bool) -> Result<String, ParseError> {
165 if !self.allow_duplicates && self.fields_seen.contains(tag) && !optional {
167 return Err(ParseError::InvalidFormat {
168 message: format!("Duplicate field: {}", tag),
169 });
170 }
171
172 let extract_result = extract_field_content(&self.input[self.position..], tag);
174
175 match extract_result {
176 Some((content, consumed)) => {
177 self.position += consumed;
178 if !self.allow_duplicates {
180 self.fields_seen.insert(tag.to_string());
181 }
182 Ok(content)
183 }
184 None => {
185 if optional {
186 Err(ParseError::InvalidFormat {
188 message: format!("Optional field {} not found", tag),
189 })
190 } else {
191 Err(ParseError::MissingRequiredField {
192 field_tag: tag.to_string(),
193 field_name: tag.to_string(),
194 message_type: self.message_type.clone(),
195 position_in_block4: Some(self.position),
196 })
197 }
198 }
199 }
200 }
201
202 fn detect_variant(&self, base_tag: &str) -> Result<String, ParseError> {
204 let common_variants = vec!["A", "B", "C", "D", "F", "K", "L"];
206
207 let remaining = &self.input[self.position..];
209
210 let trimmed = remaining.trim_start_matches(|c: char| c.is_whitespace());
212
213 for variant in common_variants {
214 let full_tag = format!("{}{}", base_tag, variant);
215 if trimmed.starts_with(&format!(":{}:", full_tag)) {
216 return Ok(variant.to_string());
217 }
218 }
219
220 if trimmed.starts_with(&format!(":{}:", base_tag)) {
222 return Ok(String::new());
223 }
224
225 Err(ParseError::MissingRequiredField {
226 field_tag: base_tag.to_string(),
227 field_name: base_tag.to_string(),
228 message_type: self.message_type.clone(),
229 position_in_block4: Some(self.position),
230 })
231 }
232
233 pub fn detect_variant_optional(&self, base_tag: &str) -> Option<String> {
235 let common_variants = vec!["A", "B", "C", "D", "F", "K", "L"];
237
238 let remaining = &self.input[self.position..];
240
241 let trimmed = remaining.trim_start_matches(|c: char| c.is_whitespace());
243
244 for variant in common_variants {
246 let full_tag = format!("{}{}", base_tag, variant);
247 if trimmed.starts_with(&format!(":{}:", full_tag)) {
248 return Some(variant.to_string());
249 }
250 }
251
252 if trimmed.starts_with(&format!(":{}:", base_tag)) {
254 return Some(String::new());
255 }
256
257 None
258 }
259
260 pub fn position(&self) -> usize {
262 self.position
263 }
264
265 pub fn remaining(&self) -> &str {
267 &self.input[self.position..]
268 }
269
270 pub fn is_complete(&self) -> bool {
272 self.position >= self.input.len()
273 || self.remaining().trim().is_empty()
274 || self.remaining().trim() == "-"
275 }
276
277 pub fn detect_field(&self, tag: &str) -> bool {
279 let remaining = self.remaining();
280 let trimmed = remaining.trim_start_matches(|c: char| c.is_whitespace());
281 trimmed.starts_with(&format!(":{}:", tag))
282 }
283
284 pub fn peek_field_variant(&self, base_tag: &str) -> Option<String> {
287 let remaining = self.remaining();
288 let trimmed = remaining.trim_start_matches(|c: char| c.is_whitespace());
289
290 for variant in [
292 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
293 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
294 ] {
295 let search_pattern = format!(":{}{}:", base_tag, variant);
296 if trimmed.starts_with(&search_pattern) {
297 return Some(variant.to_string());
298 }
299 }
300
301 let search_pattern = format!(":{}:", base_tag);
303 if trimmed.starts_with(&search_pattern) {
304 return Some("".to_string()); }
306
307 None
308 }
309}