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];
37impl 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];
62impl 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 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 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, _ => 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 *pos = fieldend + 1;
259 Ok(field)
260 }
261
262 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.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 map.add_group(f.tag(), &ingroup, Some(false));
434 group = None;
435 }
436
437 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 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 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 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 group.set_field_base(f.clone(), None);
478
479 if group_dd.is_group(f.tag()) {
480 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 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 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 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 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 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 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 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}