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}