1
2use crate::field_map::FieldBase;
3use crate::field_map::FieldMap;
4use crate::field_map::FieldMapError;
5use crate::field_map::Group;
6use crate::field_map::Tag;
7use crate::fields;
8use crate::fields::ConversionError;
9use crate::fields::types::FieldType;
10use crate::fix_values::SessionRejectReason;
11use crate::message::Message;
12use crate::tags;
13use chrono::NaiveDate;
14use chrono::NaiveDateTime;
15use chrono::NaiveTime;
16use xmltree::ParseError;
17use std::collections::BTreeMap;
18use std::collections::BTreeSet;
19
20use std::fs::File;
21use std::num::ParseIntError;
22use std::ops::Deref;
23use std::ops::DerefMut;
24use std::path::Path;
25
26#[derive(Clone, Debug)]
27pub enum MessageValidationError {
28 UnsupportedVersion { expected: String, actual: String },
29 TagException(TagException),
30 FieldMapError(FieldMapError),
31 ConversionError(ConversionError),
34 }
36
37#[derive(Clone, Debug)]
38pub struct TagException {
39 field: Tag,
40 session_reject_reason: SessionRejectReason,
41 inner: Option<String>, msg_type: Option<String>, }
44
45impl TagException {
46 pub fn other(msg: String, tag: Tag) -> TagException {
47 Self { field: tag, session_reject_reason: SessionRejectReason::OTHER(msg), inner: None, msg_type: None }
48 }
49 pub fn tag_out_of_order(tag: Tag) -> TagException {
50 Self { field: tag, session_reject_reason: SessionRejectReason::TAG_SPECIFIED_OUT_OF_REQUIRED_ORDER(), inner: None, msg_type: None }
51 }
52 pub fn invalid_tag_number(tag: Tag) -> TagException {
53 Self { field: tag, session_reject_reason: SessionRejectReason::INVALID_TAG_NUMBER(), inner: None, msg_type: None }
54 }
55 pub fn required_tag_missing(tag: Tag) -> TagException {
56 Self { field: tag, session_reject_reason: SessionRejectReason::REQUIRED_TAG_MISSING(), inner: None, msg_type: None }
57 }
58 pub fn tag_not_defined_for_message(tag: Tag, msg_type: String) -> TagException {
59 Self { field: tag, session_reject_reason: SessionRejectReason::TAG_NOT_DEFINED_FOR_THIS_MESSAGE_TYPE(), inner: None, msg_type: Some(msg_type) }
60 }
61 pub fn no_tag_value(tag: Tag) -> TagException {
62 Self { field: tag, session_reject_reason: SessionRejectReason::TAG_SPECIFIED_WITHOUT_A_VALUE(), inner: None, msg_type: None }
63 }
64 pub fn incorrect_tag_value(tag: Tag) -> TagException {
65 Self { field: tag, session_reject_reason: SessionRejectReason::VALUE_IS_INCORRECT(), inner: None, msg_type: None }
66 }
67 pub fn repeated_tag(tag: Tag) -> TagException {
68 Self { field: tag, session_reject_reason: SessionRejectReason::TAG_APPEARS_MORE_THAN_ONCE(), inner: None, msg_type: None }
69 }
70 pub fn incorrect_data_format(tag: Tag, inner: String) -> TagException {
71 Self { field: tag, session_reject_reason: SessionRejectReason::INCORRECT_DATA_FORMAT_FOR_VALUE(), inner: Some(inner), msg_type: None }
72 } pub fn invalid_message_type() -> TagException {
74 Self { field: tags::MsgType, session_reject_reason: SessionRejectReason::INVALID_MSGTYPE(), inner: None, msg_type: None }
75 }
76 pub fn repeating_group_count_mismatch(tag: Tag) -> TagException {
77 Self { field: tag, session_reject_reason: SessionRejectReason::INCORRECT_NUM_IN_GROUP_COUNT_FOR_REPEATING_GROUP(), inner: None, msg_type: None }
78 }
79 pub fn group_delimiter_tag_exception(counter_tag: Tag, delimiter_tag: Tag) -> TagException {
80 Self { field: counter_tag, session_reject_reason: SessionRejectReason::OTHER(format!("Group {counter_tag}'s first entry does not start with delimiter {delimiter_tag}")), inner: None, msg_type: None }
81 }
82 pub fn repeated_tag_without_group_delimiter_tag_exception(counter_tag: Tag, trouble_tag: Tag) -> TagException {
83 Self { field: counter_tag, session_reject_reason: SessionRejectReason::OTHER(format!("Group {counter_tag} contains a repeat occurrence of tag {trouble_tag} in a single group, which is illegal.")), inner: None, msg_type: None }
84 }
85
86 pub fn msg_type(&self) -> Option<&String> {
87 self.msg_type.as_ref()
88 }
89
90 pub fn inner(&self) -> Option<&String> {
91 self.inner.as_ref()
92 }
93
94 pub fn session_reject_reason(&self) -> &SessionRejectReason {
95 &self.session_reject_reason
96 }
97
98 pub fn field(&self) -> Tag {
99 self.field
100 }
101}
102
103impl From<FieldMapError> for MessageValidationError {
104 fn from(e: FieldMapError) -> Self {
105 MessageValidationError::FieldMapError(e)
106 }
107}
108
109impl From<ConversionError> for MessageValidationError {
110 fn from(e: ConversionError) -> Self {
111 MessageValidationError::ConversionError(e)
112 }
113}
114
115#[derive(Debug)]
116pub enum DataDictionaryError {
118 DeserializeError(serde_xml_rs::Error),
119 IoError(std::io::Error),
120 ParseError(ParseError),
121 Missing { entry_type: Arc<str>, name: Arc<str> },
122 InvalidVersionType { version_type: Arc<str> },
123 ParseIntError(ParseIntError),
124}
125
126impl From<serde_xml_rs::Error> for DataDictionaryError {
127 fn from(error: serde_xml_rs::Error) -> Self {
128 Self::DeserializeError(error)
129 }
130}
131impl From<std::io::Error> for DataDictionaryError {
132 fn from(error: std::io::Error) -> Self {
133 Self::IoError(error)
134 }
135}
136impl From<ParseError> for DataDictionaryError {
137 fn from(error: ParseError) -> Self {
138 Self::ParseError(error)
139 }
140}
141impl From<ParseIntError> for DataDictionaryError {
142 fn from(error: ParseIntError) -> Self {
143 Self::ParseIntError(error)
144 }
145}
146
147type Field = Arc<DDField>;
148pub(crate) type ArcGroup = Arc<DDGroup>;
150
151#[derive(Clone, Debug)]
152pub struct DataDictionary {
153 check_fields_have_values: bool,
154 check_fields_out_of_order: bool,
155 check_user_defined_fields: bool,
156 allow_unknown_message_fields: bool,
157 version: Option<Arc<str>>,
158 length_fields: Vec<Tag>,
159 fields_by_tag: BTreeMap<Tag, Field>,
160 fields_by_name: BTreeMap<Arc<str>, Field>,
161 messages: BTreeMap<Arc<str>, DDMap>,
162 header: DDMap,
163 trailer: DDMap,
164}
165
166impl Default for DataDictionary {
167 fn default() -> Self {
168 Self {
169 check_fields_have_values: Default::default(),
170 check_fields_out_of_order: Default::default(),
171 check_user_defined_fields: Default::default(),
172 allow_unknown_message_fields: Default::default(),
173 version: Default::default(),
174 length_fields: Default::default(),
175 fields_by_tag: Default::default(),
176 fields_by_name: Default::default(),
177 messages: Default::default(),
178 header: DDMap::new("header".into()),
179 trailer: DDMap::new("trailer".into())
180 }
181 }
182}
183
184
185impl DataDictionary {
186 pub fn from_file<P: AsRef<Path>>(path: P) -> Result<DataDictionary, DataDictionaryError> {
187 let path: &Path = path.as_ref();
188 let mut reader = match File::open(&path) {
189 Err(why) => panic!("couldn't open {}: {}", path.display(), why),
190 Ok(file) => file,
191 };
192
193 let mut contents = String::new();
194 reader.read_to_string(&mut contents)?;
195 let dd = DataDictionary::load_from_string(&contents)?;
196 Ok(dd)
197 }
198
199 pub fn version(&self) -> Option<&Arc<str>> {
200 self.version.as_ref()
201 }
202
203 pub fn header(&self) -> &DDMap {
204 &self.header
205 }
206
207 pub fn trailer(&self) -> &DDMap {
208 &self.trailer
209 }
210
211 pub fn is_header_field(&self, tag: Tag) -> bool {
212 self.header.is_field(tag)
213 }
214 pub fn is_trailer_field(&self, tag: Tag) -> bool {
215 self.trailer.is_field(tag)
216 }
217
218 pub fn validate(
219 message: &Message,
220 session_data_dictionary: Option<&DataDictionary>,
221 app_data_dictionary: &DataDictionary,
222 begin_string: &str,
223 msg_type: &str,
224 ) -> Result<(), MessageValidationError> {
225
226 if let Some(dictionary) = session_data_dictionary {
227 if let Some(version) = dictionary.version() {
228 if version.as_ref() != begin_string {
229 return Err(MessageValidationError::UnsupportedVersion {
230 expected: version.to_string(),
231 actual: begin_string.into(),
232 });
233 }
234 }
235 }
236
237 let check_order_session = session_data_dictionary
238 .map(|d| d.check_fields_out_of_order())
239 .unwrap_or(false);
240 let check_order_app = app_data_dictionary.check_fields_out_of_order();
241 if check_order_session || check_order_app {
242 message.has_valid_structure()?;
243 }
244
245 if app_data_dictionary.version().is_some() {
246 app_data_dictionary.check_msg_type(msg_type)?;
247 app_data_dictionary.check_has_required(message, msg_type)?;
248 }
249
250 if let Some(dictionary) = session_data_dictionary {
251 dictionary.iterate(message.header(), msg_type)?;
252 dictionary.iterate(message.trailer(), msg_type)?;
253 }
254
255 app_data_dictionary.iterate(message, msg_type)?;
256 Ok(())
257 }
258
259 fn check_msg_type(&self, msg_type: &str) -> Result<(), MessageValidationError> {
260 if self.messages.contains_key(msg_type) {
261 Ok(())
262 } else {
263 Err(MessageValidationError::TagException(TagException::invalid_message_type()))
265 }
266 }
267 fn check_has_required(
268 &self,
269 message: &Message,
270 msg_type: &str,
271 ) -> Result<(), MessageValidationError> {
272 for field in self.header.required_fields() {
273 if !message.header().is_field_set(*field) {
274 return Err(MessageValidationError::TagException(TagException::required_tag_missing(*field)));
275 }
276 }
277
278 for field in self.trailer.required_fields() {
279 if !message.trailer().is_field_set(*field) {
280 return Err(MessageValidationError::TagException(TagException::required_tag_missing(*field)));
281 }
282 }
283
284 for field in self.messages[msg_type].required_fields() {
285 if !message.is_field_set(*field) {
286 return Err(MessageValidationError::TagException(TagException::required_tag_missing(*field)));
287 }
288 }
289 Ok(())
290 }
291 fn check_has_no_repeated_tags(map: &FieldMap) -> Result<(), MessageValidationError> {
292 if let Some(field) = map.repeated_tags().get(0) {
293 Err(MessageValidationError::TagException(
294 TagException::repeated_tag(field.tag()),
295 ))
296 } else {
297 Ok(())
298 }
299 }
300 fn check_fields_out_of_order(&self) -> bool {
301 self.check_fields_out_of_order
302 }
303 fn check_has_value(&self, field: &FieldBase) -> Result<(), MessageValidationError> {
304 if self.check_fields_have_values && field.value().is_empty() {
305 Err(MessageValidationError::TagException(TagException::no_tag_value(field.tag())))
306 } else {
307 Ok(())
308 }
309 }
310 fn check_valid_format(&self, field: &FieldBase) -> Result<(), MessageValidationError> {
311 if let Some(field_definition) = self.fields_by_tag.get(&field.tag()) {
313 let field_type = FieldType::get(field_definition.field_type().as_ref());
314 if matches!(field_type, Ok(ftype) if ftype == fields::types::FieldType::String) {
315 return Ok(());
316 }
317
318 if !self.check_fields_have_values && field.value().len() < 1 {
319 return Ok(());
320 }
321
322 let err = match field_type {
323 Ok(ftype) => match ftype {
324 FieldType::Boolean => field.as_value::<bool>().err(),
325 FieldType::Char => { field.as_value::<char>().err() },
326 FieldType::DateOnly => { field.as_value::<NaiveDate>().err() },
327 FieldType::DateTime => { field.as_value::<NaiveDateTime>().err() },
328 FieldType::Decimal => { field.as_value::<f32>().err() },
329 FieldType::Int => { field.as_value::<i32>().err() },
330 FieldType::String => unreachable!(),
331 FieldType::TimeOnly => { field.as_value::<NaiveTime>().err() },
332 },
333 Err(msg) => todo!("{msg}"),
334 };
335 if let Some(e) = err {
336 Err(MessageValidationError::TagException(TagException::incorrect_data_format(field.tag(), format!("{e:?}"))))
337 } else {
338 Ok(())
339 }
340
341 } else {
342 Ok(())
343 }
344
345 }
346 fn check_valid_tag_number(&self, tag: Tag) -> Result<(), MessageValidationError> {
347 if !self.allow_unknown_message_fields && !self.fields_by_tag.contains_key(&tag) {
348 return Err(MessageValidationError::TagException(TagException::invalid_tag_number(tag)));
349 }
350 Ok(())
351 }
352 fn check_value(&self, field: &FieldBase) -> Result<(), MessageValidationError> {
353 match self.fields_by_tag.get(&field.tag()) {
354 Some(fld) => {
355 if fld.has_enums() {
356 if fld.is_multiple_value_field_with_enums() {
357 let string_value = field.string_value()?;
358 let splitted = string_value.split(' ');
359 for value in splitted {
360 if !fld.enums().contains_key(value) {
361 return Err(MessageValidationError::TagException(
362 TagException::incorrect_tag_value(field.tag())
363 ));
364 }
365 }
366 Ok(())
367 } else if !fld.enums().contains_key(field.string_value()?.as_str()) {
368 Err(MessageValidationError::TagException(
369 TagException::incorrect_tag_value(field.tag())
370 ))
371 } else {
372 Ok(())
373 }
374 } else {
375 Ok(())
376 }
377 }
378 None => Ok(()),
379 }
380 }
381 fn check_is_in_message(
382 &self,
383 field: &FieldBase,
384 msg_type: &str,
385 ) -> Result<(), MessageValidationError> {
386 if self.allow_unknown_message_fields {
387 return Ok(());
388 }
389
390 if matches!(self.messages.get(msg_type), Some(dd) if dd.fields.contains_key(&field.tag())) {
391 return Ok(());
392 }
393 Err(MessageValidationError::TagException(
394 TagException::tag_not_defined_for_message(field.tag(), msg_type.into())
395 ))
396 }
397 fn check_is_in_group(
398 &self,
399 field: &FieldBase,
400 dd_group: &DDGroup,
401 msg_type: &str,
402 ) -> Result<(), MessageValidationError> {
403 if dd_group.is_field(field.tag()) {
404 Ok(())
405 } else {
406 Err(MessageValidationError::TagException(
407 TagException::tag_not_defined_for_message(field.tag(), msg_type.into())
408 ))
409 }
410 }
411 fn check_group_count(
412 &self,
413 field: &FieldBase,
414 map: &FieldMap,
415 msg_type: &str,
416 ) -> Result<(), MessageValidationError> {
417 if self.is_group(msg_type, field.tag())
418 && map.get_int(field.tag())? as usize != map.group_count(field.tag()).unwrap_or(0)
419 {
420 return Err(MessageValidationError::TagException(
421 TagException::repeating_group_count_mismatch(field.tag())
422 ));
423 }
424 Ok(())
425 }
426 fn is_group(&self, msg_type: &str, tag: Tag) -> bool {
427 if self.messages.contains_key(msg_type) {
428 return self.messages[msg_type].is_group(tag);
429 }
430 false
431 }
432 fn should_check_tag(&self, field: &FieldBase) -> bool {
433 if !self.check_user_defined_fields && (field.tag() >= fields::limits::USER_MIN) {
434 return false;
435 }
436 true
437 }
438
439 fn iterate(&self, message: &FieldMap, msg_type: &str) -> Result<(), MessageValidationError> {
440 DataDictionary::check_has_no_repeated_tags(message)?;
441
442 let mut last_field = 0;
444 for (_k, v) in message.entries() {
445 let field = v;
446 if last_field != 0 && field.tag() == last_field {
447 return Err(MessageValidationError::TagException(TagException::repeated_tag(field.tag())));
448 }
449 self.check_has_value(field)?;
450
451 if !self.version.is_none() && !matches!(&self.version, Some(version) if version.is_empty()) {
452 self.check_valid_format(field)?;
453
454 if self.should_check_tag(field) {
455 self.check_valid_tag_number(field.tag())?;
456
457 self.check_value(field)?;
458 if !Message::is_header_field(field.tag(), Some(self))
459 && !Message::is_trailer_field(field.tag(), Some(self))
460 {
461 self.check_is_in_message(field, msg_type)?;
462 self.check_group_count(field, message, msg_type)?;
463 } else {
464 }
465 }
466 }
467
468 last_field = field.tag();
469 }
470
471 for tag in message.group_tags() {
473 for i in 1..=message.group_count(*tag)? {
474 let g = message.get_group(i as u32, *tag)?;
475 let ddg = self.messages[msg_type].get_group(*tag);
476 self.iterate_group(g, ddg, msg_type)?;
477 }
478 }
479
480 Ok(())
481 }
482
483 fn iterate_group(
484 &self,
485 group: &Group,
486 group_definition: Option<&ArcGroup>,
487 msg_type: &str,
488 ) -> Result<(), MessageValidationError> {
489 match group_definition {
490 Some(group_definition) => {
491 DataDictionary::check_has_no_repeated_tags(group)?;
492
493 let mut last_field = 0;
494 for (_, v) in group.entries() {
495 let field = v;
496
497 if last_field != 0 && field.tag() == last_field {
498 return Err(MessageValidationError::TagException(TagException::repeated_tag(last_field)));
499 }
500 self.check_has_value(field)?;
501
502 if !self.version.is_none() && !matches!(&self.version, Some(version) if version.is_empty()) {
503 self.check_valid_format(field)?;
504
505 if self.should_check_tag(field) {
506 self.check_valid_tag_number(field.tag())?;
507
508 self.check_value(field)?;
509 self.check_is_in_group(field, group_definition, msg_type)?;
510 self.check_group_count(field, group, msg_type)?;
511 }
512 }
513 last_field = field.tag();
514 }
515
516 for tag in group.group_tags() {
518 for i in 1..=group.group_count(*tag)? {
519 let g = group.get_group(i as u32, *tag)?;
520 let ddg = group_definition.get_group(*tag);
521 self.iterate_group(g, ddg, msg_type)?;
522 }
523 }
524
525 Ok(())
526 }
527 None => Ok(()),
528 }
529 }
530
531 pub fn get_map_for_message(&self, msg_type: &str) -> Option<&DDMap> {
532 self.messages.get(msg_type)
533 }
534
535 pub fn get_field_by_name(&self, field_name: &str) -> Option<&Field> {
536 self.fields_by_name.get(field_name)
537 }
538
539 pub(crate) fn is_length_field(&self, tag: Tag) -> bool {
540 self.length_fields.contains(&tag)
545 }
546
547 pub fn fields_by_name(&self) -> &BTreeMap<Arc<str>, Field> {
548 &self.fields_by_name
549 }
550
551 pub fn messages(&self) -> &BTreeMap<Arc<str>, DDMap> {
552 &self.messages
553 }
554
555
556 pub fn check_fields_have_values(&self) -> bool {
557 self.check_fields_have_values
558 }
559
560 pub fn check_fields_have_values_mut(&mut self) -> &mut bool {
561 &mut self.check_fields_have_values
562 }
563
564 pub fn set_check_fields_have_values(&mut self, check_fields_have_values: bool) {
565 self.check_fields_have_values = check_fields_have_values;
566 }
567
568 pub fn check_fields_out_of_order_mut(&mut self) -> &mut bool {
569 &mut self.check_fields_out_of_order
570 }
571
572 pub fn set_check_fields_out_of_order(&mut self, check_fields_out_of_order: bool) {
573 self.check_fields_out_of_order = check_fields_out_of_order;
574 }
575
576 pub fn check_user_defined_fields(&self) -> bool {
577 self.check_user_defined_fields
578 }
579
580 pub fn check_user_defined_fields_mut(&mut self) -> &mut bool {
581 &mut self.check_user_defined_fields
582 }
583
584 pub fn set_check_user_defined_fields(&mut self, check_user_defined_fields: bool) {
585 self.check_user_defined_fields = check_user_defined_fields;
586 }
587
588 pub fn allow_unknown_message_fields(&self) -> bool {
589 self.allow_unknown_message_fields
590 }
591
592 pub fn allow_unknown_message_fields_mut(&mut self) -> &mut bool {
593 &mut self.allow_unknown_message_fields
594 }
595
596 pub fn set_allow_unknown_message_fields(&mut self, allow_unknown_message_fields: bool) {
597 self.allow_unknown_message_fields = allow_unknown_message_fields;
598 }
599}
600
601#[derive(Debug, Clone)]
602pub struct DDMap {
603 fields: BTreeMap<Tag, Field>,
604 groups: BTreeMap<Tag, ArcGroup>,
605 required_fields: BTreeSet<Tag>,
606 name: Arc<str>,
607 msg_type: Arc<str>,
608 admin: bool,
609}
610impl DDMap {
611 pub fn new(name: Arc<str>) -> Self {
612 DDMap {
613 fields: BTreeMap::default(),
614 groups: BTreeMap::default(),
615 required_fields: BTreeSet::default(),
616 name,
617 msg_type: "".into(),
618 admin: false,
619 }
620 }
621 pub fn new_with_values(name: Arc<str>, msg_type: Arc<str>, admin: bool) -> Self {
622 DDMap {
623 fields: BTreeMap::default(),
624 groups: BTreeMap::default(),
625 required_fields: BTreeSet::default(),
626 name,
627 msg_type,
628 admin,
629 }
630 }
631 pub fn add_field(&mut self, field: Field) {
632 self.fields.insert(field.tag(), field);
633 }
634 pub fn is_field(&self, tag: Tag) -> bool {
635 self.fields.contains_key(&tag)
636 }
637 pub fn get_field(&self, tag: Tag) -> Option<&Field> {
638 self.fields.get(&tag)
639 }
640 pub fn add_group(&mut self, group: ArcGroup) {
641 self.groups.insert(group.delim(), group);
642 }
643 pub fn is_group(&self, tag: Tag) -> bool {
644 self.groups.contains_key(&tag)
645 }
646 pub fn get_group(&self, tag: Tag) -> Option<&ArcGroup> {
647 self.groups.get(&tag)
648 }
649 pub fn required_fields(&self) -> &BTreeSet<Tag> {
650 &self.required_fields
651 }
652 pub fn required_fields_mut(&mut self) -> &mut BTreeSet<Tag> {
653 &mut self.required_fields
654 }
655 pub fn add_required_field(&mut self, tag: Tag) {
656 self.required_fields.insert(tag);
657 }
658 pub fn name(&self) -> &Arc<str> {
659 &self.name
660 }
661 pub fn fields(&self) -> &BTreeMap<Tag, Field> {
662 &self.fields
663 }
664 pub fn groups(&self) -> &BTreeMap<Tag, ArcGroup> {
665 &self.groups
666 }
667
668 pub fn admin(&self) -> bool {
669 self.admin
670 }
671
672 pub fn msg_type(&self) -> &str {
673 self.msg_type.as_ref()
674 }
675}
676trait AsDDMap {
677 fn as_map(&self) -> &DDMap;
678 fn as_map_mut(&mut self) -> &mut DDMap;
679}
680impl AsDDMap for DDMap {
681 fn as_map(&self) -> &DDMap {
682 self
683 }
684 fn as_map_mut(&mut self) -> &mut DDMap {
685 self
686 }
687}
688impl<D: DerefMut<Target = DDMap>> AsDDMap for D {
689 fn as_map(&self) -> &DDMap {
690 self.deref()
691 }
692 fn as_map_mut(&mut self) -> &mut DDMap {
693 self.deref_mut()
694 }
695}
696
697#[derive(Clone, Debug)]
698pub enum DictionaryError {
699 ParseError(Arc<str>),
700}
701
702#[derive(Debug, Clone)]
703pub struct DDField {
704 tag: Tag,
705 name: Arc<str>,
706 enum_dictionary: BTreeMap<Arc<str>, Arc<str>>,
707 field_type: Arc<str>,
708 is_multiple_value_field_with_enums: bool,
709}
710impl DDField {
711
712 pub fn from_xml_str(xml_str: &str) -> Self {
713 todo!("DataDictionary::from_xml_str({xml_str})")
714 }
715
716 pub fn new(
717 tag: Tag,
718 name: Arc<str>,
719 enum_dictionary: BTreeMap<Arc<str>, Arc<str>>,
720 field_type: Arc<str>,
721 ) -> Self {
724 let is_multiple_value_field_with_enums = matches!(
725 field_type.as_ref(),
726 "MULTIPLEVALUESTRING" | "MULTIPLESTRINGVALUE" | "MULTIPLECHARVALUE"
727 );
728 DDField {
729 tag,
730 name,
731 enum_dictionary,
732 field_type,
733 is_multiple_value_field_with_enums,
734 }
735 }
736 pub fn tag(&self) -> Tag {
737 self.tag
738 }
739 pub fn name(&self) -> &Arc<str> {
740 &self.name
741 }
742 pub fn has_enums(&self) -> bool {
743 !self.enum_dictionary.is_empty()
744 }
745 pub fn enums(&self) -> &BTreeMap<Arc<str>, Arc<str>> {
746 &self.enum_dictionary
747 }
748 pub fn field_type(&self) -> &Arc<str> {
749 &self.field_type
750 }
751 pub fn is_length_field(&self) -> bool {
752 self.field_type.as_ref() == "LENGTH" && self.name.as_ref() != "BodyLength"
753 }
754
755 pub fn is_multiple_value_field_with_enums(&self) -> bool {
756 self.is_multiple_value_field_with_enums
757 }
758}
759
760#[derive(Debug, Clone)]
761pub struct DDGroup {
762 num_fld: Tag,
763 delim: Tag,
764 required: bool,
765 name: Arc<str>,
766 map: DDMap,
767}
768impl DDGroup {
769 pub fn new() -> Self {
770 DDGroup { num_fld: Tag::default(), delim: Tag::default(), required: bool::default(), name: "".into(), map: DDMap::new("group".into()) }
771 }
772 pub fn name(&self) -> &Arc<str> {
773 &self.name
774 }
775 pub fn num_fld(&self) -> Tag {
776 self.num_fld
777 }
778 pub fn delim(&self) -> Tag {
779 self.delim
780 }
781 pub fn required(&self) -> bool {
782 self.required
783 }
784}
785impl Deref for DDGroup {
786 type Target = DDMap;
787 fn deref(&self) -> &Self::Target {
788 &self.map
789 }
790}
791impl DerefMut for DDGroup {
792 fn deref_mut(&mut self) -> &mut Self::Target {
793 &mut self.map
794 }
795}
796
797#[derive(Debug)]
798enum GoM<'a> {
799 Map(&'a mut DDMap),
800 Group(&'a mut DDGroup)
801}
802impl<'a> Deref for GoM<'a> {
803 type Target = DDMap;
804 fn deref(&self) -> &Self::Target {
805 match self {
806 GoM::Map(g) => g,
807 GoM::Group(g) => g,
808 }
809 }
810}
811impl<'a> DerefMut for GoM<'a> {
812 fn deref_mut(&mut self) -> &mut Self::Target {
813 match self {
814 GoM::Map(g) => g,
815 GoM::Group(g) => g,
816 }
817 }
818}
819
820use std::io::Read;
821use std::println;
822use std::str::FromStr;
823use std::sync::Arc;
824use xmltree::Element;
825
826impl DataDictionary {
827 pub fn new() -> DataDictionary {
828 DataDictionary {
829 version: None,
830 length_fields: Vec::new(),
831 fields_by_tag: BTreeMap::new(),
832 fields_by_name: BTreeMap::new(),
833 messages: BTreeMap::new(),
834 check_fields_out_of_order: true,
835 check_fields_have_values: true,
836 check_user_defined_fields: true,
837 allow_unknown_message_fields: false,
838 header: DDMap::new("header".into()),
839 trailer: DDMap::new("trailer".into()),
840 }
841 }
842
843 pub fn load(&mut self, path: &str) -> Result<Self, DataDictionaryError> {
844 let mut file = File::open(path)?;
845 let mut contents = String::new();
846 file.read_to_string(&mut contents)?;
847
848 Self::load_from_string(&contents)
849 }
850
851 pub fn load_from_string(contents: &str) -> Result<Self, DataDictionaryError> {
852 let root_doc = Element::parse(contents.as_bytes())?;
853
854 let (_major_version, _minor_version, version) = get_version_info(&root_doc)?;
855 let (fields_by_tag, fields_by_name) = parse_fields(&root_doc)?;
856 let components_by_name = cache_components(&root_doc)?;
857 let messages = parse_messages(&root_doc, &fields_by_name, &components_by_name)?;
858 let header = parse_header(&root_doc, &fields_by_name, &components_by_name)?;
859 let trailer = parse_trailer(&root_doc, &fields_by_name, &components_by_name)?;
860
861 let length_fields = fields_by_tag.iter()
862 .filter_map(|(tag, f)| if f.is_length_field() { Some(*tag) } else { None } )
863 .collect();
864
865 Ok(DataDictionary {
866 version: Some(version),
867 length_fields,
868 fields_by_tag,
869 fields_by_name,
870 messages,
871 check_fields_out_of_order: true,
872 check_fields_have_values: true,
873 check_user_defined_fields: true,
874 allow_unknown_message_fields: false,
875 header,
876 trailer,
877 })
878 }
879
880}
881
882fn get_version_info(doc: &Element) -> Result<(Arc<str>, Arc<str>, Arc<str>), DataDictionaryError> {
883 let major_version = doc.attributes.get("major")
884 .ok_or(DataDictionaryError::Missing { entry_type: "attribute".into(), name: "major".into() })?.to_string();
885 let minor_version = doc.attributes.get("minor")
886 .ok_or(DataDictionaryError::Missing { entry_type: "attribute".into(), name: "minor".into() })?.to_string();
887 let version = "FIX".to_string();
888 let version_type = doc.attributes.get("type").unwrap_or(&version);
889 if version_type != "FIX" && version_type != "FIXT" {
890 return Err(DataDictionaryError::InvalidVersionType { version_type: version_type.clone().into() });
891 }
892 let version = format!("{}.{}.{}", version_type, major_version, minor_version);
893 Ok((major_version.into(), minor_version.into(), version.into()))
894}
895
896fn parse_fields(doc: &Element) -> Result<(BTreeMap<i32, Field>, BTreeMap<Arc<str>, Field>), DataDictionaryError> {
897 let mut fields_by_tag: BTreeMap<i32, Field> = BTreeMap::new();
898 let mut fields_by_name: BTreeMap<Arc<str>, Field> = BTreeMap::new();
899 let field_nodes = doc
900 .children.iter()
901 .filter_map(|c| c.as_element())
902 .filter(|c| c.name == "fields")
903 .flat_map(|node| node.children.iter())
904 .filter_map(|c| c.as_element())
905 .filter(|node| node.name == "field");
906
907 for field_node in field_nodes {
908 let tag_str = field_node.attributes.get("number")
909 .ok_or(DataDictionaryError::Missing { entry_type: "attribute".into(), name: "major".into() })?;
910 let name = field_node.attributes.get("name")
911 .ok_or(DataDictionaryError::Missing { entry_type: "attribute".into(), name: "name".into() })?;
912 let field_type = field_node.attributes.get("type")
913 .ok_or(DataDictionaryError::Missing { entry_type: "attribute".into(), name: "type".into() })?;
914
915 let tag = tag_str.parse::<i32>()?;
916 let mut enums = BTreeMap::new();
917 for enum_node in field_node.children.iter()
918 .filter_map(|c| c.as_element())
919 .filter(|c| c.name == "value")
920 {
921 let enum_value = enum_node.attributes.get("enum")
922 .ok_or(DataDictionaryError::Missing { entry_type: "attribute".into(), name: "enum".into() })?.clone();
923 let description = enum_node.attributes.get("description").map(|s| s.clone()).unwrap_or_default();
924 enums.insert(enum_value.into(), description.into());
925 }
926
927 let is_multiple_value_field_with_enums = matches!(
928 field_type.as_str(),
929 "MULTIPLEVALUESTRING" | "MULTIPLESTRINGVALUE" | "MULTIPLECHARVALUE"
930 );
931
932 let dd_field = DDField {
933 tag,
934 name: name.clone().into(),
935 enum_dictionary: enums,
936 field_type: field_type.clone().into(),
937 is_multiple_value_field_with_enums
938 };
939 let dd_field = Arc::new(dd_field);
940
941 fields_by_tag.insert(tag, dd_field.clone());
942 fields_by_name.insert(name.clone().into(), dd_field);
943 }
944 return Ok((fields_by_tag, fields_by_name));
945}
946
947fn cache_components(doc: &Element) -> Result<BTreeMap<Arc<str>, Element>, DataDictionaryError> {
948 let mut components_by_name: BTreeMap<Arc<str>, Element> = BTreeMap::new();
949 let component_nodes = doc
950 .children.iter()
951 .filter_map(|c| c.as_element())
952 .filter(|c| c.name == "components")
953 .flat_map(|node| node.children.iter())
954 .filter_map(|c| c.as_element())
955 .filter(|node| node.name == "component");
956
957 for component_node in component_nodes {
958 let name = component_node.attributes.get("name")
959 .ok_or(DataDictionaryError::Missing { entry_type: "attribute".into(), name: "name".into() })?.clone();
960 components_by_name.insert(name.into(), component_node.clone());
961 }
962 Ok(components_by_name)
963}
964
965fn parse_messages(doc: &Element, fields_by_name: &BTreeMap<Arc<str>, Field>, components_by_name: &BTreeMap<Arc<str>, Element>) -> Result<BTreeMap<Arc<str>, DDMap>, DataDictionaryError> {
966 let mut messages: BTreeMap<Arc<str>, DDMap> = BTreeMap::new();
967 let message_nodes = doc
968 .children.iter()
969 .filter_map(|c| c.as_element())
970 .filter(|c| c.name == "messages")
971 .flat_map(|node| node.children.iter())
972 .filter_map(|c| c.as_element())
973 .filter(|node| node.name == "message");
974
975 for message_node in message_nodes {
976 let name: Arc<str> = message_node.attributes.get("name")
977 .ok_or(DataDictionaryError::Missing { entry_type: "attribute".into(), name: "name".into() })?.clone().into();
978 let mut dd_map = DDMap::new(name);
979 parse_msg_element(&message_node, &mut dd_map, fields_by_name, components_by_name)?;
980 let msg_type: Arc<str> = message_node.attributes.get("msgtype")
981 .ok_or(DataDictionaryError::Missing { entry_type: "attribute".into(), name: "msgtype".into() })?.clone().into();
982 messages.insert(msg_type, dd_map);
983 }
984 Ok(messages)
985}
986
987fn parse_header(doc: &Element, fields_by_name: &BTreeMap<Arc<str>, Field>, components_by_name: &BTreeMap<Arc<str>, Element>) -> Result<DDMap, DataDictionaryError> {
988 let mut dd_map = DDMap::new("header".into());
989 if let Some(header_node) = doc.get_child("header") {
990 parse_msg_element(&header_node, &mut dd_map, fields_by_name, components_by_name)?;
991 }
992 Ok(dd_map)
993}
994
995fn parse_trailer(doc: &Element, fields_by_name: &BTreeMap<Arc<str>, Field>, components_by_name: &BTreeMap<Arc<str>, Element>) -> Result<DDMap, DataDictionaryError> {
996 let mut dd_map = DDMap::new("trailer".into());
997 if let Some(trailer_node) = doc.get_child("trailer") {
998 parse_msg_element(&trailer_node, &mut dd_map, fields_by_name, components_by_name)?;
999 }
1000 Ok(dd_map)
1001}
1002
1003fn verify_child_node(child_node: &Element, parent_node: &Element) {
1004 if child_node.attributes.is_empty() {
1005 panic!(
1006 "Malformed data dictionary: Found text-only node containing '{}'",
1007 child_node.get_text().unwrap_or_default().trim()
1008 );
1009 }
1010 if !child_node.attributes.contains_key("name") {
1011 let message_type_name = parent_node
1012 .attributes
1013 .get("name")
1014 .map(|s| s.clone())
1015 .unwrap_or_else(|| parent_node.name.clone());
1016 panic!(
1017 "Malformed data dictionary: Found '{}' node without 'name' within parent '{}/{}'",
1018 child_node.name, parent_node.name, message_type_name
1019 );
1020 }
1021}
1022
1023fn parse_msg_element(
1024 node: &Element,
1025 dd_map: &mut DDMap,
1026 fields_by_name: &BTreeMap<Arc<str>, Field>,
1027 components_by_name: &BTreeMap<Arc<str>, Element>,
1028) -> Result<(), DataDictionaryError> {
1029 parse_msg_element_inner(node, &mut GoM::Map(dd_map), fields_by_name, components_by_name, None)
1030}
1031
1032fn parse_msg_element_inner(
1033 node: &Element,
1034 dd_map: &mut GoM<'_>,
1035 fields_by_name: &BTreeMap<Arc<str>, Field>,
1036 components_by_name: &BTreeMap<Arc<str>, Element>,
1037 component_required: Option<bool>,
1038) -> Result<(), DataDictionaryError> {
1039 let message_type_name = node
1040 .attributes
1041 .get("name")
1042 .map(|s| s.clone())
1043 .unwrap_or_else(|| node.name.clone());
1044
1045 if node.children.is_empty() {
1046 return Ok(());
1047 }
1048
1049 for child_node in node.children.iter() {
1050 if let Some(child_node) = child_node.as_element() {
1051 verify_child_node(child_node, node);
1052
1053 let name_attribute: Arc<str> = child_node.attributes.get("name")
1054 .ok_or(DataDictionaryError::Missing { entry_type: "attribute".into(), name: "name".into() })?.clone().into();
1055
1056 match child_node.name.as_str() {
1057 "field" | "group" => {
1058 if !fields_by_name.contains_key(&name_attribute) {
1059 panic!(
1060 "Field '{}' is not defined in <fields> section.",
1061 name_attribute
1062 );
1063 }
1064 let dd_field = fields_by_name.get(&name_attribute)
1065 .ok_or(DataDictionaryError::Missing { entry_type: "field".into(), name: name_attribute.clone() })?.clone();
1066 let required = child_node.attributes.get("required").map(|v| v == "Y").unwrap_or(false)
1067 && component_required.unwrap_or(true);
1068
1069 if required {
1070 dd_map.required_fields.insert(dd_field.tag);
1071 }
1072
1073 if !dd_map.is_field(dd_field.tag) {
1074 dd_map.fields.insert(dd_field.tag, dd_field.clone());
1075 }
1076
1077 if let GoM::Group(grp) = dd_map {
1079 if grp.delim == 0 {
1080 grp.delim = dd_field.tag;
1081 }
1082 }
1083
1084 if child_node.name == "group" {
1085 let mut dd_grp = DDGroup::new();
1086 dd_grp.num_fld = dd_field.tag;
1087
1088 if required {
1089 dd_grp.required = true;
1090 }
1091
1092 {
1093 let mut dd_map = GoM::Group(&mut dd_grp);
1094 parse_msg_element_inner(child_node, &mut dd_map, fields_by_name, components_by_name, None)?;
1095 }
1096
1097 dd_map.groups.insert(dd_field.tag, dd_grp.into());
1098 }
1099 }
1100 "component" => {
1101 let component_node = components_by_name
1102 .get(&name_attribute)
1103 .ok_or(DataDictionaryError::Missing { entry_type: "component".into(), name: name_attribute.clone().into() })?
1104 .clone();
1105
1106 let required = child_node.attributes.get("required").map(|v| v == "Y").unwrap_or(false);
1107 parse_msg_element_inner(&component_node, dd_map, fields_by_name, components_by_name, Some(required))?;
1108 }
1109 _ => panic!(
1110 "Malformed data dictionary: child node type should be one of {{field,group,component}} but is '{}' within parent '{}/{}'",
1111 child_node.name,
1112 node.name,
1113 message_type_name
1114 ),
1115 }
1116 }
1117 }
1118 Ok(())
1119}
1120
1121#[cfg(test)]
1122mod tests {
1123 use super::DataDictionary;
1124
1125 #[test]
1126 pub fn fix40() {
1127 let result = DataDictionary::load_from_string(include_str!("../../../spec/FIX40.xml"));
1128 println!("{:?}", result);
1129 assert!(result.is_ok());
1130 }
1131
1132 #[test]
1133 pub fn fix41() {
1134 let result = DataDictionary::load_from_string(include_str!("../../../spec/FIX41.xml"));
1135 println!("{:?}", result);
1136 assert!(result.is_ok());
1137 }
1138
1139 #[test]
1140 pub fn fix42() {
1141 let result = DataDictionary::load_from_string(include_str!("../../../spec/FIX42.xml"));
1143 println!("{:?}", result);
1144 assert!(result.is_ok());
1145 }
1146
1147 #[test]
1148 pub fn fix43() {
1149 let result = DataDictionary::load_from_string(include_str!("../../../spec/FIX43.xml"));
1151 println!("{:?}", result);
1152 assert!(result.is_ok());
1153 if let Ok(dd) = result {
1154 let newordersingle = dd.messages().get("D");
1155 let handlinst = dd.fields_by_name.get("HandlInst");
1156 assert!(newordersingle.is_some());
1157 assert!(handlinst.is_some());
1158 match (newordersingle, handlinst) {
1159 (Some(newordersingle), Some(handlinst)) => {
1160 let handlinst_in_message = newordersingle.fields.contains_key(&handlinst.tag);
1161 println!("{:?}", handlinst_in_message);
1162 assert!(handlinst_in_message)
1163 }
1164 _ => (),
1165 }
1166 }
1167 }
1168
1169 #[test]
1170 pub fn fix44() {
1171 let result = DataDictionary::load_from_string(include_str!("../../../spec/FIX44.xml"));
1172 println!("{:?}", result);
1173 assert!(result.is_ok());
1174 }
1175
1176 #[test]
1177 pub fn fix50() {
1178 let result = DataDictionary::load_from_string(include_str!("../../../spec/FIX50.xml"));
1180 println!("{:?}", result);
1181 assert!(result.is_ok());
1182 }
1183
1184 #[test]
1185 pub fn fix50sp1() {
1186 let result = DataDictionary::load_from_string(include_str!("../../../spec/FIX50SP1.xml"));
1188 println!("{:?}", result);
1189 assert!(result.is_ok());
1190 }
1191
1192 #[test]
1193 pub fn fix50sp2() {
1194 let result = DataDictionary::load_from_string(include_str!("../../../spec/FIX50SP2.xml"));
1196 println!("{:?}", result);
1197 assert!(result.is_ok());
1198 }
1199
1200 #[test]
1201 pub fn fixt11() {
1202 let result = DataDictionary::load_from_string(include_str!("../../../spec/FIXT11.xml"));
1204 println!("{:?}", result);
1205 assert!(result.is_ok());
1206 }
1207}