Skip to main content

aleph_filter/
metadata.rs

1// This file contains metadata flags for each slot.
2// - **Occupied** (bit 0): Canonical slot contains a run
3// - **Continuation** (bit 1): Slot continues a run from a previous slot
4// - **Shifted** (bit 2): Data was displaced from its canonical position due to collisions
5// These flags work together to determine the structure of clusters and runs.
6
7use std::fmt;
8
9#[derive(Clone, Copy, Default, PartialEq, Eq)]
10/// A compact metadata tag for one filter slot.
11/// 
12/// Wraps a single u8 with three bit flags:
13/// - Occupied (bit 0)
14/// - Continuation (bit 1)
15/// - Shifted (bit 2)
16pub struct SlotMetadata(u8);
17
18impl SlotMetadata {
19    // BIT POSITIONS
20    
21    /// Bit position for the "occupied" flag.
22    /// Indicates this canonical slot is the start of a run.
23    const OCCUPIED_BIT: u8 = 0;
24    
25    /// Bit position for the "continuation" flag.
26    /// Indicates this slot continues a run from a previous slot.
27    const CONTINUATION_BIT: u8 = 1;
28    
29    /// Bit position for the "shifted" flag.
30    /// Indicates data here was displaced from its canonical position.
31    const SHIFTED_BIT: u8 = 2;
32
33    // CONSTRUCTORS
34
35    /// Creates empty metadata (all bits off).
36    /// 
37    /// # Returns
38    /// 
39    /// Metadata with all flags cleared
40    #[inline]
41    pub const fn new() -> Self {
42        return Self(0);
43    }
44    
45    /// Creates metadata with specific flag values.
46    /// 
47    /// # Arguments
48    /// 
49    /// * `is_occupied` - Whether this canonical slot starts a run
50    /// * `is_continuation` - Whether this slot continues a run
51    /// * `is_shifted` - Whether this slot's data is displaced from canonical position
52    /// 
53    /// # Returns
54    /// 
55    /// Metadata with the specified flags set
56    #[inline]
57    pub const fn with_flags(is_occupied: bool, is_continuation: bool, is_shifted: bool) -> Self {
58        let mut value = 0u8;
59        if is_occupied {
60            value |= 1 << Self::OCCUPIED_BIT;
61        }
62        if is_continuation {
63            value |= 1 << Self::CONTINUATION_BIT;
64        }
65
66        if is_shifted {
67            value |= 1 << Self::SHIFTED_BIT;
68        }
69        return Self(value);
70    }
71
72    // QUERIES AND SETTERS
73
74    /// Checks if this metadata is completely empty (all flags off).
75    /// 
76    /// # Returns
77    /// 
78    /// `true` if no flags are set
79    #[inline]
80    pub const fn is_empty(&self) -> bool {
81        return self.0 == 0;
82    }
83
84    /// Reads the "occupied" flag.
85    /// 
86    /// Indicates whether this canonical slot is the start of a run.
87    /// 
88    /// # Returns
89    /// 
90    /// `true` if occupied
91    #[inline]
92    pub const fn is_occupied(&self) -> bool {
93        return (self.0 >> Self::OCCUPIED_BIT) & 1 == 1;
94    }
95
96    /// Sets the "occupied" flag.
97    /// 
98    /// # Arguments
99    /// 
100    /// * `value` - `true` to set occupied, `false` to clear
101    #[inline]
102    pub fn set_occupied(&mut self, value: bool){
103        if value {
104            self.0 |= 1 << Self::OCCUPIED_BIT;
105        } else {
106            self.0 &= !(1 << Self::OCCUPIED_BIT);
107        }
108    }
109    
110    /// Reads the "continuation" flag.
111    /// 
112    /// Indicates whether this slot is part of a run that started in a previous slot.
113    /// 
114    /// # Returns
115    /// 
116    /// `true` if this is a continuation slot
117    #[inline]
118    pub const fn is_continuation(&self) -> bool {
119        return (self.0 >> Self::CONTINUATION_BIT) & 1 == 1;
120    }
121    
122    /// Sets the "continuation" flag.
123    /// 
124    /// # Arguments
125    /// 
126    /// * `value` - `true` to mark as continuation, `false` otherwise
127    #[inline]
128    pub const fn set_continuation(&mut self, value: bool){
129        if value {
130            self.0 |= 1 << Self::CONTINUATION_BIT;
131        } else{
132            self.0 &= !(1 << Self::CONTINUATION_BIT);
133        }
134    }
135    
136    /// Reads the "shifted" flag.
137    /// 
138    /// Indicates whether this slot's data was displaced from its canonical position
139    /// due to collisions during insertion.
140    /// 
141    /// # Returns
142    /// 
143    /// `true` if this slot is shifted
144    #[inline]
145    pub const fn is_shifted(&self) -> bool {
146        return (self.0 >> Self::SHIFTED_BIT) & 1 == 1;
147    }
148
149    /// Sets the "shifted" flag.
150    /// 
151    /// # Arguments
152    /// 
153    /// * `value` - `true` to mark as shifted, `false` otherwise
154    pub const fn set_shifted(&mut self, value: bool){
155        if value{
156            self.0 |= 1 << Self::SHIFTED_BIT;
157        } else {
158            self.0 &= !(1 << Self::SHIFTED_BIT);
159        }
160    }
161
162    /// Checks if this slot is a cluster start.
163    /// 
164    /// A cluster start is occupied and not shifted (canonical position).
165    /// 
166    /// # Returns
167    /// 
168    /// `true` if this slot starts a cluster
169    #[inline]
170    pub const fn is_cluster_start(&self) -> bool{
171        return self.is_occupied() && !self.is_shifted();
172    }
173
174    /// Checks if this slot is a run start within a cluster.
175    /// 
176    /// A run start is not a continuation and has some presence signal
177    /// (either occupied or shifted).
178    /// 
179    /// # Returns
180    /// 
181    /// `true` if this slot starts a run
182    #[inline]
183    pub const fn is_run_start(&self) -> bool {
184        return !self.is_continuation() && (self.is_occupied() || self.is_shifted());
185    }
186
187    /// Checks if this slot has meaningful metadata.
188    /// 
189    /// A slot has data if any of the three flags are set.
190    /// 
191    /// # Returns
192    /// 
193    /// `true` if any flag is set
194    #[inline]
195    pub const fn has_data(&self) -> bool {
196        return self.is_shifted() || self.is_continuation() || self.is_occupied();
197    }
198    
199    // SERIALIZATION & RAW ACCESS
200    
201    /// Clears all metadata flags (resets to empty).
202    /// 
203    /// # Complexity
204    /// 
205    /// O(1)
206    #[inline]
207    pub fn clear(&mut self) {
208        self.0 = 0
209    }
210
211    /// Returns the raw byte value for serialization/storage.
212    /// 
213    /// # Returns
214    /// 
215    /// The 8-bit flags value
216    pub const fn raw(&self) -> u8 {
217        return self.0;
218    }
219
220    /// Constructs metadata from a raw byte (for deserialization).
221    /// 
222    /// # Arguments
223    /// 
224    /// * `value` - Raw byte containing bit flags
225    /// 
226    /// # Returns
227    /// 
228    /// Reconstructed metadata
229    pub const fn from_raw(value: u8) -> Self {
230        return Self(value);
231    }
232}
233
234// DEBUG & DISPLAY FORMATTING
235
236impl fmt::Debug for SlotMetadata {
237    /// Produces verbose debug output showing all three flags by name.
238    /// 
239    /// Example: `SlotMetadata { occupied: true, continuation: false, shifted: true }`
240    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241        write!(f, 
242        "SlotMetadata {{ occupied: {}, continuation: {}, shifted: {}}}", 
243    self.is_occupied(), 
244    self.is_continuation(),
245    self.is_shifted()
246    )
247    }
248}
249
250impl fmt::Display for SlotMetadata {
251    /// Produces compact 3-character display of metadata flags.
252    /// 
253    /// Format: `[O|-][C|-][S|-]`
254    /// - `O` = occupied, `-` = not occupied
255    /// - `C` = continuation, `-` = not continuation
256    /// - `S` = shifted, `-` = not shifted
257    /// 
258    /// Examples: `OCS`, `O--`, `-C-`, `---`
259    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result{
260        write!(f, "{}{}{}", 
261        if self.is_occupied() {"O"} else {"-"},
262        if self.is_continuation() {"C"} else {"-"},  
263        if self.is_shifted() {"S"} else {"-"},
264    )
265    }
266}