Skip to main content

dfx_base/
data_dictionary.rs

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    // MissingGroupDefinition(),
32    //DictionaryParseException(Arc<str>),
33    ConversionError(ConversionError),
34    //InvalidStructure(u32),
35}
36
37#[derive(Clone, Debug)]
38pub struct TagException {
39    field: Tag,
40    session_reject_reason: SessionRejectReason,
41    inner: Option<String>, //todo
42    msg_type: Option<String>, //todo
43}
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    } //TODO inner
73    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)]
116/// TODO
117pub 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>;
148// type DGroup = DDGroup;
149pub(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            //TODO should this accept msg_type?
264            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        // TODO check format based on type received.
312        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        // check non-group fields
443        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        // check contents of each group
472        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                // check contents of each nested group
517                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        // match self.fields_by_tag.get(&tag) {
541        //     Some(field) => field.field_type().as_ref() == "LENGTH" && field.name().as_ref() != "BodyLength",
542        //     None => false,
543        // }
544        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        // TODO type?
722        // is_multiple_value_field_with_enums: bool
723    ) -> 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                    //TODO check if ddmap is a ddgroup and set delim!
1078                    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("../../../spec/FIX43.xml");
1142        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("../../../spec/FIX43.xml");
1150        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("../../../spec/FIX43.xml");
1179        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("../../../spec/FIX43.xml");
1187        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("../../../spec/FIX43.xml");
1195        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("../../../spec/FIX43.xml");
1203        let result = DataDictionary::load_from_string(include_str!("../../../spec/FIXT11.xml"));
1204        println!("{:?}", result);
1205        assert!(result.is_ok());
1206    }
1207}