fastlib/
text.rs

1use hashbrown::HashMap;
2
3use crate::{Error, MessageFactory, MessageVisitor, Value, ValueType};
4use crate::Result;
5use crate::utils::bytes::bytes_to_string;
6use crate::utils::stacked::Stacked;
7
8/// Message factory implementation that formats decoded messages as a human-readable text.
9pub struct TextMessageFactory {
10    pub text: String,
11    block_start: bool,
12    dynamic: Vec<bool>,
13}
14
15impl TextMessageFactory {
16    /// Creates a new message factory.
17    pub fn new() -> Self {
18        Self {
19            text: String::with_capacity(4096),
20            block_start: false,
21            dynamic: Vec::new(),
22        }
23    }
24
25    /// Resets the state of the message factory.
26    /// Called everytime a new message decoding started.
27    pub fn reset(&mut self) {
28        self.text.clear();
29        self.block_start = false;
30        self.dynamic.clear();
31    }
32
33    fn delimiter(&mut self) {
34        if !self.block_start {
35            self.text += "|";
36        } else {
37            self.block_start = false;
38        }
39    }
40}
41
42impl MessageFactory for TextMessageFactory {
43    fn start_template(&mut self, _id: u32, name: &str) {
44        self.reset();
45        self.text = format!("{name}=<");
46        self.block_start = true;
47    }
48
49    fn stop_template(&mut self) {
50        self.text += ">";
51    }
52
53    fn set_value(&mut self, _id: u32, name: &str, value: Option<Value>) {
54        if let Some(value) = value {
55            self.delimiter();
56            let value = match value {
57                Value::UInt32(v) => format!("{v}"),
58                Value::Int32(v) => format!("{v}"),
59                Value::UInt64(v) => format!("{v}"),
60                Value::Int64(v) => format!("{v}"),
61                Value::Decimal(v) => v.to_string(),
62                Value::ASCIIString(v) => v.clone(),
63                Value::UnicodeString(v) => v.clone(),
64                Value::Bytes(b) => bytes_to_string(&b),
65            };
66            self.text += &format!("{name}={value}");
67        }
68    }
69
70    fn start_sequence(&mut self, _id: u32, name: &str, _length: u32) {
71        self.delimiter();
72        self.text += &format!("{name}=");
73    }
74
75    fn start_sequence_item(&mut self, _index: u32) {
76        self.text += "<";
77        self.block_start = true;
78    }
79
80    fn stop_sequence_item(&mut self) {
81        self.text += ">";
82    }
83
84    fn stop_sequence(&mut self) {
85        self.block_start = false;
86    }
87
88    fn start_group(&mut self, name: &str) {
89        self.delimiter();
90        self.text += &format!("{name}=<");
91        self.block_start = true;
92    }
93
94    fn stop_group(&mut self) {
95        self.text += ">";
96        self.block_start = false
97    }
98
99    fn start_template_ref(&mut self, name: &str, dynamic: bool) {
100        self.dynamic.push(dynamic);
101        if dynamic {
102            self.delimiter();
103            self.text += &format!("TemplateReference=<{name}=<");
104            self.block_start = true;
105        }
106    }
107
108    fn stop_template_ref(&mut self) {
109        let dynamic = self.dynamic.pop().unwrap();
110        if dynamic {
111            self.text += ">>";
112        }
113    }
114}
115
116
117/// Message factory implementation that formats decoded messages as JSON encoded `String`.
118pub struct JsonMessageFactory {
119    pub json: String,
120    block_start: bool,
121    dynamic: Vec<bool>,
122}
123
124impl JsonMessageFactory {
125    /// Creates a new message factory.
126    pub fn new() -> Self {
127        Self {
128            json: String::with_capacity(4096),
129            block_start: false,
130            dynamic: Vec::new(),
131        }
132    }
133
134    /// Resets the state of the message factory.
135    /// Called every time a new message decoding started.
136    pub fn reset(&mut self) {
137        self.json.clear();
138        self.block_start = false;
139        self.dynamic.clear();
140    }
141
142    fn delimiter(&mut self) {
143        if !self.block_start {
144            self.json += ",";
145        } else {
146            self.block_start = false;
147        }
148    }
149}
150
151impl MessageFactory for JsonMessageFactory {
152    fn start_template(&mut self, _id: u32, name: &str) {
153        self.reset();
154        self.json = format!("{{\"{name}\":{{");
155        self.block_start = true;
156    }
157
158    fn stop_template(&mut self) {
159        self.json += "}}";
160    }
161
162    fn set_value(&mut self, _id: u32, name: &str, value: Option<Value>) {
163        if let Some(value) = value {
164            self.delimiter();
165            let value = match value {
166                Value::UInt32(v) => format!("{v}"),
167                Value::Int32(v) => format!("{v}"),
168                Value::UInt64(v) => format!("{v}"),
169                Value::Int64(v) => format!("{v}"),
170                Value::Decimal(v) => format!("{v}"),
171                Value::ASCIIString(v) => format!("\"{v}\""),
172                Value::UnicodeString(v) => format!("\"{v}\""),
173                Value::Bytes(b) => bytes_to_string(&b),
174            };
175            self.json += &format!("\"{name}\":{value}");
176        }
177    }
178
179    fn start_sequence(&mut self, _id: u32, name: &str, _length: u32) {
180        self.delimiter();
181        self.json += &format!("\"{name}\":[");
182        self.block_start = true;
183    }
184
185    fn start_sequence_item(&mut self, _index: u32) {
186        self.delimiter();
187        self.json += "{";
188        self.block_start = true;
189    }
190
191    fn stop_sequence_item(&mut self) {
192        self.json += "}";
193    }
194
195    fn stop_sequence(&mut self) {
196        self.json += "]";
197        self.block_start = false;
198    }
199
200    fn start_group(&mut self, name: &str) {
201        self.delimiter();
202        self.json += &format!("\"{name}\":{{");
203        self.block_start = true;
204    }
205
206    fn stop_group(&mut self) {
207        self.json += "}";
208        self.block_start = false
209    }
210
211    fn start_template_ref(&mut self, name: &str, dynamic: bool) {
212        self.dynamic.push(dynamic);
213        if dynamic {
214            self.delimiter();
215            self.json += &format!("\"TemplateReference\":{{\"{name}\":{{");
216            self.block_start = true;
217        }
218    }
219
220    fn stop_template_ref(&mut self) {
221        let dynamic = self.dynamic.pop().unwrap();
222        if dynamic {
223            self.json += "}}";
224        }
225    }
226}
227
228
229pub struct TextMessageVisitor {
230    pub data: TextMessageValue,
231    context: Stacked<*const TextMessageValue>,
232    group_as_seq: Stacked<bool>,
233}
234
235impl TextMessageVisitor {
236    pub fn from_text(text: &str) -> Result<Self> {
237        Ok(Self {
238            data: TextMessageValue::from_text(text)?,
239            context: Stacked::new_empty(),
240            group_as_seq: Stacked::new_empty(),
241        })
242    }
243}
244
245impl MessageVisitor for TextMessageVisitor {
246    fn get_template_name(&mut self) -> Result<String> {
247        match &self.data {
248            TextMessageValue::Group(h) => {
249                match h.iter().next() {
250                    None => Err(Error::Runtime("Template name not fount".to_string())),
251                    Some((name, value)) => {
252                        self.context.push(value);
253                        Ok(name.clone())
254                    }
255                }
256            }
257            _ => {
258                Err(Error::Runtime(format!("Template value expected to be TextMessageValue::Group, got {:?}", self.data)))
259            }
260        }
261    }
262
263    fn get_value(&mut self, name: &str, type_: &ValueType) -> Result<Option<Value>> {
264        // SAFETY: the reference to context is always valid because we never modify `self.data`
265        let ctx = unsafe { self.context.must_peek().as_ref().unwrap() };
266        match ctx {
267            TextMessageValue::Group(context) => {
268                if let Some(v) = context.get(name) {
269                    match v {
270                        TextMessageValue::Value(s) => {
271                            let mut value = type_.to_default_value()?;
272                            value.set_from_string(s)?;
273                            Ok(Some(value))
274                        }
275                        _ => {
276                            Err(Error::Runtime(format!("Field {name} expected to be TextMessageValue::Value, got {:?}", v)))
277                        }
278                    }
279                } else {
280                    Ok(None)
281                }
282            }
283            _ => unreachable!()
284        }
285    }
286
287    fn select_group(&mut self, name: &str) -> Result<bool> {
288        // SAFETY: the reference to context is always valid because we never modify `self.data`
289        let ctx = unsafe { self.context.must_peek().as_ref().unwrap() };
290        match ctx {
291            TextMessageValue::Group(context) => {
292                if let Some(v) = context.get(name) {
293                    match v {
294                        TextMessageValue::Group(_) => {
295                            self.context.push(v);
296                            Ok(true)
297                        }
298                        _ => {
299                            Err(Error::Runtime(format!("Field {name} expected to be TextMessageValue::Group, got {:?}", v)))
300                        }
301                    }
302                } else {
303                    Ok(false)
304                }
305            }
306            _ => unreachable!()
307        }
308    }
309
310    fn release_group(&mut self) -> Result<()> {
311        self.context.pop();
312        Ok(())
313    }
314
315    fn select_sequence(&mut self, name: &str) -> Result<Option<usize>> {
316        // SAFETY: the reference to context is always valid because we never modify `self.data`
317        let ctx = unsafe { self.context.must_peek().as_ref().unwrap() };
318        match ctx {
319            TextMessageValue::Group(context) => {
320                if let Some(v) = context.get(name) {
321                    match v {
322                        TextMessageValue::Group(_) => {
323                            self.group_as_seq.push(true);
324                            self.context.push(v);
325                            Ok(Some(1))
326                        }
327                        TextMessageValue::Sequence(s) => {
328                            let len = s.len();
329                            self.group_as_seq.push(false);
330                            self.context.push(v);
331                            Ok(Some(len))
332                        }
333                        _ => {
334                            Err(Error::Runtime(format!("Field {name} expected to be TextMessageValue::Sequence, got {:?}", v)))
335                        }
336                    }
337                } else {
338                    Ok(None)
339                }
340            }
341            _ => unreachable!()
342        }
343    }
344
345    fn select_sequence_item(&mut self, index: usize) -> Result<()> {
346        if *self.group_as_seq.must_peek() {
347            // context already set to proper group element
348            return if index == 0 {
349                Ok(())
350            } else {
351                Err(Error::Runtime("Index is out of range".to_string()))
352            }
353        }
354        // SAFETY: the reference to context is always valid because we never modify `self.data`
355        let ctx = unsafe { self.context.must_peek().as_ref().unwrap() };
356        match ctx {
357            TextMessageValue::Sequence(sequence) => {
358                if let Some(v) = sequence.get(index) {
359                    match v {
360                        TextMessageValue::Group(_) => {
361                            self.context.push(v);
362                            Ok(())
363                        }
364                        _ => {
365                            Err(Error::Runtime(format!("Sequence item #{index} expected to be TextMessageValue::Group, got {:?}", v)))
366                        }
367                    }
368
369                } else {
370                    return Err(Error::Runtime(format!("Index {} is out of range", index)));
371                }
372            }
373            _ => unreachable!()
374        }
375    }
376
377    fn release_sequence_item(&mut self) -> Result<()> {
378        self.context.pop();
379        Ok(())
380    }
381
382    fn release_sequence(&mut self) -> Result<()> {
383        if !self.group_as_seq.pop().unwrap() {
384            self.context.pop();
385        }
386        Ok(())
387    }
388
389    fn select_template_ref(&mut self, _name: &str, dynamic: bool) -> Result<Option<String>> {
390        if dynamic {
391            todo!()
392        } else {
393            // do nothing because static template ref is embedded into current context
394            Ok(None)
395        }
396    }
397
398    fn release_template_ref(&mut self) -> Result<()> {
399        Ok(())
400    }
401}
402
403#[derive(Debug, PartialEq)]
404pub enum TextMessageValue {
405    Value(String),
406    Group(HashMap<String, TextMessageValue>),
407    Sequence(Vec<TextMessageValue>),
408}
409
410impl TextMessageValue {
411    fn from_text(text: &str) -> Result<Self> {
412        return match TextMessageValue::parse_next(text)? {
413            (name, TextMessageValue::Group(value), size) => {
414                if size != text.len() {
415                    Err(Error::Dynamic("Symbols left in buffer after parsing text message".to_string()))
416                } else {
417                    Ok(TextMessageValue::Group(
418                        HashMap::from([
419                            (name, TextMessageValue::Group(value))
420                        ])
421                    ))
422                }
423            }
424            _ => Err(Error::Dynamic("Failed to parse message body".to_string())),
425        };
426    }
427
428    fn parse_next(text: &str) -> Result<(String, Self, usize)> {
429        let (name, rest) = text.split_once('=')
430            .ok_or_else(|| Error::Dynamic("Failed to parse next field".to_string()))?;
431        let (value, sz) = TextMessageValue::parse_value(rest)?;
432        let size = name.len() + sz + 1;
433        Ok((name.to_string(), value, size))
434    }
435
436    fn parse_value(mut text: &str) -> Result<(Self, usize)> {
437        if text.starts_with('<') {
438            // value is Group or Sequence
439            let mut size = 0;
440            let mut value: Option<TextMessageValue> = None;
441            loop {
442                let (v, s) = TextMessageValue::parse_group(&text[1..])?;
443                size += s + 1;
444                text = &text[s + 1..];
445                match &mut value {
446                    None => {
447                        value = Some(v);
448                    }
449                    Some(TextMessageValue::Group(_)) => {
450                        let mut seq = Vec::with_capacity(2);
451                        seq.push(value.unwrap());
452                        seq.push(v);
453                        value = Some(TextMessageValue::Sequence(seq));
454                    }
455                    Some(TextMessageValue::Sequence(s)) => {
456                        s.push(v);
457                    }
458                    _ => unreachable!(),
459                }
460                if text.starts_with('<') {
461                    continue
462                }
463                break
464            }
465            Ok((value.unwrap(), size))
466        } else {
467            let i = text.find(|c: char| c == '|' || c == '>')
468                .ok_or_else(|| Error::Dynamic("Failed to parse next value (no delimiter)".to_string()))?;
469            Ok((TextMessageValue::Value(text[..i].to_string()), i))
470        }
471    }
472
473    fn parse_group(mut text: &str) -> Result<(Self, usize)> {
474        let mut size = 0;
475        let mut value: HashMap<String, TextMessageValue> = HashMap::new();
476        loop {
477            let (name, v, sz) = TextMessageValue::parse_next(text)?;
478            size += sz;
479            text = &text[sz..];
480            value.insert(name, v);
481
482            if text.starts_with('|') {
483                size += 1;
484                text = &text[1..];
485                continue
486            }
487            if text.starts_with('>') {
488                size += 1;
489                break
490            }
491            return Err(Error::Dynamic("Failed to parse group".to_string()));
492        }
493        Ok((TextMessageValue::Group(value), size))
494    }
495}
496
497#[cfg(test)]
498mod tests {
499    use super::*;
500
501    #[test]
502    fn test_parse_text_group() {
503        let (value, size) = TextMessageValue::parse_group("MessageType=0|ApplVerID=8>|").unwrap();
504        assert_eq!(value, TextMessageValue::Group(HashMap::from([
505            ("MessageType".to_string(), TextMessageValue::Value("0".to_string())),
506            ("ApplVerID".to_string(), TextMessageValue::Value("8".to_string())),
507        ])));
508        assert_eq!(size, 26);
509    }
510
511    #[test]
512    fn test_parse_text_value() {
513        let (value, size) = TextMessageValue::parse_value("CQG|").unwrap();
514        assert_eq!(value, TextMessageValue::Value("CQG".to_string()));
515        assert_eq!(size, 3);
516
517        let (value, size) = TextMessageValue::parse_value("<MessageType=0>|").unwrap();
518        assert_eq!(value, TextMessageValue::Group(HashMap::from([
519            ("MessageType".to_string(), TextMessageValue::Value("0".to_string()))
520        ])));
521        assert_eq!(size, 15);
522
523        let (value, size) = TextMessageValue::parse_value("<MessageType=0><MessageType=1>|").unwrap();
524        assert_eq!(value, TextMessageValue::Sequence(vec![
525            TextMessageValue::Group(HashMap::from([
526                ("MessageType".to_string(), TextMessageValue::Value("0".to_string()))
527            ])),
528            TextMessageValue::Group(HashMap::from([
529                ("MessageType".to_string(), TextMessageValue::Value("1".to_string()))
530            ])),
531        ]));
532        assert_eq!(size, 30);
533    }
534
535    #[test]
536    fn test_parse_test_message() {
537        let m = TextMessageValue::from_text(
538            "MDHeartbeat=<MessageType=0|ApplVerID=8|SenderCompID=CQG|MsgSeqNum=2286|SendingTime=20240712171046052>"
539        ).unwrap();
540        let r = TextMessageValue::Group(HashMap::from([
541            (
542                "MDHeartbeat".to_string(),
543                TextMessageValue::Group(HashMap::from([
544                    (
545                        "MessageType".to_string(),
546                        TextMessageValue::Value("0".to_string())
547                    ), (
548                        "ApplVerID".to_string(),
549                        TextMessageValue::Value("8".to_string())
550                    ), (
551                        "SenderCompID".to_string(),
552                        TextMessageValue::Value("CQG".to_string())
553                    ), (
554                        "MsgSeqNum".to_string(),
555                        TextMessageValue::Value("2286".to_string())
556                    ), (
557                        "SendingTime".to_string(),
558                        TextMessageValue::Value("20240712171046052".to_string())
559                    ),
560                ]))
561            )
562        ]));
563        assert_eq!(m, r);
564    }
565}