Skip to main content

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}