Skip to main content

dfx_base/
message.rs

1
2
3
4use crate::data_dictionary::DDGroup;
5use crate::data_dictionary::DDMap;
6use crate::data_dictionary::ArcGroup;
7use crate::data_dictionary::DataDictionary;
8use crate::data_dictionary::MessageValidationError;
9use crate::data_dictionary::TagException;
10use crate::field_map::FieldBase;
11use crate::field_map::FieldMap;
12use crate::field_map::FieldMapError;
13use crate::field_map::Group;
14use crate::field_map::Tag;
15use crate::fix_values::SessionRejectReason;
16use crate::fields::ApplVerID;
17use crate::fields::ConversionError;
18use crate::fix_values;
19pub use crate::message_factory::*;
20use crate::parser::read_msg_type;
21use crate::session_id::SessionId;
22use crate::tags;
23use std::fmt::Display;
24use std::ops::Deref;
25use std::ops::DerefMut;
26
27#[derive(Default, Clone, Debug)]
28pub struct Header(FieldMap);
29
30impl Header {
31    pub fn calculate_string(&self) -> String {
32        self.0.calculate_string(Some(HEADER_FIELD_ORDER.to_vec()))
33    }
34}
35
36const HEADER_FIELD_ORDER: [Tag; 3] = [tags::BeginString, tags::BodyLength, tags::MsgType];
37// const HEADER_FIELD_ORDER: Vec<Tag> = vec![ tags::BeginString, tags::BodyLength, tags::MsgType ];
38
39impl Deref for Header {
40    type Target = FieldMap;
41    fn deref(&self) -> &Self::Target {
42        &self.0
43    }
44}
45
46impl DerefMut for Header {
47    fn deref_mut(&mut self) -> &mut Self::Target {
48        &mut self.0
49    }
50}
51
52#[derive(Default, Clone, Debug)]
53pub struct Trailer(FieldMap);
54
55impl Trailer {
56    pub fn calculate_string(&self) -> String {
57        self.0.calculate_string(Some(TRAILER_FIELD_ORDER.to_vec()))
58    }
59}
60
61const TRAILER_FIELD_ORDER: [Tag; 3] = [tags::SignatureLength, tags::Signature, tags::CheckSum];
62// const TRAILER_FIELD_ORDER: Vec<Tag> = vec![ tags::SignatureLength, tags::Signature, tags::CheckSum ];
63
64impl Deref for Trailer {
65    type Target = FieldMap;
66    fn deref(&self) -> &Self::Target {
67        &self.0
68    }
69}
70
71impl DerefMut for Trailer {
72    fn deref_mut(&mut self) -> &mut Self::Target {
73        &mut self.0
74    }
75}
76
77#[derive(Clone)]
78pub struct Message {
79    header: Header,
80    body: FieldMap,
81    trailer: Trailer,
82    // application_data_dictionary: Option<DataDictionary>,
83    field_: Tag,
84    valid_structure_: bool,
85}
86
87impl Default for Message {
88    fn default() -> Self {
89        Message {
90            header: Header::default(),
91            body: FieldMap::default(),
92            trailer: Trailer::default(),
93            // application_data_dictionary: None,
94            field_: 0,
95            valid_structure_: true,
96        }
97    }
98}
99
100impl std::fmt::Debug for Message {
101    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
102        fmt.write_str(
103            format!(
104                "Message (\n\tHeader {:?},\n\tBody: {:?},\n\ttrailer: {:?}\n)",
105                self.header, self.body, self.trailer
106            )
107            .as_str(),
108        )
109    }
110}
111
112impl Message {
113    pub const SOH: char = 1 as char;
114
115    pub fn new(msgstr: &[u8]) -> Result<Self, MessageParseError> {
116        let mut message = Message::default();
117        message.from_string::<DefaultMessageFactory>(msgstr, true, None, None, None, false)?;
118        Ok(message)
119    }
120
121    pub fn header(&self) -> &Header {
122        &self.header
123    }
124    pub fn header_mut(&mut self) -> &mut Header {
125        &mut self.header
126    }
127    pub fn trailer(&self) -> &Trailer {
128        &self.trailer
129    }
130    pub fn trailer_mut(&mut self) -> &mut Trailer {
131        &mut self.trailer
132    }
133
134    pub fn has_valid_structure(&self) -> Result<(), MessageValidationError> {
135        if self.valid_structure_ {
136            Ok(())
137        } else {
138            Err(MessageValidationError::TagException(TagException::tag_out_of_order(self.field_)))
139        }
140    }
141
142    pub fn is_header_field(tag: Tag, data_dictionary: Option<&DataDictionary>) -> bool {
143        match tag {
144            tags::BeginString => true,
145            tags::BodyLength => true,
146            tags::MsgType => true,
147            tags::SenderCompID => true,
148            tags::TargetCompID => true,
149            tags::OnBehalfOfCompID => true,
150            tags::DeliverToCompID => true,
151            tags::SecureDataLen => true,
152            tags::MsgSeqNum => true,
153            tags::SenderSubID => true,
154            tags::SenderLocationID => true,
155            tags::TargetSubID => true,
156            tags::TargetLocationID => true,
157            tags::OnBehalfOfSubID => true,
158            tags::OnBehalfOfLocationID => true,
159            tags::DeliverToSubID => true,
160            tags::DeliverToLocationID => true,
161            tags::PossDupFlag => true,
162            tags::PossResend => true,
163            tags::SendingTime => true,
164            tags::OrigSendingTime => true,
165            tags::XmlDataLen => true,
166            tags::XmlData => true,
167            tags::MessageEncoding => true,
168            tags::LastMsgSeqNumProcessed => true,
169            tags::OnBehalfOfSendingTime => true, //TODO
170            _ => match data_dictionary {
171                Some(dd) => dd.is_header_field(tag),
172                None => false,
173            },
174        }
175    }
176
177    pub fn is_trailer_field(tag: Tag, data_dictionary: Option<&DataDictionary>) -> bool {
178        match tag {
179            tags::SignatureLength => true,
180            tags::Signature => true,
181            tags::CheckSum => true,
182            _ => match data_dictionary {
183                Some(dd) => dd.is_trailer_field(tag),
184                None => false,
185            },
186        }
187    }
188
189    fn extract_field(
190        msgstr: &[u8],
191        pos: &mut usize,
192        _session_dd: Option<&DataDictionary>,
193        _app_dd: Option<&DataDictionary>,
194        size_hint: Option<usize>,
195    ) -> Result<FieldBase, MessageParseError> {
196        let tagend = msgstr[*pos..].iter().position(|c| *c == '=' as u8)
197            .ok_or_else(|| MessageParseError::FailedToFindEqualsAt(*pos))?;
198
199        let tagend = *pos + tagend;
200        if *pos >= tagend {
201            return Err(MessageParseError::PosGreaterThanLen(*pos, tagend));
202        }
203
204        let mut tag = 0;
205        let mut neg = false;
206        let mut start = true;
207        for byte in &msgstr[*pos..tagend] {
208            let byte = *byte;
209            if byte == b'-' && start {
210                neg = true;
211                start = false;
212            } else if byte >= b'0' && byte <= b'9' {
213                tag = 10 * tag;
214                tag += byte as Tag - b'0' as Tag;
215                start = false;
216            } else {
217                return Err(MessageParseError::InvalidTagNumber(String::from_utf8_lossy(&msgstr[*pos..tagend]).to_string()));
218            }
219        }
220        let tag = if neg { -tag } else { tag };
221        eprintln!("tag: {tag}");
222
223        *pos = tagend + 1;
224
225        let fieldend = if let Some(value) = size_hint {
226            Some(value)
227        } else {
228            msgstr[*pos..].iter().position(|c| *c == Message::SOH as u8)
229        };
230        let fieldend = fieldend.ok_or_else(|| MessageParseError::FailedToFindSohAt(*pos))?;
231        let fieldend = *pos + fieldend;
232        let value = &msgstr[*pos..fieldend];
233        let field = FieldBase::from_bytes(tag, value.into());
234
235        /*
236         TODO data dict stuff
237        if (((null != sessionDD) && sessionDD.IsDataField(field.Tag)) || ((null != appDD) && appDD.IsDataField(field.Tag)))
238        {
239            string fieldLength = "";
240            // Assume length field is 1 less
241            int lenField = field.Tag - 1;
242            // Special case for Signature which violates above assumption
243            if (Tags.Signature.Equals(field.Tag))
244                lenField = Tags.SignatureLength;
245            if ((null != group) && group.isSetField(lenField))
246            {
247                fieldLength = group.GetField(lenField);
248                soh = equalSign + 1 + atol(fieldLength.c_str());
249            }
250            else if (isSetField(lenField))
251            {
252                fieldLength = getField(lenField);
253                soh = equalSign + 1 + atol(fieldLength.c_str());
254            }
255        }
256        */
257
258        *pos = fieldend + 1;
259        Ok(field)
260    }
261
262    /// Creates a Message from a FIX string.
263    ///
264    /// msg_factory
265    /// > If [None], any groups will be constructed as generic Group objects
266    ///
267    /// ignoreBody
268    /// > (default false) if true, ignores all non-header and non-trailer fields.
269    /// >
270    /// > Intended for callers that only need rejection-related information from the header.
271    pub fn from_string<MsgFactory: MessageFactory>(
272        &mut self,
273        msgstr: &[u8],
274        validate: bool,
275        session_dd: Option<&DataDictionary>,
276        app_dd: Option<&DataDictionary>,
277        msg_factory: Option<&MsgFactory>,
278        ignore_body: bool,
279    ) -> Result<(), MessageParseError> {
280        // self.application_data_dictionary = app_dd.cloned();
281        self.clear();
282
283        let mut msg_type;
284        let mut expecting_header = true;
285        let mut expecting_body = true;
286        let mut count = 0;
287        let mut pos = 0;
288        let mut msg_map: Option<&DDMap> = None;
289        let mut size_hint = None;
290
291        while pos < msgstr.len() {
292            let f = Message::extract_field(msgstr, &mut pos, session_dd, app_dd, size_hint)?;
293            match (session_dd, app_dd) {
294                (Some(session_dd), _) if session_dd.is_length_field(f.tag()) => {
295                    size_hint = f.to_usize()
296                }
297                (_, Some(app_dd)) if app_dd.is_length_field(f.tag()) => size_hint = f.to_usize(),
298                _ => size_hint = None,
299            };
300
301            if validate && count < 3 && HEADER_FIELD_ORDER[count] != f.tag() {
302                return Err(MessageParseError::InvalidMessage(
303                    "Header fields out of order".into(),
304                ));
305            }
306            count += 1;
307
308            if Message::is_header_field(f.tag(), session_dd) {
309                if !expecting_header {
310                    if 0 == self.field_ {
311                        self.field_ = f.tag();
312                    }
313                    self.valid_structure_ = false;
314                }
315
316                if tags::MsgType == f.tag() {
317                    msg_type = f.string_value();
318                    if let Some(app_dd) = app_dd {
319                        msg_map = app_dd.get_map_for_message(msg_type?.as_str());
320                    }
321                }
322
323                if !self.header.set_field_base(f.clone(), Some(false)) {
324                    self.header.repeated_tags_mut().push(f.clone());
325                }
326
327                match session_dd {
328                    Some(dd) if dd.header().is_group(f.tag()) => {
329                        pos = Message::set_group(
330                            f.clone(),
331                            msgstr,
332                            pos,
333                            &mut self.header,
334                            dd.header().get_group(f.tag()),
335                            session_dd,
336                            app_dd,
337                            msg_factory,
338                        )?;
339                    },
340                    _ => {}
341                }
342            } else if Message::is_trailer_field(f.tag(), session_dd) {
343                expecting_header = false;
344                expecting_body = false;
345                if !self.trailer.set_field_base(f.clone(), Some(false)) {
346                    self.trailer.repeated_tags_mut().push(f.clone());
347                }
348
349                match session_dd {
350                    Some(dd) if dd.header().is_group(f.tag()) => {
351                        pos = Message::set_group(
352                            f.clone(),
353                            msgstr,
354                            pos,
355                            &mut self.trailer,
356                            dd.trailer().get_group(f.tag()),
357                            session_dd,
358                            app_dd,
359                            msg_factory,
360                        )?;
361                    },
362                    _ => {}
363                }
364            } else if !ignore_body {
365                if !expecting_body {
366                    if self.field_ == 0 {
367                        self.field_ = f.tag();
368                    }
369                    self.valid_structure_ = false;
370                }
371
372                expecting_header = false;
373                if !self.set_field_base(f.clone(), Some(false)) {
374                    self.repeated_tags_mut().push(f.clone());
375                }
376
377                match msg_map {
378                    Some(map) if map.is_group(f.tag()) => {
379                        pos = Message::set_group(
380                            f.clone(),
381                            msgstr,
382                            pos,
383                            self,
384                            map.get_group(f.tag()),
385                            session_dd,
386                            app_dd,
387                            msg_factory,
388                        )?;
389                    },
390                    _ => {},
391                }
392            }
393        }
394
395        if validate {
396            self.validate()?;
397        }
398        Ok(())
399    }
400
401    fn set_group<MsgFactory: MessageFactory>(
402        grp_no_fld: FieldBase,
403        msgstr: &[u8],
404        pos: usize,
405        map: &mut FieldMap,
406        group_dd: Option<&ArcGroup>,
407        session_dd: Option<&DataDictionary>,
408        app_dd: Option<&DataDictionary>,
409        msg_factory: Option<&MsgFactory>,
410    ) -> Result<usize, MessageParseError> {
411        match group_dd {
412            Some(group_dd) => {
413                let mut pos = pos;
414                let grp_entry_delimiter_tag = group_dd.delim();
415                let grp_pos = pos;
416                let mut group: Option<Group> = None;
417                let mut size_hint = None;
418
419                while pos < msgstr.len() {
420                    let grp_pos = pos;
421                    let f = Message::extract_field(msgstr, &mut pos, session_dd, app_dd, size_hint)?;
422                    match (session_dd, app_dd) {
423                        (Some(session_dd), _) if session_dd.is_length_field(f.tag()) => {
424                            size_hint = f.to_usize()
425                        }
426                        (_, Some(app_dd)) if app_dd.is_length_field(f.tag()) => size_hint = f.to_usize(),
427                        _ => size_hint = None,
428                    };
429                    if f.tag() == grp_entry_delimiter_tag {
430
431                        if let Some(ingroup) = group {
432                            // We were already building an entry, so the delimiter means it's done.
433                            map.add_group(f.tag(), &ingroup, Some(false));
434                            group = None;
435                        }
436
437                        // Create a new group!
438                        if let Some(factory) = msg_factory.as_ref() {
439                            let begin_string = Message::extract_begin_string(msgstr)?;
440                            let msg_type = Message::get_msg_type(msgstr)?;
441                            group = factory.create_group(
442                                begin_string.as_str(),
443                                msg_type,
444                                grp_no_fld.tag(),
445                            );
446                        }
447
448                        //If above failed (shouldn't ever happen), just use a generic Group.
449                        if group.is_none() {
450                            group = Some(Group::new(grp_no_fld.tag(), grp_entry_delimiter_tag));
451                        }
452
453                    } else if !group_dd.is_field(f.tag()) {
454                        // This field is not in the group, thus the repeating group is done.
455
456                        if let Some(group) = group {
457                            map.add_group(f.tag(), &group, Some(false));
458                        }
459                        return Ok(grp_pos);
460                    } else if group_dd.is_field(f.tag())
461                        && matches!(&group, Some(group) if group.is_field_set(f.tag()))
462                    {
463                        // Tag is appearing for the second time within a group element.
464                        // Presumably the sender didn't set the delimiter (or their DD has a different delimiter).
465
466                        return Err(
467                            MessageParseError::RepeatedTagWithoutGroupDelimiterTagException(
468                                grp_no_fld.tag(),
469                                f.tag(),
470                            ),
471                        );
472                    }
473
474                    match group.as_mut() {
475                        Some(group) => {
476                            // f is just a field in our group entry.  Add it and iterate again.
477                            group.set_field_base(f.clone(), None);
478
479                            if group_dd.is_group(f.tag()) {
480                                // f is a counter for a nested group.  Recurse!
481
482                                pos = Message::set_group(
483                                    f.clone(),
484                                    msgstr,
485                                    pos,
486                                    group,
487                                    group_dd.get_group(f.tag()),
488                                    session_dd,
489                                    app_dd,
490                                    msg_factory,
491                                )?;
492                            }
493                        },
494                        None => {
495                            // This means we got into the group's fields without finding a delimiter tag.
496                            let _b = &msgstr[pos..];
497                            return Err(MessageParseError::GroupDelimiterTagException(
498                                grp_no_fld.tag(),
499                                grp_entry_delimiter_tag,
500                            ));
501                        }
502                    }
503                }
504
505                Ok(grp_pos)
506            },
507            None => Ok(pos),
508        }
509    }
510
511    fn validate(&self) -> Result<(), MessageParseError> {
512        let received_body_length = self.header.get_int(tags::BodyLength)?;
513        if self.body_length() != received_body_length {
514            return Err(MessageParseError::InvalidMessage(format!(
515                "Expected BodyLength={}, Received BodyLength={}, Message.SeqNum={}",
516                self.body_length(),
517                received_body_length,
518                self.header.get_int(tags::MsgSeqNum)?
519            )));
520        }
521        let received_checksum = self.trailer.get_int(tags::CheckSum)?;
522        if self.checksum() != received_checksum {
523            return Err(MessageParseError::InvalidMessage(format!(
524                "Expected CheckSum={}, Received CheckSum={}, Message.SeqNum={}",
525                self.checksum(),
526                received_checksum,
527                self.header.get_int(tags::MsgSeqNum)?
528            )));
529        }
530        Ok(())
531    }
532
533    fn body_length(&self) -> u32 {
534        self.header.len() + self.len() + self.trailer.len()
535    }
536
537    fn checksum(&self) -> u32 {
538        (self.header.calculate_total() + self.calculate_total() + self.trailer.calculate_total())
539            % 256
540    }
541
542    fn clear(&mut self) {
543        self.field_ = 0;
544        self.header.clear();
545        self.body.clear();
546        self.trailer.clear();
547    }
548
549    pub fn to_string_mut(&mut self) -> String {
550        let len = self.body_length().to_string();
551        self.header
552            .set_field_base(FieldBase::new(tags::BodyLength, len), Some(true));
553        let checksum = format!("{:03}", self.checksum());
554        self.trailer
555            .set_field_base(FieldBase::new(tags::CheckSum, checksum), Some(true));
556        format!(
557            "{}{}{}",
558            self.header.calculate_string(),
559            self.calculate_string(None),
560            self.trailer.calculate_string()
561        )
562    }
563
564    pub fn is_admin(&self) -> bool {
565        matches!(self.header.get_field(tags::MsgType), Some(field) if Message::is_admin_msg_type(&field.value()))
566    }
567
568    pub fn is_admin_msg_type(msg_type: &[u8]) -> bool {
569        msg_type.len() == 1 && "0A12345n".contains(msg_type[0] as char)
570    }
571
572    pub fn extract_begin_string(msgstr: &[u8]) -> Result<String, MessageParseError> {
573        let mut pos = 0;
574        let f = Message::extract_field(msgstr, &mut pos, None, None, None)?;
575        Ok(f.string_value().clone()?)
576    }
577
578    pub(crate) fn get_msg_type(bytes: &[u8]) -> Result<&str, MessageParseError> {
579        match read_msg_type(bytes) {
580            Some(s) => Ok(s),
581            None => Err(MessageParseError::Malformed { tag: 35, message: format!(
582                    "missing or malformed tag 35 in msg: {:?}",
583                    String::from_utf8_lossy(bytes)
584            )})
585        }
586    }
587
588    pub fn identify_type(msg_str: &[u8]) -> Result<&str, MessageParseError> {
589        //TODO wrap in MsgType field?
590        Message::get_msg_type(msg_str)
591    }
592
593    pub fn get_appl_ver_id(begin_string: &str) -> Result<u32, String> {
594        match begin_string {
595            fix_values::BeginString::FIX40 => Ok(ApplVerID::FIX40),
596            fix_values::BeginString::FIX41 => Ok(ApplVerID::FIX41),
597            fix_values::BeginString::FIX42 => Ok(ApplVerID::FIX42),
598            fix_values::BeginString::FIX43 => Ok(ApplVerID::FIX43),
599            fix_values::BeginString::FIX44 => Ok(ApplVerID::FIX44),
600            fix_values::BeginString::FIX50 => Ok(ApplVerID::FIX50),
601            fix_values::BeginString::FIX50SP1 => Ok(ApplVerID::FIX50SP1),
602            fix_values::BeginString::FIX50SP2 => Ok(ApplVerID::FIX50SP2),
603            _ => Err(format!("ApplVerID for {} not supported", begin_string)),
604        }
605    }
606
607    pub fn reverse_route(&mut self, header: &Header) {
608        // required routing tags
609        self.header.remove_field(tags::BeginString);
610        self.header.remove_field(tags::SenderCompID);
611        self.header.remove_field(tags::SenderSubID);
612        self.header.remove_field(tags::SenderLocationID);
613        self.header.remove_field(tags::TargetCompID);
614        self.header.remove_field(tags::TargetSubID);
615        self.header.remove_field(tags::TargetLocationID);
616
617        if let Some(begin_string) = header.get_field(tags::BeginString) {
618            if begin_string.value().len() > 0 {
619                self.header.set_tag_value(tags::BeginString, begin_string.value());
620            }
621
622            self.header.remove_field(tags::OnBehalfOfLocationID);
623            self.header.remove_field(tags::DeliverToLocationID);
624
625            let value: &[u8] = begin_string.value();
626            if value >= b"FIX.4.1" {
627                if let Some(field) = header.get_field(tags::OnBehalfOfLocationID) {
628                    let on_behalf_of_location_id = field.value();
629                    if on_behalf_of_location_id.len() > 0 {
630                        self.header
631                            .set_tag_value(tags::DeliverToLocationID, on_behalf_of_location_id);
632                    }
633                }
634
635                if let Some(field) = header.get_field(tags::DeliverToLocationID) {
636                    let deliver_to_location_id = field.value();
637                    if deliver_to_location_id.len() > 0 {
638                        self.header
639                            .set_tag_value(tags::OnBehalfOfLocationID, deliver_to_location_id);
640                    }
641                }
642            }
643        }
644
645        if let Some(field) = header.get_field(tags::SenderCompID) {
646            let sender_comp_id = field.value();
647            if sender_comp_id.len() > 0 {
648                self.header.set_tag_value(tags::TargetCompID, sender_comp_id);
649            }
650        }
651
652        if let Some(field) = header.get_field(tags::SenderSubID) {
653            let sender_sub_id = field.value();
654            if sender_sub_id.len() > 0 {
655                self.header.set_tag_value(tags::TargetSubID, sender_sub_id);
656            }
657        }
658
659        if let Some(field) = header.get_field(tags::SenderLocationID) {
660            let sender_location_id = field.value();
661            if sender_location_id.len() > 0 {
662                self.header
663                    .set_tag_value(tags::TargetLocationID, sender_location_id);
664            }
665        }
666
667        if let Some(field) = header.get_field(tags::TargetCompID) {
668            let target_comp_id = field.value();
669            if target_comp_id.len() > 0 {
670                self.header.set_tag_value(tags::SenderCompID, target_comp_id);
671            }
672        }
673
674        if let Some(field) = header.get_field(tags::TargetSubID) {
675            let target_sub_id = field.value();
676            if target_sub_id.len() > 0 {
677                self.header.set_tag_value(tags::SenderSubID, target_sub_id);
678            }
679        }
680
681        if let Some(field) = header.get_field(tags::TargetLocationID) {
682            let target_location_id = field.value();
683            if target_location_id.len() > 0 {
684                self.header
685                    .set_tag_value(tags::SenderLocationID, target_location_id);
686            }
687        }
688
689        // optional routing tags
690        self.header.remove_field(tags::OnBehalfOfCompID);
691        self.header.remove_field(tags::OnBehalfOfSubID);
692        self.header.remove_field(tags::DeliverToCompID);
693        self.header.remove_field(tags::DeliverToSubID);
694
695        if let Some(field) = header.get_field(tags::OnBehalfOfCompID) {
696            let on_behalf_of_comp_id = field.value();
697            if on_behalf_of_comp_id.len() > 0 {
698                self.header
699                    .set_tag_value(tags::DeliverToCompID, on_behalf_of_comp_id);
700            }
701        }
702
703        if let Some(field) = header.get_field(tags::OnBehalfOfSubID) {
704            let on_behalf_of_sub_id = field.value();
705            if on_behalf_of_sub_id.len() > 0 {
706                self.header
707                    .set_tag_value(tags::DeliverToSubID, on_behalf_of_sub_id);
708            }
709        }
710
711        if let Some(field) = header.get_field(tags::DeliverToCompID) {
712            let deliver_to_comp_id = field.value();
713            if deliver_to_comp_id.len() > 0 {
714                self.header
715                    .set_tag_value(tags::OnBehalfOfCompID, deliver_to_comp_id);
716            }
717        }
718
719        if let Some(field) = header.get_field(tags::DeliverToSubID) {
720            let deliver_to_sub_id = field.value();
721            if deliver_to_sub_id.len() > 0 {
722                self.header
723                    .set_tag_value(tags::OnBehalfOfSubID, deliver_to_sub_id);
724            }
725        }
726    }
727
728    pub fn extract_contra_session_id(&self) -> SessionId {
729        SessionId::new(
730            self.header
731                .get_string(tags::BeginString)
732                .unwrap_or_default(),
733            self.header
734                .get_string(tags::TargetCompID)
735                .unwrap_or_default(),
736            self.header
737                .get_string(tags::TargetSubID)
738                .unwrap_or_default(),
739            self.header
740                .get_string(tags::TargetLocationID)
741                .unwrap_or_default(),
742            self.header
743                .get_string(tags::SenderCompID)
744                .unwrap_or_default(),
745            self.header
746                .get_string(tags::SenderSubID)
747                .unwrap_or_default(),
748            self.header
749                .get_string(tags::SenderLocationID)
750                .unwrap_or_default(),
751        )
752    }
753}
754
755impl Deref for Message {
756    type Target = FieldMap;
757    fn deref(&self) -> &Self::Target {
758        &self.body
759    }
760}
761
762impl DerefMut for Message {
763    fn deref_mut(&mut self) -> &mut Self::Target {
764        &mut self.body
765    }
766}
767
768impl Display for Message {
769    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
770        fmt.write_fmt(format_args!(
771            "{}{}{}",
772            self.header.calculate_string(),
773            self.calculate_string(None),
774            self.trailer.calculate_string()
775        ))
776    }
777}
778
779#[derive(Debug, Clone)]
780pub enum MessageParseError {
781    InvalidMessage(String),
782    InvalidTagNumber(String),
783    FailedToFindEqualsAt(usize),
784    FailedToFindSohAt(usize),
785    PosGreaterThanLen(usize, usize),
786    RepeatedTagWithoutGroupDelimiterTagException(Tag, Tag),
787    GroupDelimiterTagException(Tag, Tag),
788    FieldMapError(FieldMapError),
789    Malformed { tag: Tag, message: String },
790    ConversionError(ConversionError),
791}
792
793impl From<FieldMapError> for MessageParseError {
794    fn from(e: FieldMapError) -> MessageParseError {
795        MessageParseError::FieldMapError(e)
796    }
797}
798
799impl From<ConversionError> for MessageParseError {
800    fn from(e: ConversionError) -> MessageParseError {
801        MessageParseError::ConversionError(e)
802    }
803}
804
805impl MessageParseError {
806    pub fn as_tag(&self) -> Option<Tag> {
807        match self {
808            Self::InvalidMessage(_) => None,
809            Self::InvalidTagNumber(_) => None,
810            Self::FailedToFindEqualsAt(_) => todo!(),
811            Self::FailedToFindSohAt(_) => todo!(),
812            Self::PosGreaterThanLen(_, _) => todo!(),
813            Self::RepeatedTagWithoutGroupDelimiterTagException(_num, _delim) => todo!(),
814            Self::GroupDelimiterTagException(num, _delim) => Some(*num),
815            Self::FieldMapError(_) => todo!(),
816            Self::Malformed { tag, .. } => Some(*tag),
817            Self::ConversionError(_) => todo!(),
818        }
819    }
820    pub fn as_session_reject(self) -> Option<SessionRejectReason> {
821        match self {
822            Self::InvalidMessage(reason) => Some(SessionRejectReason::OTHER(reason)),
823            Self::InvalidTagNumber(_) => Some(SessionRejectReason::INVALID_TAG_NUMBER()),
824            Self::FailedToFindEqualsAt(_) => None,
825            Self::FailedToFindSohAt(_) => None,
826            Self::PosGreaterThanLen(_, _) => None,
827            Self::RepeatedTagWithoutGroupDelimiterTagException(_num, _delim) => None,
828            Self::GroupDelimiterTagException(num, delim) => Some(TagException::group_delimiter_tag_exception(num, delim).session_reject_reason().clone()),
829            Self::FieldMapError(_) => None,
830            Self::Malformed { tag: _, .. } => Some(SessionRejectReason::INVALID_MSGTYPE()),
831            Self::ConversionError(_) => None,
832        }
833    }
834}
835
836#[cfg(test)]
837mod tests {
838    use super::Message;
839    use crate::data_dictionary::DataDictionary;
840    use crate::message::MessageParseError;
841    use crate::message_factory::DefaultMessageFactory;
842    use std::fs::File;
843    #[test]
844    fn test_parse() {
845        let dd = DataDictionary::from_file("../../spec/FIX44.xml").expect("Able to read FIX44.xml file.");
846        println!("{:#?}", dd);
847
848        let mut message = Message::default();
849
850        // let msgstr = "8=FIXT.1.1\x019=73\x0135=W\x0134=3\x0149=sender\x0152=20110909-09:09:09.999\x0156=target\x0155=sym\x01268=1\x01269=0\x01272=20111012\x01273=22:15:30.444\x0110=249\x01";
851        let expected = "8=FIX.4.4|9=115|35=A|34=1|49=sender-comp-id|52=20221025-10:49:30.969|56=target-comp-id|98=0|108=30|141=Y|553=username|554=password|10=159|";
852
853        let msgstr = expected.replace('|', "\x01");
854        let result =
855            message.from_string::<DefaultMessageFactory>(msgstr.as_bytes(), true, Some(&dd), Some(&dd), None, false);
856        println!("{:?}", result);
857        assert!(result.is_ok());
858
859        let actual = message.to_string_mut().replace(Message::SOH, "|");
860
861        println!("{:?}", expected);
862        println!("{:?}", actual);
863        assert_eq!(expected, actual);
864    }
865
866    #[test]
867    fn test_validate() {
868        let dd = DataDictionary::from_file("../../spec/FIX44.xml").expect("Able to read FIX44.xml file.");
869
870        let mut message = Message::default();
871
872        // let msgstr = "8=FIXT.1.1\x019=73\x0135=W\x0134=3\x0149=sender\x0152=20110909-09:09:09.999\x0156=target\x0155=sym\x01268=1\x01269=0\x01272=20111012\x01273=22:15:30.444\x0110=249\x01";
873        let expected = "8=FIX.4.4|9=115|35=A|34=1|49=sender-comp-id|52=20221025-10:49:30.969|56=target-comp-id|98=0|108=30|141=Y|553=username|554=password|10=159|";
874
875        let msgstr = expected.replace('|', "\x01");
876        let result =
877            message.from_string::<DefaultMessageFactory>(msgstr.as_bytes(), true, Some(&dd), Some(&dd), None, false);
878        println!("{:?}", result);
879        assert!(result.is_ok());
880        assert!(message.is_admin());
881
882        let actual = message.to_string_mut().replace(Message::SOH, "|");
883
884        println!("{:?}", expected);
885        println!("{:?}", actual);
886        assert_eq!(expected, actual);
887
888        let result = DataDictionary::validate(&message, Some(&dd), &dd, "FIX.4.4", "A");
889        println!("{:?}", message);
890        println!("{:?}", result);
891        assert!(result.is_ok());
892    }
893
894    #[test]
895    fn test_get_msg_type_success() {
896        let msgstr = "8=FIX.4.4|9=115|35=A|34=1|49=sender-comp-id|52=20221025-10:49:30.969|56=target-comp-id|98=0|108=30|141=Y|553=username|554=password|10=159|";
897        let msgstr = msgstr.replace('|', "\x01");
898        let msg_type = Message::get_msg_type(msgstr.as_bytes());
899        assert!(msg_type.is_ok());
900        assert!(matches!(msg_type, Ok(msg_type) if msg_type == "A"));
901    }
902
903    #[test]
904    fn test_get_msg_type_failure() {
905        let msgstr = "8=FIX.4.4|9=115|35=|34=1|49=sender-comp-id|52=20221025-10:49:30.969|56=target-comp-id|98=0|108=30|141=Y|553=username|554=password|10=159|";
906        let msgstr = msgstr.replace('|', "\x01");
907        let msg_type = Message::get_msg_type(msgstr.as_bytes());
908        assert!(msg_type.is_err());
909        assert!(matches!(
910            msg_type,
911            Err(MessageParseError::Malformed { .. })
912        ));
913    }
914
915    #[test]
916    fn test_get_msg_type_raw_data() {
917        let dd = DataDictionary::from_file("../../spec/FIX44.xml").expect("Able to read FIX44.xml file.");
918
919        let mut message = Message::default();
920
921        // let msgstr = "8=FIXT.1.1\x019=73\x0135=W\x0134=3\x0149=sender\x0152=20110909-09:09:09.999\x0156=target\x0155=sym\x01268=1\x01269=0\x01272=20111012\x01273=22:15:30.444\x0110=249\x01";
922        let expected = b"8=FIX.4.4|9=127|35=0|34=1|49=sender-comp-id|52=20221025-10:49:30.969|56=target-comp-id|90=3|91=\xC1\x01\xC0|98=0|108=30|141=Y|553=username|554=password|10=149|";
923        let msgstr: Vec<u8> = expected
924            .iter()
925            .map(|b| if *b == '|' as u8 { 1_u8 } else { *b })
926            .collect();
927
928        let result = message.from_string::<DefaultMessageFactory>(&msgstr, false, Some(&dd), Some(&dd), None, false);
929        println!("{:?}", result);
930        let actual = message.to_string().replace(Message::SOH, "|");
931        println!("{}", actual);
932        assert!(result.is_ok());
933        assert!(message.is_admin());
934
935        let actual = message.to_string_mut().replace(Message::SOH, "|");
936
937        let msgstr: String = expected
938            .iter()
939            .map(|b| *b as char)
940            .map(|c| if c == Message::SOH { '|' } else { c })
941            .collect();
942
943        println!("{:?}", expected);
944        println!("{:?}", actual);
945
946        assert_eq!(msgstr, actual);
947
948        let result = DataDictionary::validate(&message, Some(&dd), &dd, "FIX.4.4", "A");
949        println!("{:?}", message);
950        println!("{:?}", result);
951        assert!(result.is_ok());
952    }
953}