Skip to main content

ironfix_fast/
encoder.rs

1/******************************************************************************
2   Author: Joaquín Béjar García
3   Email: jb@taunais.com
4   Date: 27/1/26
5******************************************************************************/
6
7//! FAST protocol encoder.
8//!
9//! This module provides encoding of values using FAST stop-bit encoding.
10
11use crate::operators::DictionaryValue;
12use std::collections::HashMap;
13
14/// FAST protocol encoder.
15#[derive(Debug)]
16pub struct FastEncoder {
17    /// Output buffer.
18    buffer: Vec<u8>,
19    /// Global dictionary for operator state.
20    global_dict: HashMap<String, DictionaryValue>,
21    /// Template-specific dictionaries.
22    template_dicts: HashMap<u32, HashMap<String, DictionaryValue>>,
23}
24
25impl FastEncoder {
26    /// Creates a new FAST encoder.
27    #[must_use]
28    pub fn new() -> Self {
29        Self {
30            buffer: Vec::new(),
31            global_dict: HashMap::new(),
32            template_dicts: HashMap::new(),
33        }
34    }
35
36    /// Creates a new encoder with pre-allocated capacity.
37    #[must_use]
38    pub fn with_capacity(capacity: usize) -> Self {
39        Self {
40            buffer: Vec::with_capacity(capacity),
41            global_dict: HashMap::new(),
42            template_dicts: HashMap::new(),
43        }
44    }
45
46    /// Encodes an unsigned integer using stop-bit encoding.
47    ///
48    /// # Arguments
49    /// * `value` - The value to encode
50    pub fn encode_uint(&mut self, value: u64) {
51        if value == 0 {
52            self.buffer.push(0x80);
53            return;
54        }
55
56        let mut bytes = Vec::new();
57        let mut v = value;
58
59        while v > 0 {
60            bytes.push((v & 0x7F) as u8);
61            v >>= 7;
62        }
63
64        bytes.reverse();
65
66        // Set stop bit on last byte
67        if let Some(last) = bytes.last_mut() {
68            *last |= 0x80;
69        }
70
71        self.buffer.extend(bytes);
72    }
73
74    /// Encodes a signed integer using stop-bit encoding.
75    ///
76    /// # Arguments
77    /// * `value` - The value to encode
78    pub fn encode_int(&mut self, value: i64) {
79        if (0..64).contains(&value) {
80            self.buffer.push((value as u8) | 0x80);
81            return;
82        }
83
84        if (-64..0).contains(&value) {
85            self.buffer.push((value as u8) | 0x80);
86            return;
87        }
88
89        let mut bytes = Vec::new();
90        let mut v = value;
91        let negative = value < 0;
92
93        loop {
94            bytes.push((v & 0x7F) as u8);
95            v >>= 7;
96
97            if (negative && v == -1 && (bytes.last().unwrap() & 0x40) != 0)
98                || (!negative && v == 0 && (bytes.last().unwrap() & 0x40) == 0)
99            {
100                break;
101            }
102
103            if v == 0 && !negative {
104                break;
105            }
106            if v == -1 && negative {
107                break;
108            }
109        }
110
111        bytes.reverse();
112
113        if let Some(last) = bytes.last_mut() {
114            *last |= 0x80;
115        }
116
117        self.buffer.extend(bytes);
118    }
119
120    /// Encodes an ASCII string using stop-bit encoding.
121    ///
122    /// # Arguments
123    /// * `value` - The string to encode
124    pub fn encode_ascii(&mut self, value: &str) {
125        let bytes = value.as_bytes();
126
127        if bytes.is_empty() {
128            self.buffer.push(0x80);
129            return;
130        }
131
132        for (i, &b) in bytes.iter().enumerate() {
133            if i == bytes.len() - 1 {
134                self.buffer.push(b | 0x80);
135            } else {
136                self.buffer.push(b & 0x7F);
137            }
138        }
139    }
140
141    /// Encodes a byte vector with length prefix.
142    ///
143    /// # Arguments
144    /// * `value` - The bytes to encode
145    pub fn encode_bytes(&mut self, value: &[u8]) {
146        self.encode_uint(value.len() as u64);
147        self.buffer.extend_from_slice(value);
148    }
149
150    /// Encodes a nullable unsigned integer.
151    ///
152    /// # Arguments
153    /// * `value` - The optional value to encode
154    pub fn encode_nullable_uint(&mut self, value: Option<u64>) {
155        match value {
156            Some(v) => self.encode_uint(v + 1),
157            None => self.buffer.push(0x80),
158        }
159    }
160
161    /// Returns the encoded bytes.
162    #[must_use]
163    pub fn finish(self) -> Vec<u8> {
164        self.buffer
165    }
166
167    /// Returns a reference to the current buffer.
168    #[must_use]
169    pub fn as_bytes(&self) -> &[u8] {
170        &self.buffer
171    }
172
173    /// Returns the current buffer length.
174    #[must_use]
175    pub fn len(&self) -> usize {
176        self.buffer.len()
177    }
178
179    /// Returns true if the buffer is empty.
180    #[must_use]
181    pub fn is_empty(&self) -> bool {
182        self.buffer.is_empty()
183    }
184
185    /// Clears the buffer for reuse.
186    pub fn clear(&mut self) {
187        self.buffer.clear();
188    }
189
190    /// Resets the encoder including dictionaries.
191    pub fn reset(&mut self) {
192        self.buffer.clear();
193        self.global_dict.clear();
194        self.template_dicts.clear();
195    }
196
197    /// Gets a value from the global dictionary.
198    #[must_use]
199    pub fn get_global(&self, key: &str) -> Option<&DictionaryValue> {
200        self.global_dict.get(key)
201    }
202
203    /// Sets a value in the global dictionary.
204    pub fn set_global(&mut self, key: impl Into<String>, value: DictionaryValue) {
205        self.global_dict.insert(key.into(), value);
206    }
207}
208
209impl Default for FastEncoder {
210    fn default() -> Self {
211        Self::new()
212    }
213}
214
215#[cfg(test)]
216mod tests {
217    use super::*;
218
219    #[test]
220    fn test_encode_uint_zero() {
221        let mut encoder = FastEncoder::new();
222        encoder.encode_uint(0);
223        assert_eq!(encoder.finish(), vec![0x80]);
224    }
225
226    #[test]
227    fn test_encode_uint_one() {
228        let mut encoder = FastEncoder::new();
229        encoder.encode_uint(1);
230        assert_eq!(encoder.finish(), vec![0x81]);
231    }
232
233    #[test]
234    fn test_encode_uint_larger() {
235        let mut encoder = FastEncoder::new();
236        encoder.encode_uint(942);
237        let bytes = encoder.finish();
238        // 942 = 7 * 128 + 46, so first byte is 7, second is 46 | 0x80 = 0xAE
239        assert_eq!(bytes, vec![0x07, 0xAE]);
240    }
241
242    #[test]
243    fn test_encode_ascii() {
244        let mut encoder = FastEncoder::new();
245        encoder.encode_ascii("Hi!");
246        let bytes = encoder.finish();
247        assert_eq!(bytes, vec![b'H', b'i', b'!' | 0x80]);
248    }
249
250    #[test]
251    fn test_encode_ascii_empty() {
252        let mut encoder = FastEncoder::new();
253        encoder.encode_ascii("");
254        assert_eq!(encoder.finish(), vec![0x80]);
255    }
256
257    #[test]
258    fn test_encode_bytes() {
259        let mut encoder = FastEncoder::new();
260        encoder.encode_bytes(&[1, 2, 3]);
261        let bytes = encoder.finish();
262        assert_eq!(bytes, vec![0x83, 1, 2, 3]);
263    }
264
265    #[test]
266    fn test_encoder_clear() {
267        let mut encoder = FastEncoder::new();
268        encoder.encode_uint(42);
269        assert!(!encoder.is_empty());
270
271        encoder.clear();
272        assert!(encoder.is_empty());
273    }
274}