1use super::swift_utils::{parse_swift_digits, split_at_first};
2use crate::errors::ParseError;
3use crate::traits::SwiftField;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
17pub struct Field28 {
18 pub statement_number: u32,
20
21 pub sequence_number: Option<u8>,
23}
24
25impl SwiftField for Field28 {
26 fn parse(input: &str) -> crate::Result<Self>
27 where
28 Self: Sized,
29 {
30 let (statement_str, sequence_str) = split_at_first(input, '/');
31
32 if statement_str.len() > 5 {
34 return Err(ParseError::InvalidFormat {
35 message: "Statement number must be at most 5 digits".to_string(),
36 });
37 }
38
39 parse_swift_digits(&statement_str, "Statement number")?;
40 let statement_number: u32 =
41 statement_str
42 .parse()
43 .map_err(|_| ParseError::InvalidFormat {
44 message: "Invalid statement number".to_string(),
45 })?;
46
47 let sequence_number = if let Some(seq_str) = sequence_str {
49 if seq_str.len() > 2 {
50 return Err(ParseError::InvalidFormat {
51 message: "Sequence number must be at most 2 digits".to_string(),
52 });
53 }
54 parse_swift_digits(&seq_str, "Sequence number")?;
55 let seq: u8 = seq_str.parse().map_err(|_| ParseError::InvalidFormat {
56 message: "Invalid sequence number".to_string(),
57 })?;
58 Some(seq)
59 } else {
60 None
61 };
62
63 Ok(Field28 {
64 statement_number,
65 sequence_number,
66 })
67 }
68
69 fn to_swift_string(&self) -> String {
70 if let Some(seq) = self.sequence_number {
71 format!(":28:{}/{:02}", self.statement_number, seq)
72 } else {
73 format!(":28:{}", self.statement_number)
74 }
75 }
76}
77
78#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
89pub struct Field28C {
90 pub statement_number: u32,
92
93 pub sequence_number: Option<u32>,
95}
96
97impl SwiftField for Field28C {
98 fn parse(input: &str) -> crate::Result<Self>
99 where
100 Self: Sized,
101 {
102 let (statement_str, sequence_str) = split_at_first(input, '/');
103
104 if statement_str.len() > 5 {
106 return Err(ParseError::InvalidFormat {
107 message: "Statement number must be at most 5 digits".to_string(),
108 });
109 }
110
111 parse_swift_digits(&statement_str, "Statement number")?;
112 let statement_number: u32 =
113 statement_str
114 .parse()
115 .map_err(|_| ParseError::InvalidFormat {
116 message: "Invalid statement number".to_string(),
117 })?;
118
119 let sequence_number = if let Some(seq_str) = sequence_str {
121 if seq_str.len() > 5 {
122 return Err(ParseError::InvalidFormat {
123 message: "Sequence number must be at most 5 digits".to_string(),
124 });
125 }
126 parse_swift_digits(&seq_str, "Sequence number")?;
127 let seq: u32 = seq_str.parse().map_err(|_| ParseError::InvalidFormat {
128 message: "Invalid sequence number".to_string(),
129 })?;
130 Some(seq)
131 } else {
132 None
133 };
134
135 Ok(Field28C {
136 statement_number,
137 sequence_number,
138 })
139 }
140
141 fn to_swift_string(&self) -> String {
142 if let Some(seq) = self.sequence_number {
143 format!(":28C:{}/{}", self.statement_number, seq)
144 } else {
145 format!(":28C:{}", self.statement_number)
146 }
147 }
148}
149
150#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
162pub struct Field28D {
163 pub index: u32,
165
166 pub total: u32,
168}
169
170impl SwiftField for Field28D {
171 fn parse(input: &str) -> crate::Result<Self>
172 where
173 Self: Sized,
174 {
175 let (index_str, total_str) = split_at_first(input, '/');
176
177 if index_str.len() > 5 {
179 return Err(ParseError::InvalidFormat {
180 message: "Index number must be at most 5 digits".to_string(),
181 });
182 }
183
184 parse_swift_digits(&index_str, "Index number")?;
185 let index: u32 = index_str.parse().map_err(|_| ParseError::InvalidFormat {
186 message: "Invalid index number".to_string(),
187 })?;
188
189 let total_str = total_str.ok_or_else(|| ParseError::InvalidFormat {
191 message: "Field28D requires both index and total separated by '/'".to_string(),
192 })?;
193
194 if total_str.len() > 5 {
195 return Err(ParseError::InvalidFormat {
196 message: "Total count must be at most 5 digits".to_string(),
197 });
198 }
199
200 parse_swift_digits(&total_str, "Total count")?;
201 let total: u32 = total_str.parse().map_err(|_| ParseError::InvalidFormat {
202 message: "Invalid total count".to_string(),
203 })?;
204
205 if index > total {
207 return Err(ParseError::InvalidFormat {
208 message: format!("Index {} cannot exceed total {}", index, total),
209 });
210 }
211
212 if index == 0 || total == 0 {
213 return Err(ParseError::InvalidFormat {
214 message: "Index and total must be greater than zero".to_string(),
215 });
216 }
217
218 Ok(Field28D { index, total })
219 }
220
221 fn to_swift_string(&self) -> String {
222 format!(":28D:{:03}/{:03}", self.index, self.total)
223 }
224}
225
226#[cfg(test)]
227mod tests {
228 use super::*;
229
230 #[test]
231 fn test_field28_parse() {
232 let field = Field28::parse("12345/67").unwrap();
234 assert_eq!(field.statement_number, 12345);
235 assert_eq!(field.sequence_number, Some(67));
236
237 let field = Field28::parse("12345").unwrap();
239 assert_eq!(field.statement_number, 12345);
240 assert_eq!(field.sequence_number, None);
241
242 let field = Field28::parse("123/5").unwrap();
244 assert_eq!(field.statement_number, 123);
245 assert_eq!(field.sequence_number, Some(5));
246 }
247
248 #[test]
249 fn test_field28c_parse() {
250 let field = Field28C::parse("12345/99999").unwrap();
252 assert_eq!(field.statement_number, 12345);
253 assert_eq!(field.sequence_number, Some(99999));
254
255 let field = Field28C::parse("12345").unwrap();
257 assert_eq!(field.statement_number, 12345);
258 assert_eq!(field.sequence_number, None);
259 }
260
261 #[test]
262 fn test_field28d_parse() {
263 let field = Field28D::parse("001/010").unwrap();
265 assert_eq!(field.index, 1);
266 assert_eq!(field.total, 10);
267
268 let field = Field28D::parse("5/5").unwrap();
270 assert_eq!(field.index, 5);
271 assert_eq!(field.total, 5);
272 }
273
274 #[test]
275 fn test_field28_to_swift_string() {
276 let field = Field28 {
277 statement_number: 12345,
278 sequence_number: Some(67),
279 };
280 assert_eq!(field.to_swift_string(), ":28:12345/67");
281
282 let field = Field28 {
283 statement_number: 12345,
284 sequence_number: None,
285 };
286 assert_eq!(field.to_swift_string(), ":28:12345");
287 }
288
289 #[test]
290 fn test_field28c_to_swift_string() {
291 let field = Field28C {
292 statement_number: 12345,
293 sequence_number: Some(99999),
294 };
295 assert_eq!(field.to_swift_string(), ":28C:12345/99999");
296 }
297
298 #[test]
299 fn test_field28d_to_swift_string() {
300 let field = Field28D {
301 index: 1,
302 total: 10,
303 };
304 assert_eq!(field.to_swift_string(), ":28D:001/010");
305 }
306
307 #[test]
308 fn test_field28d_validation_errors() {
309 assert!(Field28D::parse("11/10").is_err());
311
312 assert!(Field28D::parse("0/10").is_err());
314 assert!(Field28D::parse("1/0").is_err());
315
316 assert!(Field28D::parse("5").is_err());
318 }
319}