dfx_base/
parser.rs

1#[derive(Default, Clone, Debug)]
2pub struct Parser {
3    buffer: Vec<u8>,
4}
5
6impl Parser {
7    pub fn read_fix_message(&mut self) -> Result<Option<Vec<u8>>, ParserError> {
8        Ok(read_fix(&mut self.buffer))
9    }
10
11    pub fn add_to_stream(&mut self, read: &[u8]) {
12        self.buffer.extend_from_slice(read)
13    }
14
15    pub fn clear(&mut self) {
16        self.buffer.clear()
17    }
18}
19
20pub(crate) trait Find<T> {
21    fn find(&self, item: T) -> Option<usize>;
22}
23
24impl Find<&[u8]> for Vec<u8> {
25    fn find(&self, item: &[u8]) -> Option<usize> {
26        let mut index = 0;
27        for _c in self {
28            if item.len() >= self.len() - index {
29                return None;
30            }
31            if &self[index..index + item.len()] == item {
32                return Some(index);
33            }
34            index += 1;
35        }
36        None
37    }
38}
39impl Find<char> for Vec<u8> {
40    fn find(&self, item: char) -> Option<usize> {
41        let mut index = 0;
42        for c in self {
43            if c == &(item as u8) {
44                return Some(index);
45            }
46            index += 1;
47        }
48        None
49    }
50}
51impl Find<&[u8]> for [u8] {
52    fn find(&self, item: &[u8]) -> Option<usize> {
53        let mut index = 0;
54        for _c in self {
55            if item.len() >= self.len() - index {
56                return None;
57            }
58            if &self[index..index + item.len()] == item {
59                return Some(index);
60            }
61            index += 1;
62        }
63        None
64    }
65}
66impl Find<char> for [u8] {
67    fn find(&self, item: char) -> Option<usize> {
68        let mut index = 0;
69        for c in self {
70            if c == &(item as u8) {
71                return Some(index);
72            }
73            index += 1;
74        }
75        None
76    }
77}
78
79/// Returns `Some<String>` if it can find a potential fix message otherwise returns `None`
80/// Drains the buffer.
81pub fn read_fix(buffer: &mut Vec<u8>) -> Option<Vec<u8>> {
82    if buffer.len() < 2 {
83        return None;
84    }
85    let pos: Option<usize> = buffer.find("8=".as_bytes());
86    if pos == None || pos == Some(usize::MAX) {
87        return None;
88    }
89    let pos = pos?;
90    buffer.drain(..pos); //drain until 8=
91    if let Some((len, mut pos)) = extract_length(&buffer) {
92        pos += len;
93        if buffer.len() < pos {
94            return None;
95        }
96        let found = buffer[pos - 1..].find("\x0110=".as_bytes());
97        pos = found? + pos - 1;
98        // TODO should we return err if position of found is too large?
99        pos += 4;
100        let found = buffer[pos..].find('\x01');
101        pos += found?;
102        pos += 1;
103        return Some(buffer.drain(..pos).collect());
104    }
105    None
106}
107
108/// Returns `Option<(pos, len)>` if it can find the length in the fix message otherwise returns `None`.
109///
110pub fn extract_length(buffer: &[u8]) -> Option<(usize, usize)> {
111    let start = buffer.find("\x019=".as_bytes())? + 3;
112    let end = buffer[start..].find('\x01')? + start;
113    let str_len = &buffer[start..end];
114    match std::str::from_utf8(str_len) {
115        Ok(s) => {
116            let out_len = s.parse::<usize>().ok()?;
117            Some((end + 1, out_len))
118        }
119        Err(_) => None,
120    }
121}
122
123pub fn read_version(buffer: &[u8]) -> Option<&str> {
124    let pos: Option<usize> = buffer.find("8=".as_bytes());
125    let pos = pos?;
126    let found = buffer[pos..].find('\x01');
127    let end = found?;
128    match std::str::from_utf8(&buffer[pos + 2..end]) {
129        Ok(s) => Some(s),
130        Err(_) => None,
131    }
132}
133
134pub fn read_msg_type(buffer: &[u8]) -> Option<&str> {
135    let pos: Option<usize> = buffer.find("\x0135=".as_bytes());
136    let pos = pos? + 4;
137    let found = buffer[pos..].find('\x01');
138    let end = found? + pos;
139    match std::str::from_utf8(&buffer[pos..end]) {
140        Ok(s) if s.len() > 0 => Some(s),
141        Ok(_) => None,
142        Err(_) => None,
143    }
144}
145
146#[derive(Debug)]
147pub enum ParserError {}
148
149#[cfg(test)]
150mod tests {
151    use crate::parser::Parser;
152
153    use super::read_msg_type;
154
155    #[test]
156    pub fn two_in_one() {
157        let buffer = b"8=FIX.4.4\x019=57\x0135=A\x0134=1\x0149=ISLD\x0152=00000000-00:00:00\x0156=TW\x0198=0\x01108=30\x0110=0\x018=FIX.4.4\x019=45\x0135=5\x0134=2\x0149=ISLD\x0152=00000000-00:00:00\x0156=TW\x0110=0\x01";
158        println!("{}", buffer.iter().map(|b| *b as char).collect::<String>());
159        let mut parser = Parser::default();
160        parser.add_to_stream(buffer);
161        let msg = parser.read_fix_message();
162        assert!(msg.is_ok());
163        if let Ok(msg) = msg {
164            assert!(msg.is_some());
165            assert!(!parser.buffer.is_empty());
166            println!(
167                "{}",
168                parser.buffer.iter().map(|b| *b as char).collect::<String>()
169            );
170        }
171        let msg = parser.read_fix_message();
172        assert!(msg.is_ok());
173        if let Ok(msg) = msg {
174            assert!(msg.is_some());
175        }
176    }
177
178    #[test]
179    pub fn test_read_msg_type() {
180        let buffer = b"8=FIX.4.4\x019=57\x0135=A\x0134=1\x0149=ISLD\x0152=00000000-00:00:00\x0156=TW\x0198=0\x01108=30\x0110=0\x018=FIX.4.4\x019=45\x0135=5\x0134=2\x0149=ISLD\x0152=00000000-00:00:00\x0156=TW\x0110=0\x01";
181        let msg_type = read_msg_type(buffer);
182        assert!(msg_type.is_some());
183        assert_eq!(msg_type.unwrap(), "A");
184    }
185
186    #[test]
187    pub fn test_read_msg_type_longer() {
188        let buffer = b"8=FIX.4.4\x019=57\x0135=AASDFA\x0134=1\x0149=ISLD\x0152=00000000-00:00:00\x0156=TW\x0198=0\x01108=30\x0110=0\x018=FIX.4.4\x019=45\x0135=5\x0134=2\x0149=ISLD\x0152=00000000-00:00:00\x0156=TW\x0110=0\x01";
189        let msg_type = read_msg_type(buffer);
190        assert!(msg_type.is_some());
191        assert_eq!(msg_type.unwrap(), "AASDFA");
192    }
193}