Skip to main content

fasters/app/
slr.rs

1//! A schema-less, [`HashMap`]-backed internal representation for FIX messages.
2
3use crate::app::slr;
4use crate::app::TsrMessageRef;
5use std::collections::BTreeMap;
6use std::time::SystemTime;
7
8/// An owned value of a FIX field.
9#[derive(Clone, Debug, PartialEq)]
10pub enum FixFieldValue {
11    Int(i64),
12    Float(f64),
13    Char(char),
14    String(String),
15    Data(Vec<u8>),
16    Group(Vec<BTreeMap<i64, FixFieldValue>>),
17}
18
19impl From<i64> for FixFieldValue {
20    fn from(v: i64) -> Self {
21        FixFieldValue::Int(v)
22    }
23}
24
25impl From<String> for FixFieldValue {
26    fn from(v: String) -> Self {
27        FixFieldValue::String(v)
28    }
29}
30
31impl From<f64> for FixFieldValue {
32    fn from(v: f64) -> Self {
33        FixFieldValue::Float(v)
34    }
35}
36
37impl From<(u8, u16)> for FixFieldValue {
38    fn from(v: (u8, u16)) -> Self {
39        FixFieldValue::Int(((v.0 as i64) << 16) + (v.1 as i64))
40    }
41}
42
43impl From<char> for FixFieldValue {
44    fn from(v: char) -> Self {
45        FixFieldValue::Char(v)
46    }
47}
48
49impl From<usize> for FixFieldValue {
50    fn from(v: usize) -> Self {
51        FixFieldValue::Int(v as i64)
52    }
53}
54
55impl From<Vec<u8>> for FixFieldValue {
56    fn from(v: Vec<u8>) -> Self {
57        FixFieldValue::Data(v)
58    }
59}
60
61impl From<bool> for FixFieldValue {
62    fn from(v: bool) -> Self {
63        FixFieldValue::Char(if v { 't' } else { 'f' })
64    }
65}
66
67impl From<u8> for FixFieldValue {
68    fn from(v: u8) -> Self {
69        FixFieldValue::Int(v.into())
70    }
71}
72
73impl From<SystemTime> for FixFieldValue {
74    fn from(v: SystemTime) -> Self {
75        FixFieldValue::Int(v.duration_since(std::time::UNIX_EPOCH).unwrap().as_secs() as i64)
76    }
77}
78
79#[derive(Debug, Clone, PartialEq)]
80pub struct Field {
81    tag: i64,
82    value: FixFieldValue,
83}
84
85impl Field {
86    /// Creates a new [`Field`] value with `tag` and `value`.
87    pub fn new(tag: u32, value: FixFieldValue) -> Self {
88        Self { tag: tag as i64, value }
89    }
90
91    /// Returns the field tag of `self`.
92    pub fn tag(&self) -> i64 {
93        self.tag
94    }
95
96    /// Returns an immutable reference to the value of `self`.
97    pub fn value(&self) -> &FixFieldValue {
98        &self.value
99    }
100}
101
102/// FIX message, backed by an associative array.
103#[derive(Debug, Clone, Default, PartialEq)]
104pub struct Message {
105    pub fields: BTreeMap<i64, FixFieldValue>,
106}
107
108#[derive(Debug, Clone, Default, PartialEq)]
109pub struct PushyMessage {
110    fields: Vec<(u32, FixFieldValue)>,
111}
112
113impl TsrMessageRef for PushyMessage {
114    fn set_field(&mut self, msg_type: u32, val: slr::FixFieldValue) {
115        PushyMessage::add_field(self, msg_type, val)
116    }
117
118    fn get_field(&self, msg_type: u32) -> Option<&slr::FixFieldValue> {
119        PushyMessage::get_field(self, msg_type)
120    }
121}
122
123impl PushyMessage {
124    /// Creates a new [`Message`] without any fields.
125    pub fn new() -> Self {
126        Self {
127            fields: Vec::new(),
128        }
129    }
130
131    /// Adds a field to `self`.
132    pub fn add_field<K: Into<u32>>(&mut self, tag: K, value: slr::FixFieldValue) {
133        self.fields.push((tag.into(), value));
134    }
135
136    /// Adds a string field to `self`.
137    pub fn add_str<K: Into<u32>, S: Into<String>>(&mut self, tag: K, value: S) {
138        self.add_field(tag, slr::FixFieldValue::String(value.into()))
139    }
140
141    /// Adds an integer field to `self`.
142    pub fn add_int<K: Into<u32>>(&mut self, tag: K, value: i64) {
143        self.add_field(tag, slr::FixFieldValue::Int(value))
144    }
145
146    pub fn get_field<K: Into<u32>>(&self, tag: K) -> Option<&slr::FixFieldValue> {
147        let tag = tag.into();
148        let index = self.fields.iter().position(|(t, _)| *t == tag);
149        index.map(|i| &self.fields[i].1)
150    }
151
152    pub fn msg_type(&self) -> Option<&str> {
153        match self.get_field(35u32) {
154            Some(FixFieldValue::String(s)) => Some(s.as_str()),
155            _ => None,
156        }
157    }
158
159    pub fn seq_num(&self) -> Option<u64> {
160        match self.get_field(34u32) {
161            Some(FixFieldValue::Int(n)) => Some(*n as u64),
162            _ => None,
163        }
164    }
165
166    pub fn test_indicator(&self) -> Option<bool> {
167        match self.get_field(464u32) {
168            Some(FixFieldValue::Char('Y')) => Some(true),
169            Some(FixFieldValue::Char('N')) => Some(false),
170            _ => Some(false),
171        }
172    }
173}
174
175impl TsrMessageRef for Message {
176    fn get_field(&self, msg_type: u32) -> Option<&slr::FixFieldValue> {
177        self.fields.get(&(msg_type as i64))
178    }
179
180    fn set_field(&mut self, msg_type: u32, val: slr::FixFieldValue) {
181        self.fields.insert(msg_type as i64, val);
182    }
183}
184
185impl<'a> Iterator for &'a Message {
186    type Item = slr::FixFieldValue;
187
188    fn next(&mut self) -> Option<Self::Item> {
189        None
190    }
191}
192
193impl Message {
194    /// Creates a new [`Message`] without any fields.
195    pub fn new() -> Self {
196        Message {
197            fields: BTreeMap::new(),
198        }
199    }
200
201    /// Adds a field to `self`.
202    pub fn add_field<K: Into<i64>>(&mut self, tag: K, value: slr::FixFieldValue) {
203        self.fields.insert(tag.into(), value);
204    }
205
206    /// Adds a string field to `self`.
207    pub fn add_str<K: Into<i64>, S: Into<String>>(&mut self, tag: K, value: S) {
208        self.add_field(tag, slr::FixFieldValue::String(value.into()))
209    }
210
211    /// Adds an integer field to `self`.
212    pub fn add_int<K: Into<i64>>(&mut self, tag: K, value: i64) {
213        self.add_field(tag, slr::FixFieldValue::Int(value))
214    }
215
216    pub fn get_field<K: Into<i64>>(&self, tag: K) -> Option<&slr::FixFieldValue> {
217        self.fields.get(&tag.into())
218    }
219
220    pub fn msg_type(&self) -> Option<&str> {
221        match self.fields.get(&35) {
222            Some(FixFieldValue::String(s)) => Some(s.as_str()),
223            _ => None,
224        }
225    }
226
227    pub fn seq_num(&self) -> Option<u64> {
228        match self.fields.get(&34) {
229            Some(FixFieldValue::Int(n)) => Some(*n as u64),
230            _ => None,
231        }
232    }
233
234    pub fn test_indicator(&self) -> Option<bool> {
235        match self.fields.get(&464) {
236            Some(FixFieldValue::Char('Y')) => Some(true),
237            Some(FixFieldValue::Char('N')) => Some(false),
238            _ => Some(false),
239        }
240    }
241}