fixlite/tag/mod.rs
1use crate::{enums, fix};
2use chrono::{DateTime, Utc};
3
4/// tag::Registry is used to define mapping between FIX tags and their allowed Rust types.
5/// DefaultRegistry is provided and users can also override it with their own definitions.
6/// Trait that describes which Rust types are allowed for a given FIX tag.
7///
8/// Most users should rely on `fix_tag_registry!` instead of implementing this manually.
9pub trait Registry {
10 fn get_allowed_types_for_tag(&self, tag: &str) -> Vec<String>;
11 fn contains(&self, tag: &str) -> bool;
12}
13
14/// Marker trait implemented by registries to allow specific tag/type pairs.
15///
16/// This is used for compile-time validation; users generally rely on `fix_tag_registry!`.
17pub trait AllowedType<const TAG: u32, T> {}
18
19#[macro_export]
20macro_rules! fix_tag_registry {
21 // Case 1: Normal case
22 ($registry_name:ident { $( $tag:literal => [$($type:ty),+ $(,)?] ),* $(,)? } ) => {
23 pub struct $registry_name;
24
25 impl $crate::tag::Registry for $registry_name {
26 fn get_allowed_types_for_tag(&self, tag: &str) -> Vec<String> {
27 let parsed = tag.parse::<u32>();
28 match parsed.unwrap_or(0) {
29 $( $tag => vec![$(stringify!($type).to_string()),+], )*
30 _ => vec![]
31 }
32 }
33
34 fn contains(&self, tag: &str) -> bool {
35 let tag_val = tag.parse::<u32>().unwrap_or(0);
36 #[allow(unreachable_code)]
37 {
38 // Emit match expression only if tags are provided
39 false $(|| tag_val == $tag)*
40 }
41 }
42 }
43
44 // Explicit AllowedType impls
45 $( $(
46 impl $crate::tag::AllowedType<$tag, $type> for $registry_name {}
47 impl $crate::tag::AllowedType<$tag, Option<$type>> for $registry_name {}
48 )+ )*
49
50 // Blanket impls (only for undeclared tags)
51 impl<const TAG: u32> $crate::tag::AllowedType<TAG, String> for $registry_name {}
52 impl<const TAG: u32> $crate::tag::AllowedType<TAG, &str> for $registry_name {}
53 impl<const TAG: u32> $crate::tag::AllowedType<TAG, Option<String>> for $registry_name {}
54 impl<const TAG: u32> $crate::tag::AllowedType<TAG, Option<&str>> for $registry_name {}
55 };
56 // Case 2: Registry without braces
57 ($registry_name:ident) => {
58 $crate::fix_tag_registry!($registry_name {});
59 };
60}
61
62pub use crate::fix_tag_registry;
63
64// Default FIX tag registry defining mapping between fix tags and
65// corresponding allowed Rust types.
66fix_tag_registry! {
67 DefaultRegistry {
68 9 => [u32], // BodyLength
69 6 => [f64, fix::Price], // AvgPx
70 14 => [f64], // CumQty
71 31 => [f64, fix::Price], // LastPx
72 32 => [f64], // LastQty
73 34 => [u64, i64], // MsgSeqNum
74 38 => [f64], // OrderQty
75 44 => [f64, fix::Price], // Price
76 52 => [DateTime<Utc>], // SendingTime
77 99 => [f64, fix::Price], // StopPx
78 132 => [f64, fix::Price], // CashOrderQty
79 133 => [f64, fix::Price], // OrderQty2
80 140 => [f64, fix::Price], // PrevClosePx
81 141 => [u8, enums::ResetSeqNumFlag], // ResetSeqNumFlag
82 151 => [f64], // LeavesQty
83 202 => [f64, fix::Price], // StrikePrice
84 231 => [f64], // ContractMultiplier
85 260 => [f64, fix::Price], // MDEntryPx
86 270 => [f64, fix::Price], // MDEntryPx (again – used in market data)
87 271 => [f64], // MDEntrySize
88 272 => [DateTime<Utc>], // MDEntryDate
89 393 => [u32], // TotNoRelatedSym
90 810 => [f64, fix::Price], // PriceDelta
91 1208 => [f64], // TargetStrategyParameters
92
93 // Enums
94 35 => [enums::MsgType], // MsgType
95 20 => [enums::ExecTransType], // ExecTransType
96 21 => [enums::HandlInst], // HandlInst
97 22 => [enums::SecurityIDSource], // SecurityIDSource
98 39 => [enums::OrdStatus], // OrdStatus
99 40 => [enums::OrdType], // OrdType
100 54 => [enums::Side], // Side
101 59 => [enums::TimeInForce], // TimeInForce
102 150 => [enums::ExecType], // ExecType
103 167 => [enums::SecurityType], // SecurityType
104 263 => [enums::SubscriptionRequestType], // SubscriptionRequestType
105 205 => [u8, fix::DayOfMonth], // MaturityDay
106 265 => [enums::MDUpdateType], // MDUpdateType
107 269 => [enums::MDEntryType], // MDEntryType
108 279 => [enums::MDUpdateAction], // MDUpdateAction
109 281 => [enums::MDReqRejReason], // MDReqRejReason
110 314 => [u8, fix::DayOfMonth], // UnderlyingMaturityDay
111 321 => [enums::SecurityRequestType], // SecurityRequestType
112 323 => [enums::SecurityResponseType], // SecurityResponseType
113 373 => [enums::SessionRejectReason], // SessionRejectReason
114
115 // Checksum
116 10 => [u8], // CheckSum
117 }
118}