iso8583_core/
bitmap_simd.rs1#![cfg_attr(not(feature = "std"), no_std)]
35
36#[derive(Debug, Clone, PartialEq, Eq)]
38pub struct Bitmap {
39 primary: [u8; 8],
41 secondary: Option<[u8; 8]>,
43 tertiary: Option<[u8; 8]>,
45}
46
47impl Bitmap {
48 #[inline]
50 pub const fn new() -> Self {
51 Self {
52 primary: [0u8; 8],
53 secondary: None,
54 tertiary: None,
55 }
56 }
57
58 #[inline]
60 pub fn is_set(&self, field: u8) -> bool {
61 if field == 0 || field > 192 {
62 return false;
63 }
64
65 match field {
66 1..=64 => Self::is_set_in_bitmap(&self.primary, field),
67 65..=128 => {
68 if let Some(ref secondary) = self.secondary {
69 Self::is_set_in_bitmap(secondary, field - 64)
70 } else {
71 false
72 }
73 }
74 129..=192 => {
75 if let Some(ref tertiary) = self.tertiary {
76 Self::is_set_in_bitmap(tertiary, field - 128)
77 } else {
78 false
79 }
80 }
81 _ => false,
82 }
83 }
84
85 #[inline]
87 pub fn set(&mut self, field: u8) -> Result<(), &'static str> {
88 if field == 0 || field > 192 {
89 return Err("Field number out of range (1-192)");
90 }
91
92 match field {
93 1 => {
94 Self::set_in_bitmap(&mut self.primary, 1);
96 if self.secondary.is_none() {
97 self.secondary = Some([0u8; 8]);
98 }
99 }
100 2..=64 => {
101 Self::set_in_bitmap(&mut self.primary, field);
102 }
103 65 => {
104 if self.secondary.is_none() {
106 self.secondary = Some([0u8; 8]);
107 Self::set_in_bitmap(&mut self.primary, 1); }
109 if let Some(ref mut secondary) = self.secondary {
110 Self::set_in_bitmap(secondary, 1);
111 if self.tertiary.is_none() {
112 self.tertiary = Some([0u8; 8]);
113 }
114 }
115 }
116 66..=128 => {
117 if self.secondary.is_none() {
118 self.secondary = Some([0u8; 8]);
119 Self::set_in_bitmap(&mut self.primary, 1); }
121 if let Some(ref mut secondary) = self.secondary {
122 Self::set_in_bitmap(secondary, field - 64);
123 }
124 }
125 129..=192 => {
126 if self.secondary.is_none() {
128 self.secondary = Some([0u8; 8]);
129 Self::set_in_bitmap(&mut self.primary, 1);
130 }
131 if let Some(ref mut secondary) = self.secondary {
132 if self.tertiary.is_none() {
133 self.tertiary = Some([0u8; 8]);
134 Self::set_in_bitmap(secondary, 1); }
136 }
137 if let Some(ref mut tertiary) = self.tertiary {
138 Self::set_in_bitmap(tertiary, field - 128);
139 }
140 }
141 _ => return Err("Field number out of range"),
142 }
143
144 Ok(())
145 }
146
147 #[inline]
149 pub fn clear(&mut self, field: u8) -> Result<(), &'static str> {
150 if field == 0 || field > 192 {
151 return Err("Field number out of range (1-192)");
152 }
153
154 match field {
155 1..=64 => {
156 Self::clear_in_bitmap(&mut self.primary, field);
157 }
158 65..=128 => {
159 if let Some(ref mut secondary) = self.secondary {
160 Self::clear_in_bitmap(secondary, field - 64);
161 }
162 }
163 129..=192 => {
164 if let Some(ref mut tertiary) = self.tertiary {
165 Self::clear_in_bitmap(tertiary, field - 128);
166 }
167 }
168 _ => return Err("Field number out of range"),
169 }
170
171 Ok(())
172 }
173
174 #[inline]
176 pub fn is_empty(&self) -> bool {
177 !self.has_any_set(&self.primary)
178 && !self.secondary.as_ref().is_some_and(|s| self.has_any_set(s))
179 && !self.tertiary.as_ref().is_some_and(|t| self.has_any_set(t))
180 }
181
182 pub fn get_set_fields(&self) -> ([u8; 192], usize) {
185 let mut fields = [0u8; 192];
186 let mut count = 0;
187
188 for field in 1..=64 {
190 if Self::is_set_in_bitmap(&self.primary, field) {
191 fields[count] = field;
192 count += 1;
193 }
194 }
195
196 if let Some(ref secondary) = self.secondary {
198 for field in 1..=64 {
199 if Self::is_set_in_bitmap(secondary, field) {
200 fields[count] = field + 64;
201 count += 1;
202 }
203 }
204 }
205
206 if let Some(ref tertiary) = self.tertiary {
208 for field in 1..=64 {
209 if Self::is_set_in_bitmap(tertiary, field) {
210 fields[count] = field + 128;
211 count += 1;
212 }
213 }
214 }
215
216 (fields, count)
217 }
218
219 pub fn to_bytes(&self) -> ([u8; 24], usize) {
222 let mut bytes = [0u8; 24];
223 let mut len = 0;
224
225 bytes[len..len + 8].copy_from_slice(&self.primary);
227 len += 8;
228
229 if let Some(ref secondary) = self.secondary {
231 bytes[len..len + 8].copy_from_slice(secondary);
232 len += 8;
233 }
234
235 if let Some(ref tertiary) = self.tertiary {
237 bytes[len..len + 8].copy_from_slice(tertiary);
238 len += 8;
239 }
240
241 (bytes, len)
242 }
243
244 pub fn from_bytes(bytes: &[u8]) -> Result<Self, &'static str> {
246 if bytes.len() < 8 {
247 return Err("Bitmap must be at least 8 bytes");
248 }
249
250 let mut primary = [0u8; 8];
251 primary.copy_from_slice(&bytes[0..8]);
252
253 let mut bitmap = Self {
254 primary,
255 secondary: None,
256 tertiary: None,
257 };
258
259 if bitmap.is_set(1) && bytes.len() >= 16 {
261 let mut secondary = [0u8; 8];
262 secondary.copy_from_slice(&bytes[8..16]);
263 bitmap.secondary = Some(secondary);
264
265 if bitmap.is_set(65) && bytes.len() >= 24 {
267 let mut tertiary = [0u8; 8];
268 tertiary.copy_from_slice(&bytes[16..24]);
269 bitmap.tertiary = Some(tertiary);
270 }
271 }
272
273 Ok(bitmap)
274 }
275
276 pub fn from_hex(hex_str: &str) -> Result<Self, &'static str> {
278 let bytes = hex::decode(hex_str).map_err(|_| "Invalid hex string")?;
279 Self::from_bytes(&bytes)
280 }
281
282 #[inline]
286 fn is_set_in_bitmap(bitmap: &[u8; 8], field: u8) -> bool {
287 if field == 0 || field > 64 {
288 return false;
289 }
290
291 let byte_index = ((field - 1) / 8) as usize;
292 let bit_index = 7 - ((field - 1) % 8);
293
294 bitmap[byte_index] & (1 << bit_index) != 0
295 }
296
297 #[inline]
299 fn set_in_bitmap(bitmap: &mut [u8; 8], field: u8) {
300 if field == 0 || field > 64 {
301 return;
302 }
303
304 let byte_index = ((field - 1) / 8) as usize;
305 let bit_index = 7 - ((field - 1) % 8);
306
307 bitmap[byte_index] |= 1 << bit_index;
308 }
309
310 #[inline]
312 fn clear_in_bitmap(bitmap: &mut [u8; 8], field: u8) {
313 if field == 0 || field > 64 {
314 return;
315 }
316
317 let byte_index = ((field - 1) / 8) as usize;
318 let bit_index = 7 - ((field - 1) % 8);
319
320 bitmap[byte_index] &= !(1 << bit_index);
321 }
322
323 #[cfg(all(feature = "simd", target_arch = "x86_64", target_feature = "sse2"))]
325 #[inline]
326 fn has_any_set(&self, bitmap: &[u8; 8]) -> bool {
327 #[cfg(target_arch = "x86_64")]
328 unsafe {
335 use core::arch::x86_64::*;
336 let ptr = bitmap.as_ptr() as *const __m128i;
337 let value = _mm_loadl_epi64(ptr);
338 _mm_testz_si128(value, value) == 0
339 }
340 }
341
342 #[cfg(all(feature = "simd", target_arch = "aarch64", target_feature = "neon"))]
344 #[inline]
345 fn has_any_set(&self, bitmap: &[u8; 8]) -> bool {
346 #[cfg(target_arch = "aarch64")]
347 unsafe {
355 use core::arch::aarch64::*;
356 let value = vld1_u8(bitmap.as_ptr());
357 let zero = vdup_n_u8(0);
358 let cmp = vceq_u8(value, zero);
359 vminv_u8(cmp) == 0
360 }
361 }
362
363 #[cfg(not(all(
365 feature = "simd",
366 any(
367 all(target_arch = "x86_64", target_feature = "sse2"),
368 all(target_arch = "aarch64", target_feature = "neon")
369 )
370 )))]
371 #[inline]
372 fn has_any_set(&self, bitmap: &[u8; 8]) -> bool {
373 bitmap.iter().any(|&b| b != 0)
374 }
375}
376
377impl Default for Bitmap {
378 fn default() -> Self {
379 Self::new()
380 }
381}
382
383#[cfg(test)]
384mod tests {
385 use super::*;
386
387 #[test]
388 fn test_new_bitmap() {
389 let bitmap = Bitmap::new();
390 assert!(bitmap.is_empty());
391 }
392
393 #[test]
394 fn test_set_and_check() {
395 let mut bitmap = Bitmap::new();
396 assert!(bitmap.set(2).is_ok());
397 assert!(bitmap.is_set(2));
398 assert!(!bitmap.is_set(3));
399 }
400
401 #[test]
402 fn test_clear() {
403 let mut bitmap = Bitmap::new();
404 bitmap.set(2).unwrap();
405 assert!(bitmap.is_set(2));
406 bitmap.clear(2).unwrap();
407 assert!(!bitmap.is_set(2));
408 }
409
410 #[test]
411 fn test_secondary_bitmap() {
412 let mut bitmap = Bitmap::new();
413 bitmap.set(70).unwrap();
414 assert!(bitmap.is_set(1)); assert!(bitmap.is_set(70));
416 }
417
418 #[test]
419 fn test_roundtrip() {
420 let mut bitmap = Bitmap::new();
421 bitmap.set(2).unwrap();
422 bitmap.set(3).unwrap();
423 bitmap.set(4).unwrap();
424
425 let (bytes_array, len) = bitmap.to_bytes();
426 let restored = Bitmap::from_bytes(&bytes_array[..len]).unwrap();
427
428 assert_eq!(bitmap, restored);
429 }
430
431 #[test]
432 fn test_get_set_fields() {
433 let mut bitmap = Bitmap::new();
434 bitmap.set(2).unwrap();
435 bitmap.set(4).unwrap();
436 bitmap.set(11).unwrap();
437
438 let (fields, count) = bitmap.get_set_fields();
439 let fields_slice = &fields[..count];
440
441 assert!(fields_slice.contains(&2));
442 assert!(fields_slice.contains(&4));
443 assert!(fields_slice.contains(&11));
444 }
445
446 #[test]
447 fn test_bounds() {
448 let mut bitmap = Bitmap::new();
449 assert!(bitmap.set(0).is_err());
450 assert!(bitmap.set(193).is_err());
451 }
452}