Skip to main content

ironfix_fast/
pmap.rs

1/******************************************************************************
2   Author: Joaquín Béjar García
3   Email: jb@taunais.com
4   Date: 27/1/26
5******************************************************************************/
6
7//! FAST presence map handling.
8//!
9//! The presence map (PMAP) is a bitmap that indicates which optional fields
10//! are present in a FAST message. It uses stop-bit encoding where the high
11//! bit of each byte indicates whether more bytes follow.
12
13use crate::error::FastError;
14
15/// FAST presence map.
16///
17/// The presence map tracks which optional fields are present in a message.
18/// Bits are consumed in order as fields are decoded.
19#[derive(Debug, Clone)]
20pub struct PresenceMap {
21    /// The raw bits of the presence map.
22    bits: Vec<bool>,
23    /// Current bit position.
24    position: usize,
25}
26
27impl PresenceMap {
28    /// Creates an empty presence map.
29    #[must_use]
30    pub fn new() -> Self {
31        Self {
32            bits: Vec::new(),
33            position: 0,
34        }
35    }
36
37    /// Creates a presence map from raw bits.
38    #[must_use]
39    pub fn from_bits(bits: Vec<bool>) -> Self {
40        Self { bits, position: 0 }
41    }
42
43    /// Decodes a presence map from a byte slice.
44    ///
45    /// # Arguments
46    /// * `data` - The input bytes
47    /// * `offset` - Current position in the data (will be updated)
48    ///
49    /// # Returns
50    /// The decoded presence map.
51    ///
52    /// # Errors
53    /// Returns `FastError::UnexpectedEof` if the data is incomplete.
54    pub fn decode(data: &[u8], offset: &mut usize) -> Result<Self, FastError> {
55        let mut bits = Vec::new();
56
57        loop {
58            if *offset >= data.len() {
59                return Err(FastError::UnexpectedEof);
60            }
61
62            let byte = data[*offset];
63            *offset += 1;
64
65            // Extract 7 bits (excluding stop bit)
66            for i in (0..7).rev() {
67                bits.push((byte >> i) & 1 == 1);
68            }
69
70            // Check stop bit (high bit)
71            if byte & 0x80 != 0 {
72                break;
73            }
74        }
75
76        Ok(Self { bits, position: 0 })
77    }
78
79    /// Returns the next bit from the presence map.
80    ///
81    /// # Returns
82    /// `true` if the field is present, `false` otherwise.
83    /// Returns `false` if the map is exhausted.
84    #[inline]
85    pub fn next_bit(&mut self) -> bool {
86        if self.position < self.bits.len() {
87            let bit = self.bits[self.position];
88            self.position += 1;
89            bit
90        } else {
91            false
92        }
93    }
94
95    /// Returns the bit at the specified position without consuming it.
96    ///
97    /// # Arguments
98    /// * `index` - The bit position (0-indexed)
99    #[must_use]
100    pub fn bit(&self, index: usize) -> bool {
101        self.bits.get(index).copied().unwrap_or(false)
102    }
103
104    /// Returns the number of bits in the presence map.
105    #[must_use]
106    pub fn len(&self) -> usize {
107        self.bits.len()
108    }
109
110    /// Returns true if the presence map is empty.
111    #[must_use]
112    pub fn is_empty(&self) -> bool {
113        self.bits.is_empty()
114    }
115
116    /// Returns the current position in the presence map.
117    #[must_use]
118    pub fn position(&self) -> usize {
119        self.position
120    }
121
122    /// Resets the position to the beginning.
123    pub fn reset(&mut self) {
124        self.position = 0;
125    }
126
127    /// Encodes the presence map to bytes.
128    ///
129    /// # Returns
130    /// The encoded bytes with stop-bit encoding.
131    #[must_use]
132    pub fn encode(&self) -> Vec<u8> {
133        if self.bits.is_empty() {
134            return vec![0x80]; // Empty pmap with stop bit
135        }
136
137        let mut result = Vec::new();
138        let mut bit_index = 0;
139
140        while bit_index < self.bits.len() {
141            let mut byte: u8 = 0;
142
143            // Pack 7 bits into each byte
144            for i in (0..7).rev() {
145                if bit_index < self.bits.len() && self.bits[bit_index] {
146                    byte |= 1 << i;
147                }
148                bit_index += 1;
149            }
150
151            // Set stop bit if this is the last byte
152            if bit_index >= self.bits.len() {
153                byte |= 0x80;
154            }
155
156            result.push(byte);
157        }
158
159        result
160    }
161}
162
163impl Default for PresenceMap {
164    fn default() -> Self {
165        Self::new()
166    }
167}
168
169/// Builder for constructing presence maps.
170#[derive(Debug, Default)]
171pub struct PresenceMapBuilder {
172    bits: Vec<bool>,
173}
174
175impl PresenceMapBuilder {
176    /// Creates a new builder.
177    #[must_use]
178    pub fn new() -> Self {
179        Self::default()
180    }
181
182    /// Adds a bit to the presence map.
183    #[must_use]
184    pub fn bit(mut self, present: bool) -> Self {
185        self.bits.push(present);
186        self
187    }
188
189    /// Builds the presence map.
190    #[must_use]
191    pub fn build(self) -> PresenceMap {
192        PresenceMap::from_bits(self.bits)
193    }
194}
195
196#[cfg(test)]
197mod tests {
198    use super::*;
199
200    #[test]
201    fn test_presence_map_decode_single_byte() {
202        // 0b1100_0000: stop bit (bit 7) = 1, bits 6-0 = 100_0000
203        // Extracted bits (from bit 6 to bit 0): 1, 0, 0, 0, 0, 0, 0
204        let data = [0b1100_0000];
205        let mut offset = 0;
206        let pmap = PresenceMap::decode(&data, &mut offset).unwrap();
207
208        assert_eq!(offset, 1);
209        assert_eq!(pmap.len(), 7);
210        assert!(pmap.bit(0)); // bit 6 of byte = 1
211        assert!(!pmap.bit(1)); // bit 5 of byte = 0
212        assert!(!pmap.bit(2)); // bit 4 of byte = 0
213    }
214
215    #[test]
216    fn test_presence_map_decode_multi_byte() {
217        let data = [0b0100_0000, 0b1000_0000]; // Two bytes
218        let mut offset = 0;
219        let pmap = PresenceMap::decode(&data, &mut offset).unwrap();
220
221        assert_eq!(offset, 2);
222        assert_eq!(pmap.len(), 14);
223    }
224
225    #[test]
226    fn test_presence_map_next_bit() {
227        let mut pmap = PresenceMap::from_bits(vec![true, false, true]);
228
229        assert!(pmap.next_bit());
230        assert!(!pmap.next_bit());
231        assert!(pmap.next_bit());
232        assert!(!pmap.next_bit()); // Exhausted
233    }
234
235    #[test]
236    fn test_presence_map_encode() {
237        let pmap = PresenceMap::from_bits(vec![true, true, false, false, false, false, false]);
238        let encoded = pmap.encode();
239
240        assert_eq!(encoded.len(), 1);
241        assert_eq!(encoded[0], 0b1110_0000);
242    }
243
244    #[test]
245    fn test_presence_map_builder() {
246        let pmap = PresenceMapBuilder::new()
247            .bit(true)
248            .bit(false)
249            .bit(true)
250            .build();
251
252        assert_eq!(pmap.len(), 3);
253        assert!(pmap.bit(0));
254        assert!(!pmap.bit(1));
255        assert!(pmap.bit(2));
256    }
257}