1use crate::error::DecodeError;
16use crate::field::FieldRef;
17use bytes::Bytes;
18use serde::{Deserialize, Serialize};
19use smallvec::SmallVec;
20use std::fmt;
21use std::ops::Range;
22
23#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
28pub enum MsgType {
29 #[default]
31 Heartbeat,
32 TestRequest,
34 ResendRequest,
36 Reject,
38 SequenceReset,
40 Logout,
42 IndicationOfInterest,
44 Advertisement,
46 ExecutionReport,
48 OrderCancelReject,
50 Logon,
52 News,
54 Email,
56 NewOrderSingle,
58 NewOrderList,
60 OrderCancelRequest,
62 OrderCancelReplaceRequest,
64 OrderStatusRequest,
66 AllocationInstruction,
68 ListCancelRequest,
70 ListExecute,
72 ListStatusRequest,
74 ListStatus,
76 AllocationInstructionAck,
78 DontKnowTrade,
80 QuoteRequest,
82 Quote,
84 SettlementInstructions,
86 MarketDataRequest,
88 MarketDataSnapshotFullRefresh,
90 MarketDataIncrementalRefresh,
92 MarketDataRequestReject,
94 QuoteCancel,
96 QuoteStatusRequest,
98 MassQuoteAcknowledgement,
100 SecurityDefinitionRequest,
102 SecurityDefinition,
104 SecurityStatusRequest,
106 SecurityStatus,
108 TradingSessionStatusRequest,
110 TradingSessionStatus,
112 MassQuote,
114 BusinessMessageReject,
116 BidRequest,
118 BidResponse,
120 ListStrikePrice,
122 XmlMessage,
124 RegistrationInstructions,
126 RegistrationInstructionsResponse,
128 OrderMassCancelRequest,
130 OrderMassCancelReport,
132 NewOrderCross,
134 CrossOrderCancelReplaceRequest,
136 CrossOrderCancelRequest,
138 SecurityTypeRequest,
140 SecurityTypes,
142 SecurityListRequest,
144 SecurityList,
146 DerivativeSecurityListRequest,
148 Custom(String),
150}
151
152impl std::str::FromStr for MsgType {
153 type Err = std::convert::Infallible;
154
155 fn from_str(s: &str) -> Result<Self, Self::Err> {
160 Ok(match s {
161 "0" => Self::Heartbeat,
162 "1" => Self::TestRequest,
163 "2" => Self::ResendRequest,
164 "3" => Self::Reject,
165 "4" => Self::SequenceReset,
166 "5" => Self::Logout,
167 "6" => Self::IndicationOfInterest,
168 "7" => Self::Advertisement,
169 "8" => Self::ExecutionReport,
170 "9" => Self::OrderCancelReject,
171 "A" => Self::Logon,
172 "B" => Self::News,
173 "C" => Self::Email,
174 "D" => Self::NewOrderSingle,
175 "E" => Self::NewOrderList,
176 "F" => Self::OrderCancelRequest,
177 "G" => Self::OrderCancelReplaceRequest,
178 "H" => Self::OrderStatusRequest,
179 "J" => Self::AllocationInstruction,
180 "K" => Self::ListCancelRequest,
181 "L" => Self::ListExecute,
182 "M" => Self::ListStatusRequest,
183 "N" => Self::ListStatus,
184 "P" => Self::AllocationInstructionAck,
185 "Q" => Self::DontKnowTrade,
186 "R" => Self::QuoteRequest,
187 "S" => Self::Quote,
188 "T" => Self::SettlementInstructions,
189 "V" => Self::MarketDataRequest,
190 "W" => Self::MarketDataSnapshotFullRefresh,
191 "X" => Self::MarketDataIncrementalRefresh,
192 "Y" => Self::MarketDataRequestReject,
193 "Z" => Self::QuoteCancel,
194 "a" => Self::QuoteStatusRequest,
195 "b" => Self::MassQuoteAcknowledgement,
196 "c" => Self::SecurityDefinitionRequest,
197 "d" => Self::SecurityDefinition,
198 "e" => Self::SecurityStatusRequest,
199 "f" => Self::SecurityStatus,
200 "g" => Self::TradingSessionStatusRequest,
201 "h" => Self::TradingSessionStatus,
202 "i" => Self::MassQuote,
203 "j" => Self::BusinessMessageReject,
204 "k" => Self::BidRequest,
205 "l" => Self::BidResponse,
206 "m" => Self::ListStrikePrice,
207 "n" => Self::XmlMessage,
208 "o" => Self::RegistrationInstructions,
209 "p" => Self::RegistrationInstructionsResponse,
210 "q" => Self::OrderMassCancelRequest,
211 "r" => Self::OrderMassCancelReport,
212 "s" => Self::NewOrderCross,
213 "t" => Self::CrossOrderCancelReplaceRequest,
214 "u" => Self::CrossOrderCancelRequest,
215 "v" => Self::SecurityTypeRequest,
216 "w" => Self::SecurityTypes,
217 "x" => Self::SecurityListRequest,
218 "y" => Self::SecurityList,
219 "z" => Self::DerivativeSecurityListRequest,
220 other => Self::Custom(other.to_string()),
221 })
222 }
223}
224
225impl MsgType {
226 #[must_use]
228 pub fn as_str(&self) -> &str {
229 match self {
230 Self::Heartbeat => "0",
231 Self::TestRequest => "1",
232 Self::ResendRequest => "2",
233 Self::Reject => "3",
234 Self::SequenceReset => "4",
235 Self::Logout => "5",
236 Self::IndicationOfInterest => "6",
237 Self::Advertisement => "7",
238 Self::ExecutionReport => "8",
239 Self::OrderCancelReject => "9",
240 Self::Logon => "A",
241 Self::News => "B",
242 Self::Email => "C",
243 Self::NewOrderSingle => "D",
244 Self::NewOrderList => "E",
245 Self::OrderCancelRequest => "F",
246 Self::OrderCancelReplaceRequest => "G",
247 Self::OrderStatusRequest => "H",
248 Self::AllocationInstruction => "J",
249 Self::ListCancelRequest => "K",
250 Self::ListExecute => "L",
251 Self::ListStatusRequest => "M",
252 Self::ListStatus => "N",
253 Self::AllocationInstructionAck => "P",
254 Self::DontKnowTrade => "Q",
255 Self::QuoteRequest => "R",
256 Self::Quote => "S",
257 Self::SettlementInstructions => "T",
258 Self::MarketDataRequest => "V",
259 Self::MarketDataSnapshotFullRefresh => "W",
260 Self::MarketDataIncrementalRefresh => "X",
261 Self::MarketDataRequestReject => "Y",
262 Self::QuoteCancel => "Z",
263 Self::QuoteStatusRequest => "a",
264 Self::MassQuoteAcknowledgement => "b",
265 Self::SecurityDefinitionRequest => "c",
266 Self::SecurityDefinition => "d",
267 Self::SecurityStatusRequest => "e",
268 Self::SecurityStatus => "f",
269 Self::TradingSessionStatusRequest => "g",
270 Self::TradingSessionStatus => "h",
271 Self::MassQuote => "i",
272 Self::BusinessMessageReject => "j",
273 Self::BidRequest => "k",
274 Self::BidResponse => "l",
275 Self::ListStrikePrice => "m",
276 Self::XmlMessage => "n",
277 Self::RegistrationInstructions => "o",
278 Self::RegistrationInstructionsResponse => "p",
279 Self::OrderMassCancelRequest => "q",
280 Self::OrderMassCancelReport => "r",
281 Self::NewOrderCross => "s",
282 Self::CrossOrderCancelReplaceRequest => "t",
283 Self::CrossOrderCancelRequest => "u",
284 Self::SecurityTypeRequest => "v",
285 Self::SecurityTypes => "w",
286 Self::SecurityListRequest => "x",
287 Self::SecurityList => "y",
288 Self::DerivativeSecurityListRequest => "z",
289 Self::Custom(s) => s.as_str(),
290 }
291 }
292
293 #[must_use]
295 pub fn is_admin(&self) -> bool {
296 matches!(
297 self,
298 Self::Heartbeat
299 | Self::TestRequest
300 | Self::ResendRequest
301 | Self::Reject
302 | Self::SequenceReset
303 | Self::Logout
304 | Self::Logon
305 )
306 }
307
308 #[must_use]
310 pub fn is_app(&self) -> bool {
311 !self.is_admin()
312 }
313}
314
315impl fmt::Display for MsgType {
316 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
317 write!(f, "{}", self.as_str())
318 }
319}
320
321#[derive(Debug, Clone)]
327pub struct RawMessage<'a> {
328 buffer: &'a [u8],
330 begin_string: Range<usize>,
332 body: Range<usize>,
334 msg_type: MsgType,
336 fields: SmallVec<[FieldRef<'a>; 32]>,
338}
339
340impl<'a> RawMessage<'a> {
341 #[must_use]
350 pub fn new(
351 buffer: &'a [u8],
352 begin_string: Range<usize>,
353 body: Range<usize>,
354 msg_type: MsgType,
355 fields: SmallVec<[FieldRef<'a>; 32]>,
356 ) -> Self {
357 Self {
358 buffer,
359 begin_string,
360 body,
361 msg_type,
362 fields,
363 }
364 }
365
366 #[inline]
368 #[must_use]
369 pub const fn buffer(&self) -> &'a [u8] {
370 self.buffer
371 }
372
373 #[must_use]
375 pub fn begin_string(&self) -> &'a str {
376 std::str::from_utf8(&self.buffer[self.begin_string.clone()]).unwrap_or("")
377 }
378
379 #[inline]
381 #[must_use]
382 pub fn msg_type(&self) -> &MsgType {
383 &self.msg_type
384 }
385
386 #[inline]
388 pub fn fields(&self) -> impl Iterator<Item = &FieldRef<'a>> {
389 self.fields.iter()
390 }
391
392 #[inline]
394 #[must_use]
395 pub fn field_count(&self) -> usize {
396 self.fields.len()
397 }
398
399 #[must_use]
407 pub fn get_field(&self, tag: u32) -> Option<&FieldRef<'a>> {
408 self.fields.iter().find(|f| f.tag == tag)
409 }
410
411 #[must_use]
419 pub fn get_field_str(&self, tag: u32) -> Option<&'a str> {
420 self.get_field(tag).and_then(|f| f.as_str().ok())
421 }
422
423 pub fn get_field_as<T: std::str::FromStr>(&self, tag: u32) -> Result<T, DecodeError> {
431 self.get_field(tag)
432 .ok_or(DecodeError::MissingRequiredField { tag })?
433 .parse()
434 }
435
436 #[inline]
438 #[must_use]
439 pub fn body_range(&self) -> &Range<usize> {
440 &self.body
441 }
442
443 #[inline]
445 #[must_use]
446 pub fn len(&self) -> usize {
447 self.buffer.len()
448 }
449
450 #[inline]
452 #[must_use]
453 pub fn is_empty(&self) -> bool {
454 self.buffer.is_empty()
455 }
456
457 #[must_use]
459 pub fn to_owned(&self) -> OwnedMessage {
460 OwnedMessage::from_raw(self)
461 }
462}
463
464#[derive(Debug, Clone)]
469pub struct OwnedMessage {
470 buffer: Bytes,
472 msg_type: MsgType,
474 field_offsets: Vec<(u32, Range<usize>)>,
476}
477
478impl OwnedMessage {
479 #[must_use]
484 pub fn from_raw(raw: &RawMessage<'_>) -> Self {
485 let buffer = Bytes::copy_from_slice(raw.buffer);
486 let field_offsets = raw
487 .fields
488 .iter()
489 .map(|f| {
490 let start = f.value.as_ptr() as usize - raw.buffer.as_ptr() as usize;
491 let end = start + f.value.len();
492 (f.tag, start..end)
493 })
494 .collect();
495
496 Self {
497 buffer,
498 msg_type: raw.msg_type.clone(),
499 field_offsets,
500 }
501 }
502
503 #[must_use]
510 pub fn new(buffer: Bytes, msg_type: MsgType, field_offsets: Vec<(u32, Range<usize>)>) -> Self {
511 Self {
512 buffer,
513 msg_type,
514 field_offsets,
515 }
516 }
517
518 #[inline]
520 #[must_use]
521 pub fn msg_type(&self) -> &MsgType {
522 &self.msg_type
523 }
524
525 #[inline]
527 #[must_use]
528 pub fn as_bytes(&self) -> &[u8] {
529 &self.buffer
530 }
531
532 #[inline]
534 #[must_use]
535 pub fn len(&self) -> usize {
536 self.buffer.len()
537 }
538
539 #[inline]
541 #[must_use]
542 pub fn is_empty(&self) -> bool {
543 self.buffer.is_empty()
544 }
545
546 #[must_use]
554 pub fn get_field(&self, tag: u32) -> Option<&[u8]> {
555 self.field_offsets
556 .iter()
557 .find(|(t, _)| *t == tag)
558 .map(|(_, range)| &self.buffer[range.clone()])
559 }
560
561 #[must_use]
569 pub fn get_field_str(&self, tag: u32) -> Option<&str> {
570 self.get_field(tag)
571 .and_then(|b| std::str::from_utf8(b).ok())
572 }
573
574 #[inline]
576 #[must_use]
577 pub fn field_count(&self) -> usize {
578 self.field_offsets.len()
579 }
580
581 #[must_use]
583 pub fn into_bytes(self) -> Bytes {
584 self.buffer
585 }
586}
587
588pub trait FixMessage: Sized {
593 const MSG_TYPE: &'static str;
595
596 fn from_raw(raw: &RawMessage<'_>) -> Result<Self, DecodeError>;
604
605 fn encode(&self, buf: &mut Vec<u8>) -> Result<(), crate::error::EncodeError>;
613}
614
615#[cfg(test)]
616mod tests {
617 use super::*;
618
619 #[test]
620 fn test_msg_type_from_str() {
621 assert_eq!("0".parse::<MsgType>().unwrap(), MsgType::Heartbeat);
622 assert_eq!("A".parse::<MsgType>().unwrap(), MsgType::Logon);
623 assert_eq!("D".parse::<MsgType>().unwrap(), MsgType::NewOrderSingle);
624 assert_eq!("8".parse::<MsgType>().unwrap(), MsgType::ExecutionReport);
625 }
626
627 #[test]
628 fn test_msg_type_as_str() {
629 assert_eq!(MsgType::Heartbeat.as_str(), "0");
630 assert_eq!(MsgType::Logon.as_str(), "A");
631 assert_eq!(MsgType::NewOrderSingle.as_str(), "D");
632 }
633
634 #[test]
635 fn test_msg_type_is_admin() {
636 assert!(MsgType::Heartbeat.is_admin());
637 assert!(MsgType::Logon.is_admin());
638 assert!(MsgType::Logout.is_admin());
639 assert!(!MsgType::NewOrderSingle.is_admin());
640 assert!(!MsgType::ExecutionReport.is_admin());
641 }
642
643 #[test]
644 fn test_msg_type_custom() {
645 let custom: MsgType = "XX".parse().unwrap();
646 assert!(matches!(custom, MsgType::Custom(_)));
647 assert_eq!(custom.as_str(), "XX");
648 }
649
650 #[test]
651 fn test_owned_message_field_access() {
652 let buffer = Bytes::from_static(b"8=FIX.4.4\x0135=D\x0149=SENDER\x01");
656 let field_offsets = vec![(8, 2..9), (35, 13..14), (49, 18..24)];
657 let msg = OwnedMessage::new(buffer, MsgType::NewOrderSingle, field_offsets);
658
659 assert_eq!(msg.get_field_str(8), Some("FIX.4.4"));
660 assert_eq!(msg.get_field_str(35), Some("D"));
661 assert_eq!(msg.get_field_str(49), Some("SENDER"));
662 assert_eq!(msg.get_field_str(999), None);
663 }
664}