Skip to main content

commonware_utils/bitmap/
mod.rs

1//! Bitmap implementation
2//!
3//! The bitmap is a compact representation of a sequence of bits, using chunks of bytes for a
4//! more-efficient memory layout than doing [`Vec<bool>`].
5
6#[cfg(not(feature = "std"))]
7use alloc::{collections::VecDeque, vec::Vec};
8use bytes::{Buf, BufMut};
9use commonware_codec::{util::at_least, EncodeSize, Error as CodecError, Read, ReadExt, Write};
10use core::{
11    fmt::{self, Formatter, Write as _},
12    iter,
13    ops::{BitAnd, BitOr, BitXor, Index, Range},
14};
15#[cfg(feature = "std")]
16use std::collections::VecDeque;
17
18mod prunable;
19pub use prunable::Prunable;
20
21pub mod historical;
22
23/// The default [BitMap] chunk size in bytes.
24pub const DEFAULT_CHUNK_SIZE: usize = 8;
25
26/// A bitmap that stores data in chunks of N bytes.
27///
28/// # Panics
29///
30/// Operations panic if `bit / CHUNK_SIZE_BITS > usize::MAX`. On 32-bit systems
31/// with N=32, this occurs at bit >= 1,099,511,627,776.
32#[derive(Clone, PartialEq, Eq, Hash)]
33pub struct BitMap<const N: usize = DEFAULT_CHUNK_SIZE> {
34    /// The bitmap itself, in chunks of size N bytes. Within each byte, lowest order bits are
35    /// treated as coming before higher order bits in the bit ordering.
36    ///
37    /// Invariant: `chunks.len() == len.div_ceil(CHUNK_SIZE_BITS)`
38    /// Invariant: All bits at index `i` where `i >= len` must be 0.
39    chunks: VecDeque<[u8; N]>,
40
41    /// The total number of bits stored in the bitmap.
42    len: u64,
43}
44
45impl<const N: usize> BitMap<N> {
46    const _CHUNK_SIZE_NON_ZERO_ASSERT: () = assert!(N > 0, "chunk size must be > 0");
47
48    /// The size of a chunk in bits.
49    pub const CHUNK_SIZE_BITS: u64 = (N * 8) as u64;
50
51    /// A chunk of all 0s.
52    const EMPTY_CHUNK: [u8; N] = [0u8; N];
53
54    /// A chunk of all 1s.
55    const FULL_CHUNK: [u8; N] = [u8::MAX; N];
56
57    /* Constructors */
58
59    /// Create a new empty bitmap.
60    pub const fn new() -> Self {
61        #[allow(path_statements)]
62        Self::_CHUNK_SIZE_NON_ZERO_ASSERT; // Prevent compilation for N == 0
63
64        Self {
65            chunks: VecDeque::new(),
66            len: 0,
67        }
68    }
69
70    // Create a new empty bitmap with the capacity to hold `size` bits without reallocating.
71    pub fn with_capacity(size: u64) -> Self {
72        #[allow(path_statements)]
73        Self::_CHUNK_SIZE_NON_ZERO_ASSERT; // Prevent compilation for N == 0
74
75        Self {
76            chunks: VecDeque::with_capacity(size.div_ceil(Self::CHUNK_SIZE_BITS) as usize),
77            len: 0,
78        }
79    }
80
81    /// Create a new bitmap with `size` bits, with all bits set to 0.
82    pub fn zeroes(size: u64) -> Self {
83        #[allow(path_statements)]
84        Self::_CHUNK_SIZE_NON_ZERO_ASSERT; // Prevent compilation for N == 0
85
86        let num_chunks = size.div_ceil(Self::CHUNK_SIZE_BITS) as usize;
87        let mut chunks = VecDeque::with_capacity(num_chunks);
88        for _ in 0..num_chunks {
89            chunks.push_back(Self::EMPTY_CHUNK);
90        }
91        Self { chunks, len: size }
92    }
93
94    /// Create a new bitmap with `size` bits, with all bits set to 1.
95    pub fn ones(size: u64) -> Self {
96        #[allow(path_statements)]
97        Self::_CHUNK_SIZE_NON_ZERO_ASSERT; // Prevent compilation for N == 0
98
99        let num_chunks = size.div_ceil(Self::CHUNK_SIZE_BITS) as usize;
100        let mut chunks = VecDeque::with_capacity(num_chunks);
101        for _ in 0..num_chunks {
102            chunks.push_back(Self::FULL_CHUNK);
103        }
104        let mut result = Self { chunks, len: size };
105        // Clear trailing bits to maintain invariant
106        result.clear_trailing_bits();
107        result
108    }
109
110    /* Length */
111
112    /// Return the number of bits currently stored in the bitmap.
113    #[inline]
114    pub const fn len(&self) -> u64 {
115        self.len
116    }
117
118    /// Returns true if the bitmap is empty.
119    #[inline]
120    pub const fn is_empty(&self) -> bool {
121        self.len() == 0
122    }
123
124    /// Returns true if the bitmap length is aligned to a chunk boundary.
125    #[inline]
126    pub const fn is_chunk_aligned(&self) -> bool {
127        self.len.is_multiple_of(Self::CHUNK_SIZE_BITS)
128    }
129
130    // Get the number of chunks currently in the bitmap.
131    fn chunks_len(&self) -> usize {
132        self.chunks.len()
133    }
134
135    /* Getters */
136
137    /// Get the value of the bit at the given index.
138    ///
139    /// # Warning
140    ///
141    /// Panics if the bit doesn't exist.
142    #[inline]
143    pub fn get(&self, bit: u64) -> bool {
144        let chunk = self.get_chunk_containing(bit);
145        Self::get_bit_from_chunk(chunk, bit)
146    }
147
148    /// Returns the bitmap chunk containing the given bit.
149    ///
150    /// # Warning
151    ///
152    /// Panics if the bit doesn't exist.
153    #[inline]
154    fn get_chunk_containing(&self, bit: u64) -> &[u8; N] {
155        assert!(
156            bit < self.len(),
157            "bit {} out of bounds (len: {})",
158            bit,
159            self.len()
160        );
161        &self.chunks[Self::to_chunk_index(bit)]
162    }
163
164    /// Get a reference to a chunk by its index in the current bitmap.
165    /// Note this is an index into the chunks, not a bit.
166    ///
167    /// # Warning
168    ///
169    /// Panics if the `chunk` is out of bounds.
170    #[inline]
171    pub(super) fn get_chunk(&self, chunk: usize) -> &[u8; N] {
172        assert!(
173            chunk < self.chunks.len(),
174            "chunk {} out of bounds (chunks: {})",
175            chunk,
176            self.chunks.len()
177        );
178        &self.chunks[chunk]
179    }
180
181    /// Get the value at the given `bit` from the `chunk`.
182    /// `bit` is an index into the entire bitmap, not just the chunk.
183    #[inline]
184    pub const fn get_bit_from_chunk(chunk: &[u8; N], bit: u64) -> bool {
185        let byte = Self::chunk_byte_offset(bit);
186        let byte = chunk[byte];
187        let mask = Self::chunk_byte_bitmask(bit);
188        (byte & mask) != 0
189    }
190
191    /// Return the last chunk of the bitmap and its size in bits.
192    ///
193    /// # Panics
194    ///
195    /// Panics if bitmap is empty.
196    #[inline]
197    fn last_chunk(&self) -> (&[u8; N], u64) {
198        let rem = self.len % Self::CHUNK_SIZE_BITS;
199        let bits_in_last_chunk = if rem == 0 { Self::CHUNK_SIZE_BITS } else { rem };
200        (self.chunks.back().unwrap(), bits_in_last_chunk)
201    }
202
203    /* Setters */
204
205    /// Add a single bit to the bitmap.
206    pub fn push(&mut self, bit: bool) {
207        // Check if we need a new chunk
208        if self.is_chunk_aligned() {
209            self.chunks.push_back(Self::EMPTY_CHUNK);
210        }
211
212        // Append to the last chunk
213        if bit {
214            let last_chunk = self.chunks.back_mut().unwrap();
215            let chunk_byte = Self::chunk_byte_offset(self.len);
216            last_chunk[chunk_byte] |= Self::chunk_byte_bitmask(self.len);
217        }
218        // If bit is false, just advance len -- the bit is already 0
219        self.len += 1;
220    }
221
222    /// Remove and return the last bit from the bitmap.
223    ///
224    /// # Warning
225    ///
226    /// Panics if the bitmap is empty.
227    pub fn pop(&mut self) -> bool {
228        assert!(!self.is_empty(), "Cannot pop from empty bitmap");
229
230        // Get the bit value at the last position
231        let last_bit_pos = self.len - 1;
232        let bit = Self::get_bit_from_chunk(self.chunks.back().unwrap(), last_bit_pos);
233
234        // Decrement length
235        self.len -= 1;
236
237        // Clear the bit we just popped to maintain invariant (if it was 1)
238        if bit {
239            let chunk_byte = Self::chunk_byte_offset(last_bit_pos);
240            let mask = Self::chunk_byte_bitmask(last_bit_pos);
241            self.chunks.back_mut().unwrap()[chunk_byte] &= !mask;
242        }
243
244        // Remove the last chunk if it's now empty
245        if self.is_chunk_aligned() {
246            self.chunks.pop_back();
247        }
248
249        bit
250    }
251
252    /// Remove and return the last complete chunk from the bitmap.
253    ///
254    /// # Warning
255    ///
256    /// Panics if the bitmap has fewer than `CHUNK_SIZE_BITS` bits or if not chunk-aligned.
257    pub(super) fn pop_chunk(&mut self) -> [u8; N] {
258        assert!(
259            self.len() >= Self::CHUNK_SIZE_BITS,
260            "cannot pop chunk: bitmap has fewer than CHUNK_SIZE_BITS bits"
261        );
262        assert!(
263            self.is_chunk_aligned(),
264            "cannot pop chunk when not chunk aligned"
265        );
266
267        // Remove and return the last data chunk
268        let chunk = self.chunks.pop_back().expect("chunk must exist");
269        self.len -= Self::CHUNK_SIZE_BITS;
270        chunk
271    }
272
273    /// Flips the given bit.
274    ///
275    /// # Panics
276    ///
277    /// Panics if `bit` is out of bounds.
278    #[inline]
279    pub fn flip(&mut self, bit: u64) {
280        self.assert_bit(bit);
281        let chunk = Self::to_chunk_index(bit);
282        let byte = Self::chunk_byte_offset(bit);
283        let mask = Self::chunk_byte_bitmask(bit);
284        self.chunks[chunk][byte] ^= mask;
285    }
286
287    /// Flips all bits (1s become 0s and vice versa).
288    pub fn flip_all(&mut self) {
289        for chunk in &mut self.chunks {
290            for byte in chunk {
291                *byte = !*byte;
292            }
293        }
294        // Clear trailing bits to maintain invariant
295        self.clear_trailing_bits();
296    }
297
298    /// Set the value of the referenced bit.
299    ///
300    /// # Warning
301    ///
302    /// Panics if the bit doesn't exist.
303    pub fn set(&mut self, bit: u64, value: bool) {
304        assert!(
305            bit < self.len(),
306            "bit {} out of bounds (len: {})",
307            bit,
308            self.len()
309        );
310
311        let chunk = &mut self.chunks[Self::to_chunk_index(bit)];
312        let byte = Self::chunk_byte_offset(bit);
313        let mask = Self::chunk_byte_bitmask(bit);
314        if value {
315            chunk[byte] |= mask;
316        } else {
317            chunk[byte] &= !mask;
318        }
319    }
320
321    /// Sets all bits to the specified value.
322    #[inline]
323    pub fn set_all(&mut self, bit: bool) {
324        let value = if bit { u8::MAX } else { 0 };
325        for chunk in &mut self.chunks {
326            chunk.fill(value);
327        }
328        // Clear trailing bits to maintain invariant
329        if bit {
330            self.clear_trailing_bits();
331        }
332    }
333
334    // Add a byte's worth of bits to the bitmap.
335    //
336    // # Warning
337    //
338    // Panics if self.len is not byte aligned.
339    fn push_byte(&mut self, byte: u8) {
340        assert!(
341            self.len.is_multiple_of(8),
342            "cannot add byte when not byte aligned"
343        );
344
345        // Check if we need a new chunk
346        if self.is_chunk_aligned() {
347            self.chunks.push_back(Self::EMPTY_CHUNK);
348        }
349
350        let chunk_byte = Self::chunk_byte_offset(self.len);
351        self.chunks.back_mut().unwrap()[chunk_byte] = byte;
352        self.len += 8;
353    }
354
355    /// Add a chunk of bits to the bitmap.
356    ///
357    /// # Warning
358    ///
359    /// Panics if self.len is not chunk aligned.
360    pub fn push_chunk(&mut self, chunk: &[u8; N]) {
361        assert!(
362            self.is_chunk_aligned(),
363            "cannot add chunk when not chunk aligned"
364        );
365        self.chunks.push_back(*chunk);
366        self.len += Self::CHUNK_SIZE_BITS;
367    }
368
369    /* Invariant Maintenance */
370
371    /// Clear all bits in the last chunk that are >= self.len to maintain the invariant.
372    /// Returns true if any bits were flipped from 1 to 0.
373    fn clear_trailing_bits(&mut self) -> bool {
374        if self.chunks.is_empty() {
375            return false;
376        }
377
378        let pos_in_chunk = self.len % Self::CHUNK_SIZE_BITS;
379        if pos_in_chunk == 0 {
380            // Chunk is full -- there are no trailing bits to clear.
381            return false;
382        }
383
384        let mut flipped_any = false;
385        let last_chunk = self.chunks.back_mut().unwrap();
386
387        // Clear whole bytes after the last valid bit
388        let last_byte_index = ((pos_in_chunk - 1) / 8) as usize;
389        for byte in last_chunk.iter_mut().skip(last_byte_index + 1) {
390            if *byte != 0 {
391                flipped_any = true;
392                *byte = 0;
393            }
394        }
395
396        // Clear the trailing bits in the last partial byte
397        let bits_in_last_byte = pos_in_chunk % 8;
398        if bits_in_last_byte != 0 {
399            let mask = (1u8 << bits_in_last_byte) - 1;
400            let old_byte = last_chunk[last_byte_index];
401            let new_byte = old_byte & mask;
402            if old_byte != new_byte {
403                flipped_any = true;
404                last_chunk[last_byte_index] = new_byte;
405            }
406        }
407
408        flipped_any
409    }
410
411    /* Pruning */
412
413    /// Remove the first `chunks` chunks from the bitmap.
414    ///
415    /// # Warning
416    ///
417    /// Panics if trying to prune more chunks than exist.
418    fn prune_chunks(&mut self, chunks: usize) {
419        assert!(
420            chunks <= self.chunks.len(),
421            "cannot prune {chunks} chunks, only {} available",
422            self.chunks.len()
423        );
424        self.chunks.drain(..chunks);
425        // Update len to reflect the removed chunks
426        let bits_removed = (chunks as u64) * Self::CHUNK_SIZE_BITS;
427        self.len = self.len.saturating_sub(bits_removed);
428    }
429
430    /// Prepend a chunk to the beginning of the bitmap.
431    pub(super) fn prepend_chunk(&mut self, chunk: &[u8; N]) {
432        self.chunks.push_front(*chunk);
433        self.len += Self::CHUNK_SIZE_BITS;
434    }
435
436    /// Overwrite a chunk's data at the given index.
437    ///
438    /// Replaces the entire chunk data, including any bits beyond `len()` in the last chunk.
439    /// The caller is responsible for ensuring `chunk_data` has the correct bit pattern
440    /// (e.g., zeros beyond the valid length if this is a partial last chunk).
441    ///
442    /// # Panics
443    ///
444    /// Panics if chunk_index is out of bounds.
445    pub(super) fn set_chunk_by_index(&mut self, chunk_index: usize, chunk_data: &[u8; N]) {
446        assert!(
447            chunk_index < self.chunks.len(),
448            "chunk index {chunk_index} out of bounds (chunks_len: {})",
449            self.chunks.len()
450        );
451        self.chunks[chunk_index].copy_from_slice(chunk_data);
452    }
453
454    /* Counting */
455
456    /// Returns the number of bits set to 1.
457    #[inline]
458    pub fn count_ones(&self) -> u64 {
459        // Thanks to the invariant that trailing bits are always 0,
460        // we can simply count all set bits in all chunks.
461        // Iterate over both contiguous deque segments and count 64-bit words first.
462        let (front, back) = self.chunks.as_slices();
463        Self::count_ones_in_chunk_slice(front) + Self::count_ones_in_chunk_slice(back)
464    }
465
466    #[inline]
467    fn count_ones_in_chunk_slice(chunks: &[[u8; N]]) -> u64 {
468        let mut total = 0u64;
469        let mut words = chunks.as_flattened().chunks_exact(8);
470        for word in &mut words {
471            total += u64::from_le_bytes(word.try_into().unwrap()).count_ones() as u64;
472        }
473        for byte in words.remainder() {
474            total += byte.count_ones() as u64;
475        }
476        total
477    }
478
479    /// Returns the number of bits set to 0.
480    #[inline]
481    pub fn count_zeros(&self) -> u64 {
482        self.len() - self.count_ones()
483    }
484
485    /* Indexing Helpers */
486
487    /// Convert a bit offset into a bitmask for the byte containing that bit.
488    #[inline]
489    pub(super) const fn chunk_byte_bitmask(bit: u64) -> u8 {
490        1 << (bit % 8)
491    }
492
493    /// Convert a bit into the index of the byte within a chunk containing the bit.
494    #[inline]
495    pub(super) const fn chunk_byte_offset(bit: u64) -> usize {
496        ((bit / 8) % N as u64) as usize
497    }
498
499    /// Convert a bit into the index of the chunk it belongs to.
500    ///
501    /// # Panics
502    ///
503    /// Panics if the chunk index overflows `usize`.
504    #[inline]
505    pub(super) fn to_chunk_index(bit: u64) -> usize {
506        let chunk = bit / Self::CHUNK_SIZE_BITS;
507        assert!(
508            chunk <= usize::MAX as u64,
509            "chunk overflow: {chunk} exceeds usize::MAX",
510        );
511        chunk as usize
512    }
513
514    /* Iterator */
515
516    /// Creates an iterator over the bits.
517    pub const fn iter(&self) -> Iterator<'_, N> {
518        Iterator {
519            bitmap: self,
520            pos: 0,
521        }
522    }
523
524    /* Bitwise Operations */
525
526    /// Helper for binary operations
527    #[inline]
528    fn binary_op<F: Fn(u8, u8) -> u8>(&mut self, other: &Self, op: F) {
529        self.assert_eq_len(other);
530        for (a_chunk, b_chunk) in self.chunks.iter_mut().zip(other.chunks.iter()) {
531            for (a_byte, b_byte) in a_chunk.iter_mut().zip(b_chunk.iter()) {
532                *a_byte = op(*a_byte, *b_byte);
533            }
534        }
535        // Clear trailing bits to maintain invariant
536        self.clear_trailing_bits();
537    }
538
539    /// Performs a bitwise AND with another BitMap.
540    ///
541    /// # Panics
542    ///
543    /// Panics if the lengths don't match.
544    pub fn and(&mut self, other: &Self) {
545        self.binary_op(other, |a, b| a & b);
546    }
547
548    /// Performs a bitwise OR with another BitMap.
549    ///
550    /// # Panics
551    ///
552    /// Panics if the lengths don't match.
553    pub fn or(&mut self, other: &Self) {
554        self.binary_op(other, |a, b| a | b);
555    }
556
557    /// Performs a bitwise XOR with another BitMap.
558    ///
559    /// # Panics
560    ///
561    /// Panics if the lengths don't match.
562    pub fn xor(&mut self, other: &Self) {
563        self.binary_op(other, |a, b| a ^ b);
564    }
565
566    /* Assertions */
567
568    /// Asserts that the bit is within bounds.
569    #[inline(always)]
570    fn assert_bit(&self, bit: u64) {
571        assert!(
572            bit < self.len(),
573            "bit {} out of bounds (len: {})",
574            bit,
575            self.len()
576        );
577    }
578
579    /// Asserts that the lengths of two [BitMap]s match.
580    #[inline(always)]
581    fn assert_eq_len(&self, other: &Self) {
582        assert_eq!(
583            self.len(),
584            other.len(),
585            "BitMap lengths don't match: {} vs {}",
586            self.len(),
587            other.len()
588        );
589    }
590
591    /// Check if all the bits in a given range are 0.
592    ///
593    /// Returns `true` if every index in the range is unset (i.e.
594    /// [`Self::get`] returns `false`). Returns `true` if the range
595    /// is empty.
596    ///
597    /// # Panics
598    ///
599    /// Panics if `range.end` exceeds the length of the bitmap.
600    ///
601    /// # Examples
602    ///
603    /// ```
604    /// use commonware_utils::bitmap::BitMap;
605    ///
606    /// let mut bitmap = BitMap::<8>::zeroes(128);
607    /// assert!(bitmap.is_unset(0..128));
608    ///
609    /// bitmap.set(64, true);
610    /// assert!(bitmap.is_unset(0..64));
611    /// assert!(!bitmap.is_unset(0..65));
612    /// ```
613    pub fn is_unset(&self, range: Range<u64>) -> bool {
614        assert!(
615            range.end <= self.len(),
616            "range end {} out of bounds (len: {})",
617            range.end,
618            self.len()
619        );
620        if range.start >= range.end {
621            return true;
622        }
623        let start = range.start;
624        let end = range.end;
625
626        // We know this can't underflow, because start < end.
627        //
628        // We now want "end" to represent the last bit we want to consider.
629        let end = end - 1;
630
631        // Get the chunks containing the start and end bits.
632        let first_chunk = Self::to_chunk_index(start);
633        let last_chunk = Self::to_chunk_index(end);
634
635        // All of these chunks require all of their bits to be checked.
636        // If first_chunk == last_chunk, we skip the loop.
637        let zero = [0u8; N];
638        for full_chunk in (first_chunk + 1)..last_chunk {
639            if self.chunks[full_chunk] != zero {
640                return false;
641            }
642        }
643
644        // Check first chunk tail (or whole range if first_chunk == last_chunk).
645        let start_byte = Self::chunk_byte_offset(start);
646        let end_byte = Self::chunk_byte_offset(end);
647        let start_mask = (0xFFu16 << ((start & 0b111) as u32)) as u8;
648        let end_mask = (0xFFu16 >> (7 - ((end & 0b111) as u32))) as u8;
649        let first = &self.chunks[first_chunk];
650        let first_end_byte = if first_chunk == last_chunk {
651            end_byte
652        } else {
653            N - 1
654        };
655        for (i, &byte) in first
656            .iter()
657            .enumerate()
658            .take(first_end_byte + 1)
659            .skip(start_byte)
660        {
661            let mut mask = 0xFFu8;
662            if i == start_byte {
663                mask &= start_mask;
664            }
665            if first_chunk == last_chunk && i == end_byte {
666                mask &= end_mask;
667            }
668            if (byte & mask) != 0 {
669                return false;
670            }
671        }
672        if first_chunk == last_chunk {
673            return true;
674        }
675
676        // Check last chunk head.
677        let last = &self.chunks[last_chunk];
678        for (i, &byte) in last.iter().enumerate().take(end_byte + 1) {
679            let mask = if i == end_byte { end_mask } else { 0xFF };
680            if (byte & mask) != 0 {
681                return false;
682            }
683        }
684
685        true
686    }
687}
688
689impl<const N: usize> Default for BitMap<N> {
690    fn default() -> Self {
691        Self::new()
692    }
693}
694
695impl<T: AsRef<[bool]>, const N: usize> From<T> for BitMap<N> {
696    fn from(t: T) -> Self {
697        let bools = t.as_ref();
698        let mut bv = Self::with_capacity(bools.len() as u64);
699        for &b in bools {
700            bv.push(b);
701        }
702        bv
703    }
704}
705
706impl<const N: usize> From<BitMap<N>> for Vec<bool> {
707    fn from(bv: BitMap<N>) -> Self {
708        bv.iter().collect()
709    }
710}
711
712impl<const N: usize> fmt::Debug for BitMap<N> {
713    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
714        // For very large BitMaps, only show a preview
715        const MAX_DISPLAY: u64 = 64;
716        const HALF_DISPLAY: u64 = MAX_DISPLAY / 2;
717
718        // Closure for writing a bit
719        let write_bit = |formatter: &mut Formatter<'_>, bit: u64| -> core::fmt::Result {
720            formatter.write_char(if self.get(bit) { '1' } else { '0' })
721        };
722
723        f.write_str("BitMap[")?;
724        let len = self.len();
725        if len <= MAX_DISPLAY {
726            // Show all bits
727            for i in 0..len {
728                write_bit(f, i)?;
729            }
730        } else {
731            // Show first and last bits with ellipsis
732            for i in 0..HALF_DISPLAY {
733                write_bit(f, i)?;
734            }
735
736            f.write_str("...")?;
737
738            for i in (len - HALF_DISPLAY)..len {
739                write_bit(f, i)?;
740            }
741        }
742        f.write_str("]")
743    }
744}
745
746impl<const N: usize> Index<u64> for BitMap<N> {
747    type Output = bool;
748
749    /// Allows accessing bits using the `[]` operator.
750    ///
751    /// Panics if out of bounds.
752    #[inline]
753    fn index(&self, bit: u64) -> &Self::Output {
754        self.assert_bit(bit);
755        let value = self.get(bit);
756        if value {
757            &true
758        } else {
759            &false
760        }
761    }
762}
763
764impl<const N: usize> BitAnd for &BitMap<N> {
765    type Output = BitMap<N>;
766
767    fn bitand(self, rhs: Self) -> Self::Output {
768        self.assert_eq_len(rhs);
769        let mut result = self.clone();
770        result.and(rhs);
771        result
772    }
773}
774
775impl<const N: usize> BitOr for &BitMap<N> {
776    type Output = BitMap<N>;
777
778    fn bitor(self, rhs: Self) -> Self::Output {
779        self.assert_eq_len(rhs);
780        let mut result = self.clone();
781        result.or(rhs);
782        result
783    }
784}
785
786impl<const N: usize> BitXor for &BitMap<N> {
787    type Output = BitMap<N>;
788
789    fn bitxor(self, rhs: Self) -> Self::Output {
790        self.assert_eq_len(rhs);
791        let mut result = self.clone();
792        result.xor(rhs);
793        result
794    }
795}
796
797impl<const N: usize> Write for BitMap<N> {
798    fn write(&self, buf: &mut impl BufMut) {
799        // Prefix with the number of bits
800        self.len().write(buf);
801
802        // Write all chunks
803        for chunk in &self.chunks {
804            for &byte in chunk {
805                byte.write(buf);
806            }
807        }
808    }
809}
810
811impl<const N: usize> Read for BitMap<N> {
812    type Cfg = u64; // Max bitmap length
813
814    fn read_cfg(buf: &mut impl Buf, max_len: &Self::Cfg) -> Result<Self, CodecError> {
815        // Parse length in bits
816        let len = u64::read(buf)?;
817        if len > *max_len {
818            return Err(CodecError::InvalidLength(len as usize));
819        }
820
821        // Calculate how many chunks we need to read
822        let num_chunks = len.div_ceil(Self::CHUNK_SIZE_BITS) as usize;
823
824        // Parse chunks
825        let mut chunks = VecDeque::with_capacity(num_chunks);
826        for _ in 0..num_chunks {
827            at_least(buf, N)?;
828            let mut chunk = [0u8; N];
829            buf.copy_to_slice(&mut chunk);
830            chunks.push_back(chunk);
831        }
832
833        let mut result = Self { chunks, len };
834
835        // Verify trailing bits are zero (maintain invariant)
836        if result.clear_trailing_bits() {
837            return Err(CodecError::Invalid(
838                "BitMap",
839                "Invalid trailing bits in encoded data",
840            ));
841        }
842
843        Ok(result)
844    }
845}
846
847impl<const N: usize> EncodeSize for BitMap<N> {
848    fn encode_size(&self) -> usize {
849        // Size of length prefix + all chunks
850        self.len().encode_size() + (self.chunks.len() * N)
851    }
852}
853
854/// Iterator over bits in a [BitMap].
855pub struct Iterator<'a, const N: usize> {
856    /// Reference to the BitMap being iterated over
857    bitmap: &'a BitMap<N>,
858
859    /// Current index in the BitMap
860    pos: u64,
861}
862
863impl<const N: usize> iter::Iterator for Iterator<'_, N> {
864    type Item = bool;
865
866    fn next(&mut self) -> Option<Self::Item> {
867        if self.pos >= self.bitmap.len() {
868            return None;
869        }
870
871        let bit = self.bitmap.get(self.pos);
872        self.pos += 1;
873        Some(bit)
874    }
875
876    fn size_hint(&self) -> (usize, Option<usize>) {
877        let remaining = self.bitmap.len().saturating_sub(self.pos);
878        let capped = remaining.min(usize::MAX as u64) as usize;
879        (capped, Some(capped))
880    }
881}
882
883impl<const N: usize> ExactSizeIterator for Iterator<'_, N> {}
884
885#[cfg(feature = "arbitrary")]
886impl<const N: usize> arbitrary::Arbitrary<'_> for BitMap<N> {
887    fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
888        let size = u.int_in_range(0..=1024)?;
889        let mut bits = Self::with_capacity(size);
890        for _ in 0..size {
891            bits.push(u.arbitrary::<bool>()?);
892        }
893        Ok(bits)
894    }
895}
896
897#[cfg(test)]
898mod tests {
899    use super::*;
900    use crate::hex;
901    use bytes::BytesMut;
902    use commonware_codec::{Decode, Encode};
903
904    #[test]
905    fn test_constructors() {
906        // Test new()
907        let bv: BitMap<4> = BitMap::new();
908        assert_eq!(bv.len(), 0);
909        assert!(bv.is_empty());
910
911        // Test default()
912        let bv: BitMap<4> = Default::default();
913        assert_eq!(bv.len(), 0);
914        assert!(bv.is_empty());
915
916        // Test with_capacity()
917        let bv: BitMap<4> = BitMap::with_capacity(0);
918        assert_eq!(bv.len(), 0);
919        assert!(bv.is_empty());
920
921        let bv: BitMap<4> = BitMap::with_capacity(10);
922        assert_eq!(bv.len(), 0);
923        assert!(bv.is_empty());
924    }
925
926    #[test]
927    fn test_zeroes() {
928        let bv: BitMap<1> = BitMap::zeroes(0);
929        assert_eq!(bv.len(), 0);
930        assert!(bv.is_empty());
931        assert_eq!(bv.count_ones(), 0);
932        assert_eq!(bv.count_zeros(), 0);
933
934        let bv: BitMap<1> = BitMap::zeroes(1);
935        assert_eq!(bv.len(), 1);
936        assert!(!bv.is_empty());
937        assert_eq!(bv.len(), 1);
938        assert!(!bv.get(0));
939        assert_eq!(bv.count_ones(), 0);
940        assert_eq!(bv.count_zeros(), 1);
941
942        let bv: BitMap<1> = BitMap::zeroes(10);
943        assert_eq!(bv.len(), 10);
944        assert!(!bv.is_empty());
945        assert_eq!(bv.len(), 10);
946        for i in 0..10 {
947            assert!(!bv.get(i as u64));
948        }
949        assert_eq!(bv.count_ones(), 0);
950        assert_eq!(bv.count_zeros(), 10);
951    }
952
953    #[test]
954    fn test_ones() {
955        let bv: BitMap<1> = BitMap::ones(0);
956        assert_eq!(bv.len(), 0);
957        assert!(bv.is_empty());
958        assert_eq!(bv.count_ones(), 0);
959        assert_eq!(bv.count_zeros(), 0);
960
961        let bv: BitMap<1> = BitMap::ones(1);
962        assert_eq!(bv.len(), 1);
963        assert!(!bv.is_empty());
964        assert_eq!(bv.len(), 1);
965        assert!(bv.get(0));
966        assert_eq!(bv.count_ones(), 1);
967        assert_eq!(bv.count_zeros(), 0);
968
969        let bv: BitMap<1> = BitMap::ones(10);
970        assert_eq!(bv.len(), 10);
971        assert!(!bv.is_empty());
972        assert_eq!(bv.len(), 10);
973        for i in 0..10 {
974            assert!(bv.get(i as u64));
975        }
976        assert_eq!(bv.count_ones(), 10);
977        assert_eq!(bv.count_zeros(), 0);
978    }
979
980    #[test]
981    fn test_invariant_trailing_bits_are_zero() {
982        // Helper function to check the invariant
983        fn check_trailing_bits_zero<const N: usize>(bitmap: &BitMap<N>) {
984            let (last_chunk, next_bit) = bitmap.last_chunk();
985
986            // Check that all bits >= next_bit in the last chunk are 0
987            for bit_idx in next_bit..((N * 8) as u64) {
988                let byte_idx = (bit_idx / 8) as usize;
989                let bit_in_byte = bit_idx % 8;
990                let mask = 1u8 << bit_in_byte;
991                assert_eq!(last_chunk[byte_idx] & mask, 0);
992            }
993        }
994
995        // Test ones() constructor
996        let bv: BitMap<4> = BitMap::ones(15);
997        check_trailing_bits_zero(&bv);
998
999        let bv: BitMap<4> = BitMap::ones(33);
1000        check_trailing_bits_zero(&bv);
1001
1002        // Test after push operations
1003        let mut bv: BitMap<4> = BitMap::new();
1004        for i in 0..37 {
1005            bv.push(i % 2 == 0);
1006            check_trailing_bits_zero(&bv);
1007        }
1008
1009        // Test after pop operations
1010        let mut bv: BitMap<4> = BitMap::ones(40);
1011        check_trailing_bits_zero(&bv);
1012        for _ in 0..15 {
1013            bv.pop();
1014            check_trailing_bits_zero(&bv);
1015        }
1016
1017        // Test after flip_all
1018        let mut bv: BitMap<4> = BitMap::ones(25);
1019        bv.flip_all();
1020        check_trailing_bits_zero(&bv);
1021
1022        // Test after binary operations
1023        let bv1: BitMap<4> = BitMap::ones(20);
1024        let bv2: BitMap<4> = BitMap::zeroes(20);
1025
1026        let mut bv_and = bv1.clone();
1027        bv_and.and(&bv2);
1028        check_trailing_bits_zero(&bv_and);
1029
1030        let mut bv_or = bv1.clone();
1031        bv_or.or(&bv2);
1032        check_trailing_bits_zero(&bv_or);
1033
1034        let mut bv_xor = bv1;
1035        bv_xor.xor(&bv2);
1036        check_trailing_bits_zero(&bv_xor);
1037
1038        // Test after deserialization
1039        let original: BitMap<4> = BitMap::ones(27);
1040        let encoded = original.encode();
1041        let decoded: BitMap<4> =
1042            BitMap::decode_cfg(&mut encoded.as_ref(), &(usize::MAX as u64)).unwrap();
1043        check_trailing_bits_zero(&decoded);
1044
1045        // Test clear_trailing_bits return value
1046        let mut bv_clean: BitMap<4> = BitMap::ones(20);
1047        // Should return false since ones() already clears trailing bits
1048        assert!(!bv_clean.clear_trailing_bits());
1049
1050        // Create a bitmap with invalid trailing bits by manually setting them
1051        let mut bv_dirty: BitMap<4> = BitMap::ones(20);
1052        // Manually corrupt the last chunk to have trailing bits set
1053        let last_chunk = bv_dirty.chunks.back_mut().unwrap();
1054        last_chunk[3] |= 0xF0; // Set some high bits in the last byte
1055                               // Should return true since we had invalid trailing bits
1056        assert!(bv_dirty.clear_trailing_bits());
1057        // After clearing, should return false
1058        assert!(!bv_dirty.clear_trailing_bits());
1059        check_trailing_bits_zero(&bv_dirty);
1060    }
1061
1062    #[test]
1063    fn test_get_set() {
1064        let mut bv: BitMap<4> = BitMap::new();
1065
1066        // Test initial state
1067        assert_eq!(bv.len(), 0);
1068        assert!(bv.is_empty());
1069
1070        // Test push
1071        bv.push(true);
1072        bv.push(false);
1073        bv.push(true);
1074        assert_eq!(bv.len(), 3);
1075        assert!(!bv.is_empty());
1076
1077        // Test get
1078        assert!(bv.get(0));
1079        assert!(!bv.get(1));
1080        assert!(bv.get(2));
1081
1082        bv.set(1, true);
1083        assert!(bv.get(1));
1084        bv.set(2, false);
1085        assert!(!bv.get(2));
1086
1087        // Test flip
1088        bv.flip(0); // true -> false
1089        assert!(!bv.get(0));
1090        bv.flip(0); // false -> true
1091        assert!(bv.get(0));
1092    }
1093
1094    #[test]
1095    fn test_chunk_operations() {
1096        let mut bv: BitMap<4> = BitMap::new();
1097        let test_chunk = hex!("0xABCDEF12");
1098
1099        // Test push_chunk
1100        bv.push_chunk(&test_chunk);
1101        assert_eq!(bv.len(), 32); // 4 bytes * 8 bits
1102
1103        // Test get_chunk
1104        let chunk = bv.get_chunk(0);
1105        assert_eq!(chunk, &test_chunk);
1106
1107        // Test get_chunk_containing
1108        let chunk = bv.get_chunk_containing(0);
1109        assert_eq!(chunk, &test_chunk);
1110
1111        // Test last_chunk
1112        let (last_chunk, next_bit) = bv.last_chunk();
1113        assert_eq!(next_bit, BitMap::<4>::CHUNK_SIZE_BITS); // Should be at chunk boundary
1114        assert_eq!(last_chunk, &test_chunk); // The chunk we just pushed
1115    }
1116
1117    #[test]
1118    fn test_pop() {
1119        let mut bv: BitMap<3> = BitMap::new();
1120        bv.push(true);
1121        assert!(bv.pop());
1122        assert_eq!(bv.len(), 0);
1123
1124        bv.push(false);
1125        assert!(!bv.pop());
1126        assert_eq!(bv.len(), 0);
1127
1128        bv.push(true);
1129        bv.push(false);
1130        bv.push(true);
1131        assert!(bv.pop());
1132        assert_eq!(bv.len(), 2);
1133        assert!(!bv.pop());
1134        assert_eq!(bv.len(), 1);
1135        assert!(bv.pop());
1136        assert_eq!(bv.len(), 0);
1137
1138        for i in 0..100 {
1139            bv.push(i % 2 == 0);
1140        }
1141        assert_eq!(bv.len(), 100);
1142        for i in (0..100).rev() {
1143            assert_eq!(bv.pop(), i % 2 == 0);
1144        }
1145        assert_eq!(bv.len(), 0);
1146        assert!(bv.is_empty());
1147    }
1148
1149    #[test]
1150    fn test_pop_chunk() {
1151        let mut bv: BitMap<3> = BitMap::new();
1152        const CHUNK_SIZE: u64 = BitMap::<3>::CHUNK_SIZE_BITS;
1153
1154        // Test 1: Pop a single chunk and verify it returns the correct data
1155        let chunk1 = hex!("0xAABBCC");
1156        bv.push_chunk(&chunk1);
1157        assert_eq!(bv.len(), CHUNK_SIZE);
1158        let popped = bv.pop_chunk();
1159        assert_eq!(popped, chunk1);
1160        assert_eq!(bv.len(), 0);
1161        assert!(bv.is_empty());
1162
1163        // Test 2: Pop multiple chunks in reverse order
1164        let chunk2 = hex!("0x112233");
1165        let chunk3 = hex!("0x445566");
1166        let chunk4 = hex!("0x778899");
1167
1168        bv.push_chunk(&chunk2);
1169        bv.push_chunk(&chunk3);
1170        bv.push_chunk(&chunk4);
1171        assert_eq!(bv.len(), CHUNK_SIZE * 3);
1172
1173        assert_eq!(bv.pop_chunk(), chunk4);
1174        assert_eq!(bv.len(), CHUNK_SIZE * 2);
1175
1176        assert_eq!(bv.pop_chunk(), chunk3);
1177        assert_eq!(bv.len(), CHUNK_SIZE);
1178
1179        assert_eq!(bv.pop_chunk(), chunk2);
1180        assert_eq!(bv.len(), 0);
1181
1182        // Test 3: Verify data integrity when popping chunks
1183        let first_chunk = hex!("0xAABBCC");
1184        let second_chunk = hex!("0x112233");
1185        bv.push_chunk(&first_chunk);
1186        bv.push_chunk(&second_chunk);
1187
1188        // Pop the second chunk, verify it and that first chunk is intact
1189        assert_eq!(bv.pop_chunk(), second_chunk);
1190        assert_eq!(bv.len(), CHUNK_SIZE);
1191
1192        for i in 0..CHUNK_SIZE {
1193            let byte_idx = (i / 8) as usize;
1194            let bit_idx = i % 8;
1195            let expected = (first_chunk[byte_idx] >> bit_idx) & 1 == 1;
1196            assert_eq!(bv.get(i), expected);
1197        }
1198
1199        assert_eq!(bv.pop_chunk(), first_chunk);
1200        assert_eq!(bv.len(), 0);
1201    }
1202
1203    #[test]
1204    #[should_panic(expected = "cannot pop chunk when not chunk aligned")]
1205    fn test_pop_chunk_not_aligned() {
1206        let mut bv: BitMap<3> = BitMap::new();
1207
1208        // Push a full chunk plus one bit
1209        bv.push_chunk(&[0xFF; 3]);
1210        bv.push(true);
1211
1212        // Should panic because not chunk-aligned
1213        bv.pop_chunk();
1214    }
1215
1216    #[test]
1217    #[should_panic(expected = "cannot pop chunk: bitmap has fewer than CHUNK_SIZE_BITS bits")]
1218    fn test_pop_chunk_insufficient_bits() {
1219        let mut bv: BitMap<3> = BitMap::new();
1220
1221        // Push only a few bits (less than a full chunk)
1222        bv.push(true);
1223        bv.push(false);
1224
1225        // Should panic because we don't have a full chunk to pop
1226        bv.pop_chunk();
1227    }
1228
1229    #[test]
1230    fn test_byte_operations() {
1231        let mut bv: BitMap<4> = BitMap::new();
1232
1233        // Test push_byte
1234        bv.push_byte(0xFF);
1235        assert_eq!(bv.len(), 8);
1236
1237        // All bits in the byte should be set
1238        for i in 0..8 {
1239            assert!(bv.get(i as u64));
1240        }
1241
1242        bv.push_byte(0x00);
1243        assert_eq!(bv.len(), 16);
1244
1245        // All bits in the second byte should be clear
1246        for i in 8..16 {
1247            assert!(!bv.get(i as u64));
1248        }
1249    }
1250
1251    #[test]
1252    fn test_count_operations() {
1253        let mut bv: BitMap<4> = BitMap::new();
1254
1255        // Empty bitmap
1256        assert_eq!(bv.count_ones(), 0);
1257        assert_eq!(bv.count_zeros(), 0);
1258
1259        // Add some bits
1260        bv.push(true);
1261        bv.push(false);
1262        bv.push(true);
1263        bv.push(true);
1264        bv.push(false);
1265
1266        assert_eq!(bv.count_ones(), 3);
1267        assert_eq!(bv.count_zeros(), 2);
1268        assert_eq!(bv.len(), 5);
1269
1270        // Test with full bytes
1271        let mut bv2: BitMap<4> = BitMap::new();
1272        bv2.push_byte(0xFF); // 8 ones
1273        bv2.push_byte(0x00); // 8 zeros
1274        bv2.push_byte(0xAA); // 4 ones, 4 zeros (10101010)
1275
1276        assert_eq!(bv2.count_ones(), 12);
1277        assert_eq!(bv2.count_zeros(), 12);
1278        assert_eq!(bv2.len(), 24);
1279    }
1280
1281    #[test]
1282    fn test_set_all() {
1283        let mut bv: BitMap<1> = BitMap::new();
1284
1285        // Add some bits
1286        bv.push(true);
1287        bv.push(false);
1288        bv.push(true);
1289        bv.push(false);
1290        bv.push(true);
1291        bv.push(false);
1292        bv.push(true);
1293        bv.push(false);
1294        bv.push(true);
1295        bv.push(false);
1296
1297        assert_eq!(bv.len(), 10);
1298        assert_eq!(bv.count_ones(), 5);
1299        assert_eq!(bv.count_zeros(), 5);
1300
1301        // Test set_all(true)
1302        bv.set_all(true);
1303        assert_eq!(bv.len(), 10);
1304        assert_eq!(bv.count_ones(), 10);
1305        assert_eq!(bv.count_zeros(), 0);
1306
1307        // Test set_all(false)
1308        bv.set_all(false);
1309        assert_eq!(bv.len(), 10);
1310        assert_eq!(bv.count_ones(), 0);
1311        assert_eq!(bv.count_zeros(), 10);
1312    }
1313
1314    #[test]
1315    fn test_flip_all() {
1316        let mut bv: BitMap<4> = BitMap::new();
1317
1318        bv.push(true);
1319        bv.push(false);
1320        bv.push(true);
1321        bv.push(false);
1322        bv.push(true);
1323
1324        let original_ones = bv.count_ones();
1325        let original_zeros = bv.count_zeros();
1326        let original_len = bv.len();
1327
1328        bv.flip_all();
1329
1330        // Length should not change
1331        assert_eq!(bv.len(), original_len);
1332
1333        // Ones and zeros should be swapped
1334        assert_eq!(bv.count_ones(), original_zeros);
1335        assert_eq!(bv.count_zeros(), original_ones);
1336
1337        // Check bits
1338        assert!(!bv.get(0));
1339        assert!(bv.get(1));
1340        assert!(!bv.get(2));
1341        assert!(bv.get(3));
1342        assert!(!bv.get(4));
1343    }
1344
1345    #[test]
1346    fn test_bitwise_and() {
1347        let mut bv1: BitMap<4> = BitMap::new();
1348        let mut bv2: BitMap<4> = BitMap::new();
1349
1350        // Create test patterns: 10110 & 11010 = 10010
1351        let pattern1 = [true, false, true, true, false];
1352        let pattern2 = [true, true, false, true, false];
1353        let expected = [true, false, false, true, false];
1354
1355        for &bit in &pattern1 {
1356            bv1.push(bit);
1357        }
1358        for &bit in &pattern2 {
1359            bv2.push(bit);
1360        }
1361
1362        bv1.and(&bv2);
1363
1364        assert_eq!(bv1.len(), 5);
1365        for (i, &expected_bit) in expected.iter().enumerate() {
1366            assert_eq!(bv1.get(i as u64), expected_bit);
1367        }
1368    }
1369
1370    #[test]
1371    fn test_bitwise_or() {
1372        let mut bv1: BitMap<4> = BitMap::new();
1373        let mut bv2: BitMap<4> = BitMap::new();
1374
1375        // Create test patterns: 10110 | 11010 = 11110
1376        let pattern1 = [true, false, true, true, false];
1377        let pattern2 = [true, true, false, true, false];
1378        let expected = [true, true, true, true, false];
1379
1380        for &bit in &pattern1 {
1381            bv1.push(bit);
1382        }
1383        for &bit in &pattern2 {
1384            bv2.push(bit);
1385        }
1386
1387        bv1.or(&bv2);
1388
1389        assert_eq!(bv1.len(), 5);
1390        for (i, &expected_bit) in expected.iter().enumerate() {
1391            assert_eq!(bv1.get(i as u64), expected_bit);
1392        }
1393    }
1394
1395    #[test]
1396    fn test_bitwise_xor() {
1397        let mut bv1: BitMap<4> = BitMap::new();
1398        let mut bv2: BitMap<4> = BitMap::new();
1399
1400        // Create test patterns: 10110 ^ 11010 = 01100
1401        let pattern1 = [true, false, true, true, false];
1402        let pattern2 = [true, true, false, true, false];
1403        let expected = [false, true, true, false, false];
1404
1405        for &bit in &pattern1 {
1406            bv1.push(bit);
1407        }
1408        for &bit in &pattern2 {
1409            bv2.push(bit);
1410        }
1411
1412        bv1.xor(&bv2);
1413
1414        assert_eq!(bv1.len(), 5);
1415        for (i, &expected_bit) in expected.iter().enumerate() {
1416            assert_eq!(bv1.get(i as u64), expected_bit);
1417        }
1418    }
1419
1420    #[test]
1421    fn test_multi_chunk_operations() {
1422        let mut bv1: BitMap<4> = BitMap::new();
1423        let mut bv2: BitMap<4> = BitMap::new();
1424
1425        // Fill multiple chunks
1426        let chunk1 = hex!("0xAABBCCDD"); // 10101010 10111011 11001100 11011101
1427        let chunk2 = hex!("0x55667788"); // 01010101 01100110 01110111 10001000
1428
1429        bv1.push_chunk(&chunk1);
1430        bv1.push_chunk(&chunk1);
1431        bv2.push_chunk(&chunk2);
1432        bv2.push_chunk(&chunk2);
1433
1434        assert_eq!(bv1.len(), 64);
1435        assert_eq!(bv2.len(), 64);
1436
1437        // Test AND operation
1438        let mut bv_and = bv1.clone();
1439        bv_and.and(&bv2);
1440
1441        // Test OR operation
1442        let mut bv_or = bv1.clone();
1443        bv_or.or(&bv2);
1444
1445        // Test XOR operation
1446        let mut bv_xor = bv1.clone();
1447        bv_xor.xor(&bv2);
1448
1449        // Verify results make sense
1450        assert_eq!(bv_and.len(), 64);
1451        assert_eq!(bv_or.len(), 64);
1452        assert_eq!(bv_xor.len(), 64);
1453
1454        // AND should have fewer or equal ones than either operand
1455        assert!(bv_and.count_ones() <= bv1.count_ones());
1456        assert!(bv_and.count_ones() <= bv2.count_ones());
1457
1458        // OR should have more or equal ones than either operand
1459        assert!(bv_or.count_ones() >= bv1.count_ones());
1460        assert!(bv_or.count_ones() >= bv2.count_ones());
1461    }
1462
1463    #[test]
1464    fn test_partial_chunk_operations() {
1465        let mut bv1: BitMap<4> = BitMap::new();
1466        let mut bv2: BitMap<4> = BitMap::new();
1467
1468        // Add partial chunks (not aligned to chunk boundaries)
1469        for i in 0..35 {
1470            // 35 bits = 4 bytes + 3 bits
1471            bv1.push(i % 2 == 0);
1472            bv2.push(i % 3 == 0);
1473        }
1474
1475        assert_eq!(bv1.len(), 35);
1476        assert_eq!(bv2.len(), 35);
1477
1478        // Test operations with partial chunks
1479        let mut bv_and = bv1.clone();
1480        bv_and.and(&bv2);
1481
1482        let mut bv_or = bv1.clone();
1483        bv_or.or(&bv2);
1484
1485        let mut bv_xor = bv1.clone();
1486        bv_xor.xor(&bv2);
1487
1488        // All should maintain the same length
1489        assert_eq!(bv_and.len(), 35);
1490        assert_eq!(bv_or.len(), 35);
1491        assert_eq!(bv_xor.len(), 35);
1492
1493        // Test flip_all with partial chunk
1494        let mut bv_inv = bv1.clone();
1495        let original_ones = bv_inv.count_ones();
1496        let original_zeros = bv_inv.count_zeros();
1497        bv_inv.flip_all();
1498        assert_eq!(bv_inv.count_ones(), original_zeros);
1499        assert_eq!(bv_inv.count_zeros(), original_ones);
1500    }
1501
1502    #[test]
1503    #[should_panic(expected = "bit 1 out of bounds (len: 1)")]
1504    fn test_flip_out_of_bounds() {
1505        let mut bv: BitMap<4> = BitMap::new();
1506        bv.push(true);
1507        bv.flip(1); // Only bit 0 exists
1508    }
1509
1510    #[test]
1511    #[should_panic(expected = "BitMap lengths don't match: 2 vs 1")]
1512    fn test_and_length_mismatch() {
1513        let mut bv1: BitMap<4> = BitMap::new();
1514        let mut bv2: BitMap<4> = BitMap::new();
1515
1516        bv1.push(true);
1517        bv1.push(false);
1518        bv2.push(true); // Different length
1519
1520        bv1.and(&bv2);
1521    }
1522
1523    #[test]
1524    #[should_panic(expected = "BitMap lengths don't match: 1 vs 2")]
1525    fn test_or_length_mismatch() {
1526        let mut bv1: BitMap<4> = BitMap::new();
1527        let mut bv2: BitMap<4> = BitMap::new();
1528
1529        bv1.push(true);
1530        bv2.push(true);
1531        bv2.push(false); // Different length
1532
1533        bv1.or(&bv2);
1534    }
1535
1536    #[test]
1537    #[should_panic(expected = "BitMap lengths don't match: 3 vs 2")]
1538    fn test_xor_length_mismatch() {
1539        let mut bv1: BitMap<4> = BitMap::new();
1540        let mut bv2: BitMap<4> = BitMap::new();
1541
1542        bv1.push(true);
1543        bv1.push(false);
1544        bv1.push(true);
1545        bv2.push(true);
1546        bv2.push(false); // Different length
1547
1548        bv1.xor(&bv2);
1549    }
1550
1551    #[test]
1552    fn test_equality() {
1553        // Test empty bitmaps
1554        assert_eq!(BitMap::<4>::new(), BitMap::<4>::new());
1555        assert_eq!(BitMap::<8>::new(), BitMap::<8>::new());
1556
1557        // Test non-empty bitmaps from constructors
1558        let pattern = [true, false, true, true, false, false, true, false, true];
1559        let bv4: BitMap<4> = pattern.as_ref().into();
1560        assert_eq!(bv4, BitMap::<4>::from(pattern.as_ref()));
1561        let bv8: BitMap<8> = pattern.as_ref().into();
1562        assert_eq!(bv8, BitMap::<8>::from(pattern.as_ref()));
1563
1564        // Test non-empty bitmaps from push operations
1565        let mut bv1: BitMap<4> = BitMap::new();
1566        let mut bv2: BitMap<4> = BitMap::new();
1567        for i in 0..33 {
1568            let bit = i % 3 == 0;
1569            bv1.push(bit);
1570            bv2.push(bit);
1571        }
1572        assert_eq!(bv1, bv2);
1573
1574        // Test inequality: different lengths
1575        bv1.push(true);
1576        assert_ne!(bv1, bv2);
1577        bv1.pop(); // Restore equality
1578        assert_eq!(bv1, bv2);
1579
1580        // Test inequality: different content
1581        bv1.flip(15);
1582        assert_ne!(bv1, bv2);
1583        bv1.flip(15); // Restore equality
1584        assert_eq!(bv1, bv2);
1585
1586        // Test equality after operations
1587        let mut bv_ops1 = BitMap::<16>::ones(25);
1588        let mut bv_ops2 = BitMap::<16>::ones(25);
1589        bv_ops1.flip_all();
1590        bv_ops2.flip_all();
1591        assert_eq!(bv_ops1, bv_ops2);
1592
1593        let mask_bits: Vec<bool> = (0..33).map(|i| i % 3 == 0).collect();
1594        let mask = BitMap::<4>::from(mask_bits);
1595        bv1.and(&mask);
1596        bv2.and(&mask);
1597        assert_eq!(bv1, bv2);
1598    }
1599
1600    #[test]
1601    fn test_different_chunk_sizes() {
1602        // Test with different chunk sizes
1603        let mut bv8: BitMap<8> = BitMap::new();
1604        let mut bv16: BitMap<16> = BitMap::new();
1605        let mut bv32: BitMap<32> = BitMap::new();
1606
1607        // Test chunk operations first (must be chunk-aligned)
1608        let chunk8 = [0xFF; 8];
1609        let chunk16 = [0xAA; 16];
1610        let chunk32 = [0x55; 32];
1611
1612        bv8.push_chunk(&chunk8);
1613        bv16.push_chunk(&chunk16);
1614        bv32.push_chunk(&chunk32);
1615
1616        // Test basic operations work with different sizes
1617        bv8.push(true);
1618        bv8.push(false);
1619        assert_eq!(bv8.len(), 64 + 2);
1620        assert_eq!(bv8.count_ones(), 64 + 1); // chunk8 is all 0xFF + 1 true bit
1621        assert_eq!(bv8.count_zeros(), 1);
1622
1623        bv16.push(true);
1624        bv16.push(false);
1625        assert_eq!(bv16.len(), 128 + 2);
1626        assert_eq!(bv16.count_ones(), 64 + 1); // chunk16 is 0xAA pattern + 1 true bit
1627        assert_eq!(bv16.count_zeros(), 64 + 1);
1628
1629        bv32.push(true);
1630        bv32.push(false);
1631        assert_eq!(bv32.len(), 256 + 2);
1632        assert_eq!(bv32.count_ones(), 128 + 1); // chunk32 is 0x55 pattern + 1 true bit
1633        assert_eq!(bv32.count_zeros(), 128 + 1);
1634    }
1635
1636    #[test]
1637    fn test_iterator() {
1638        // Test empty iterator
1639        let bv: BitMap<4> = BitMap::new();
1640        let mut iter = bv.iter();
1641        assert_eq!(iter.next(), None);
1642        assert_eq!(iter.size_hint(), (0, Some(0)));
1643
1644        // Test iterator with some bits
1645        let pattern = [true, false, true, false, true];
1646        let bv: BitMap<4> = pattern.as_ref().into();
1647
1648        // Collect all bits via iterator
1649        let collected: Vec<bool> = bv.iter().collect();
1650        assert_eq!(collected, pattern);
1651
1652        // Test size_hint
1653        let mut iter = bv.iter();
1654        assert_eq!(iter.size_hint(), (5, Some(5)));
1655
1656        // Consume one element and check size_hint again
1657        assert_eq!(iter.next(), Some(true));
1658        assert_eq!(iter.size_hint(), (4, Some(4)));
1659
1660        // Test ExactSizeIterator
1661        let iter = bv.iter();
1662        assert_eq!(iter.len(), 5);
1663
1664        // Test iterator with larger bitmap
1665        let mut large_bv: BitMap<8> = BitMap::new();
1666        for i in 0..100 {
1667            large_bv.push(i % 3 == 0);
1668        }
1669
1670        let collected: Vec<bool> = large_bv.iter().collect();
1671        assert_eq!(collected.len(), 100);
1672        for (i, &bit) in collected.iter().enumerate() {
1673            assert_eq!(bit, i % 3 == 0);
1674        }
1675    }
1676
1677    #[test]
1678    fn test_iterator_edge_cases() {
1679        // Test iterator with single bit
1680        let mut bv: BitMap<4> = BitMap::new();
1681        bv.push(true);
1682
1683        let collected: Vec<bool> = bv.iter().collect();
1684        assert_eq!(collected, vec![true]);
1685
1686        // Test iterator across chunk boundaries
1687        let mut bv: BitMap<4> = BitMap::new();
1688        // Fill exactly one chunk (32 bits)
1689        for i in 0..32 {
1690            bv.push(i % 2 == 0);
1691        }
1692        // Add a few more bits in the next chunk
1693        bv.push(true);
1694        bv.push(false);
1695        bv.push(true);
1696
1697        let collected: Vec<bool> = bv.iter().collect();
1698        assert_eq!(collected.len(), 35);
1699
1700        // Verify the pattern
1701        for (i, &bit) in collected.iter().enumerate().take(32) {
1702            assert_eq!(bit, i % 2 == 0);
1703        }
1704        assert!(collected[32]);
1705        assert!(!collected[33]);
1706        assert!(collected[34]);
1707    }
1708
1709    #[test]
1710    fn test_codec_roundtrip() {
1711        // Test empty bitmap
1712        let original: BitMap<4> = BitMap::new();
1713        let encoded = original.encode();
1714        let decoded = BitMap::decode_cfg(&mut encoded.as_ref(), &(usize::MAX as u64)).unwrap();
1715        assert_eq!(original, decoded);
1716
1717        // Test small bitmap
1718        let pattern = [true, false, true, false, true];
1719        let original: BitMap<4> = pattern.as_ref().into();
1720        let encoded = original.encode();
1721        let decoded = BitMap::decode_cfg(&mut encoded.as_ref(), &(usize::MAX as u64)).unwrap();
1722        assert_eq!(original, decoded);
1723
1724        // Verify the decoded bitmap has the same bits
1725        for (i, &expected) in pattern.iter().enumerate() {
1726            assert_eq!(decoded.get(i as u64), expected);
1727        }
1728
1729        // Test larger bitmap across multiple chunks
1730        let mut large_original: BitMap<8> = BitMap::new();
1731        for i in 0..100 {
1732            large_original.push(i % 7 == 0);
1733        }
1734
1735        let encoded = large_original.encode();
1736        let decoded = BitMap::decode_cfg(&mut encoded.as_ref(), &(usize::MAX as u64)).unwrap();
1737        assert_eq!(large_original, decoded);
1738
1739        // Verify all bits match
1740        assert_eq!(decoded.len(), 100);
1741        for i in 0..100 {
1742            assert_eq!(decoded.get(i as u64), i % 7 == 0);
1743        }
1744    }
1745
1746    #[test]
1747    fn test_codec_different_chunk_sizes() {
1748        let pattern = [true, false, true, true, false, false, true];
1749
1750        // Test with different chunk sizes
1751        let bv4: BitMap<4> = pattern.as_ref().into();
1752        let bv8: BitMap<8> = pattern.as_ref().into();
1753        let bv16: BitMap<16> = pattern.as_ref().into();
1754
1755        // Encode and decode each
1756        let encoded4 = bv4.encode();
1757        let decoded4 = BitMap::decode_cfg(&mut encoded4.as_ref(), &(usize::MAX as u64)).unwrap();
1758        assert_eq!(bv4, decoded4);
1759
1760        let encoded8 = bv8.encode();
1761        let decoded8 = BitMap::decode_cfg(&mut encoded8.as_ref(), &(usize::MAX as u64)).unwrap();
1762        assert_eq!(bv8, decoded8);
1763
1764        let encoded16 = bv16.encode();
1765        let decoded16 = BitMap::decode_cfg(&mut encoded16.as_ref(), &(usize::MAX as u64)).unwrap();
1766        assert_eq!(bv16, decoded16);
1767
1768        // All should have the same logical content
1769        for (i, &expected) in pattern.iter().enumerate() {
1770            let i = i as u64;
1771            assert_eq!(decoded4.get(i), expected);
1772            assert_eq!(decoded8.get(i), expected);
1773            assert_eq!(decoded16.get(i), expected);
1774        }
1775    }
1776
1777    #[test]
1778    fn test_codec_edge_cases() {
1779        // Test bitmap with exactly one chunk filled
1780        let mut bv: BitMap<4> = BitMap::new();
1781        for i in 0..32 {
1782            bv.push(i % 2 == 0);
1783        }
1784
1785        let encoded = bv.encode();
1786        let decoded = BitMap::decode_cfg(&mut encoded.as_ref(), &(usize::MAX as u64)).unwrap();
1787        assert_eq!(bv, decoded);
1788        assert_eq!(decoded.len(), 32);
1789
1790        // Test bitmap with partial chunk
1791        let mut bv2: BitMap<4> = BitMap::new();
1792        for i in 0..35 {
1793            // 32 + 3 bits
1794            bv2.push(i % 3 == 0);
1795        }
1796
1797        let encoded2 = bv2.encode();
1798        let decoded2 = BitMap::decode_cfg(&mut encoded2.as_ref(), &(usize::MAX as u64)).unwrap();
1799        assert_eq!(bv2, decoded2);
1800        assert_eq!(decoded2.len(), 35);
1801    }
1802
1803    #[test]
1804    fn test_encode_size() {
1805        // Test encode size calculation
1806        let bv: BitMap<4> = BitMap::new();
1807        let encoded = bv.encode();
1808        assert_eq!(bv.encode_size(), encoded.len());
1809
1810        // Test with some data
1811        let pattern = [true, false, true, false, true];
1812        let bv: BitMap<4> = pattern.as_ref().into();
1813        let encoded = bv.encode();
1814        assert_eq!(bv.encode_size(), encoded.len());
1815
1816        // Test with larger data
1817        let mut large_bv: BitMap<8> = BitMap::new();
1818        for i in 0..100 {
1819            large_bv.push(i % 2 == 0);
1820        }
1821        let encoded = large_bv.encode();
1822        assert_eq!(large_bv.encode_size(), encoded.len());
1823    }
1824
1825    #[test]
1826    fn test_codec_empty_chunk_optimization() {
1827        // Test that empty last chunks are not serialized
1828
1829        // Case 1: Empty bitmap (omits the only empty chunk)
1830        let bv_empty: BitMap<4> = BitMap::new();
1831        let encoded_empty = bv_empty.encode();
1832        let decoded_empty: BitMap<4> =
1833            BitMap::decode_cfg(&mut encoded_empty.as_ref(), &(usize::MAX as u64)).unwrap();
1834        assert_eq!(bv_empty, decoded_empty);
1835        assert_eq!(bv_empty.len(), decoded_empty.len());
1836        // Should only encode the length, no chunks
1837        assert_eq!(encoded_empty.len(), bv_empty.len().encode_size());
1838
1839        // Case 2: Bitmap ending exactly at chunk boundary (omits empty last chunk)
1840        let mut bv_exact: BitMap<4> = BitMap::new();
1841        for _ in 0..32 {
1842            bv_exact.push(true);
1843        }
1844        let encoded_exact = bv_exact.encode();
1845        let decoded_exact: BitMap<4> =
1846            BitMap::decode_cfg(&mut encoded_exact.as_ref(), &(usize::MAX as u64)).unwrap();
1847        assert_eq!(bv_exact, decoded_exact);
1848
1849        // Case 3: Bitmap with partial last chunk (includes last chunk)
1850        let mut bv_partial: BitMap<4> = BitMap::new();
1851        for _ in 0..35 {
1852            bv_partial.push(true);
1853        }
1854        let encoded_partial = bv_partial.encode();
1855        let decoded_partial: BitMap<4> =
1856            BitMap::decode_cfg(&mut encoded_partial.as_ref(), &(usize::MAX as u64)).unwrap();
1857        assert_eq!(bv_partial, decoded_partial);
1858        assert_eq!(bv_partial.len(), decoded_partial.len());
1859
1860        // Verify optimization works correctly
1861        assert!(encoded_exact.len() < encoded_partial.len());
1862        assert_eq!(encoded_exact.len(), bv_exact.len().encode_size() + 4); // length + 1 chunk
1863        assert_eq!(encoded_partial.len(), bv_partial.len().encode_size() + 8); // length + 2 chunks
1864    }
1865
1866    #[test]
1867    fn test_codec_error_cases() {
1868        // Test invalid length with range check
1869        let mut buf = BytesMut::new();
1870        100u64.write(&mut buf); // bits length
1871
1872        // 100 bits requires 4 chunks (3 full + partially filled)
1873        for _ in 0..4 {
1874            [0u8; 4].write(&mut buf);
1875        }
1876
1877        // Test with a restricted range that excludes 100
1878        let result = BitMap::<4>::decode_cfg(&mut buf, &99);
1879        assert!(matches!(result, Err(CodecError::InvalidLength(100))));
1880
1881        // Test truncated buffer (not enough chunks)
1882        let mut buf = BytesMut::new();
1883        100u64.write(&mut buf); // bits length requiring 4 chunks (3 full + partially filled)
1884                                // Only write 3 chunks
1885        [0u8; 4].write(&mut buf);
1886        [0u8; 4].write(&mut buf);
1887        [0u8; 4].write(&mut buf);
1888
1889        let result = BitMap::<4>::decode_cfg(&mut buf, &(usize::MAX as u64));
1890        // Should fail when trying to read missing chunks
1891        assert!(result.is_err());
1892
1893        // Test invalid trailing bits
1894
1895        // Create a valid bitmap and encode it
1896        let original: BitMap<4> = BitMap::ones(20);
1897        let mut buf = BytesMut::new();
1898        original.write(&mut buf);
1899
1900        // Manually corrupt the encoded data by setting trailing bits
1901        let corrupted_data = buf.freeze();
1902        let mut corrupted_bytes = corrupted_data.to_vec();
1903
1904        // The last byte should have some trailing bits set to 1
1905        // For 20 bits with 4-byte chunks: 20 bits = 2.5 bytes, so last byte should have 4 valid bits
1906        // Set the high 4 bits of the last byte to 1 (these should be 0)
1907        let last_byte_idx = corrupted_bytes.len() - 1;
1908        corrupted_bytes[last_byte_idx] |= 0xF0;
1909
1910        // Read should fail
1911        let result = BitMap::<4>::read_cfg(&mut corrupted_bytes.as_slice(), &(usize::MAX as u64));
1912        assert!(matches!(
1913            result,
1914            Err(CodecError::Invalid(
1915                "BitMap",
1916                "Invalid trailing bits in encoded data"
1917            ))
1918        ));
1919    }
1920
1921    #[test]
1922    fn test_codec_range_config() {
1923        // Test RangeCfg validation in read_cfg
1924
1925        // Create a bitmap with 100 bits
1926        let mut original: BitMap<4> = BitMap::new();
1927        for i in 0..100 {
1928            original.push(i % 3 == 0);
1929        }
1930
1931        // Write to a buffer
1932        let mut buf = BytesMut::new();
1933        original.write(&mut buf);
1934
1935        // Test with max length < actual size (should fail)
1936        let result = BitMap::<4>::decode_cfg(&mut buf.as_ref(), &50);
1937        assert!(matches!(result, Err(CodecError::InvalidLength(100))));
1938
1939        // Test with max length == actual size (should succeed)
1940        let decoded = BitMap::<4>::decode_cfg(&mut buf.as_ref(), &100).unwrap();
1941        assert_eq!(decoded.len(), 100);
1942        assert_eq!(decoded, original);
1943
1944        // Test with max length > actual size (should succeed)
1945        let decoded = BitMap::<4>::decode_cfg(&mut buf.as_ref(), &101).unwrap();
1946        assert_eq!(decoded.len(), 100);
1947        assert_eq!(decoded, original);
1948
1949        // Test empty bitmap
1950        let empty = BitMap::<4>::new();
1951        let mut buf = BytesMut::new();
1952        empty.write(&mut buf);
1953
1954        // Empty bitmap should work with max length 0
1955        let decoded = BitMap::<4>::decode_cfg(&mut buf.as_ref(), &0).unwrap();
1956        assert_eq!(decoded.len(), 0);
1957        assert!(decoded.is_empty());
1958
1959        // Empty bitmap should work with max length > 0
1960        let decoded = BitMap::<4>::decode_cfg(&mut buf.as_ref(), &1).unwrap();
1961        assert_eq!(decoded.len(), 0);
1962        assert!(decoded.is_empty());
1963    }
1964
1965    #[test]
1966    fn test_from() {
1967        // Test From trait with different input types
1968
1969        // Test with Vec<bool>
1970        let vec_bool = vec![true, false, true, false, true];
1971        let bv: BitMap<4> = vec_bool.into();
1972        assert_eq!(bv.len(), 5);
1973        assert_eq!(bv.count_ones(), 3);
1974        assert_eq!(bv.count_zeros(), 2);
1975        for (i, &expected) in [true, false, true, false, true].iter().enumerate() {
1976            assert_eq!(bv.get(i as u64), expected);
1977        }
1978
1979        // Test with array slice
1980        let array = [false, true, true, false];
1981        let bv: BitMap<4> = (&array).into();
1982        assert_eq!(bv.len(), 4);
1983        assert_eq!(bv.count_ones(), 2);
1984        assert_eq!(bv.count_zeros(), 2);
1985        for (i, &expected) in array.iter().enumerate() {
1986            assert_eq!(bv.get(i as u64), expected);
1987        }
1988
1989        // Test with empty slice
1990        let empty: Vec<bool> = vec![];
1991        let bv: BitMap<4> = empty.into();
1992        assert_eq!(bv.len(), 0);
1993        assert!(bv.is_empty());
1994
1995        // Test with large slice
1996        let large: Vec<bool> = (0..100).map(|i| i % 3 == 0).collect();
1997        let bv: BitMap<8> = large.clone().into();
1998        assert_eq!(bv.len(), 100);
1999        for (i, &expected) in large.iter().enumerate() {
2000            assert_eq!(bv.get(i as u64), expected);
2001        }
2002    }
2003
2004    #[test]
2005    fn test_debug_formatting() {
2006        // Test Debug formatting for different sizes
2007
2008        // Test empty bitmap
2009        let bv: BitMap<4> = BitMap::new();
2010        let debug_str = format!("{bv:?}");
2011        assert_eq!(debug_str, "BitMap[]");
2012
2013        // Test small bitmap (should show all bits)
2014        let bv: BitMap<4> = [true, false, true, false, true].as_ref().into();
2015        let debug_str = format!("{bv:?}");
2016        assert_eq!(debug_str, "BitMap[10101]");
2017
2018        // Test bitmap at the display limit (64 bits)
2019        let pattern: Vec<bool> = (0..64).map(|i| i % 2 == 0).collect();
2020        let bv: BitMap<8> = pattern.into();
2021        let debug_str = format!("{bv:?}");
2022        let expected_pattern = "1010".repeat(16); // 64 bits alternating
2023        assert_eq!(debug_str, format!("BitMap[{expected_pattern}]"));
2024
2025        // Test large bitmap (should show ellipsis)
2026        let large_pattern: Vec<bool> = (0..100).map(|i| i % 2 == 0).collect();
2027        let bv: BitMap<16> = large_pattern.into();
2028        let debug_str = format!("{bv:?}");
2029
2030        // Should show first 32 bits + "..." + last 32 bits
2031        let first_32 = "10".repeat(16); // First 32 bits: 1010...
2032        let last_32 = "10".repeat(16); // Last 32 bits: ...1010
2033        let expected = format!("BitMap[{first_32}...{last_32}]");
2034        assert_eq!(debug_str, expected);
2035
2036        // Test single bit
2037        let bv: BitMap<4> = [true].as_ref().into();
2038        assert_eq!(format!("{bv:?}"), "BitMap[1]");
2039
2040        let bv: BitMap<4> = [false].as_ref().into();
2041        assert_eq!(format!("{bv:?}"), "BitMap[0]");
2042
2043        // Test exactly at boundary (65 bits - should show ellipsis)
2044        let pattern: Vec<bool> = (0..65).map(|i| i == 0 || i == 64).collect(); // First and last bits are true
2045        let bv: BitMap<16> = pattern.into();
2046        let debug_str = format!("{bv:?}");
2047
2048        // Should show first 32 bits (100000...) + "..." + last 32 bits (...000001)
2049        let first_32 = "1".to_string() + &"0".repeat(31);
2050        let last_32 = "0".repeat(31) + "1";
2051        let expected = format!("BitMap[{first_32}...{last_32}]");
2052        assert_eq!(debug_str, expected);
2053    }
2054
2055    #[test]
2056    fn test_from_different_chunk_sizes() {
2057        // Test From trait works with different chunk sizes
2058        let pattern = [true, false, true, true, false, false, true];
2059
2060        let bv4: BitMap<4> = pattern.as_ref().into();
2061        let bv8: BitMap<8> = pattern.as_ref().into();
2062        let bv16: BitMap<16> = pattern.as_ref().into();
2063
2064        // All should have the same content regardless of chunk size
2065        // Test each bitmap separately since they have different types
2066        for bv in [&bv4] {
2067            assert_eq!(bv.len(), 7);
2068            assert_eq!(bv.count_ones(), 4);
2069            assert_eq!(bv.count_zeros(), 3);
2070            for (i, &expected) in pattern.iter().enumerate() {
2071                assert_eq!(bv.get(i as u64), expected);
2072            }
2073        }
2074
2075        assert_eq!(bv8.len(), 7);
2076        assert_eq!(bv8.count_ones(), 4);
2077        assert_eq!(bv8.count_zeros(), 3);
2078        for (i, &expected) in pattern.iter().enumerate() {
2079            assert_eq!(bv8.get(i as u64), expected);
2080        }
2081
2082        assert_eq!(bv16.len(), 7);
2083        assert_eq!(bv16.count_ones(), 4);
2084        assert_eq!(bv16.count_zeros(), 3);
2085        for (i, &expected) in pattern.iter().enumerate() {
2086            assert_eq!(bv16.get(i as u64), expected);
2087        }
2088    }
2089
2090    #[test]
2091    fn test_prune_chunks() {
2092        let mut bv: BitMap<4> = BitMap::new();
2093        bv.push_chunk(&[1, 2, 3, 4]);
2094        bv.push_chunk(&[5, 6, 7, 8]);
2095        bv.push_chunk(&[9, 10, 11, 12]);
2096
2097        assert_eq!(bv.len(), 96);
2098        assert_eq!(bv.get_chunk(0), &[1, 2, 3, 4]);
2099
2100        // Prune first chunk
2101        bv.prune_chunks(1);
2102        assert_eq!(bv.len(), 64);
2103        assert_eq!(bv.get_chunk(0), &[5, 6, 7, 8]);
2104        assert_eq!(bv.get_chunk(1), &[9, 10, 11, 12]);
2105
2106        // Prune another chunk
2107        bv.prune_chunks(1);
2108        assert_eq!(bv.len(), 32);
2109        assert_eq!(bv.get_chunk(0), &[9, 10, 11, 12]);
2110    }
2111
2112    #[test]
2113    #[should_panic(expected = "cannot prune")]
2114    fn test_prune_too_many_chunks() {
2115        let mut bv: BitMap<4> = BitMap::new();
2116        bv.push_chunk(&[1, 2, 3, 4]);
2117        bv.push_chunk(&[5, 6, 7, 8]);
2118        bv.push(true);
2119
2120        // Try to prune 4 chunks when only 3 are available
2121        bv.prune_chunks(4);
2122    }
2123
2124    #[test]
2125    fn test_prune_with_partial_last_chunk() {
2126        let mut bv: BitMap<4> = BitMap::new();
2127        bv.push_chunk(&[1, 2, 3, 4]);
2128        bv.push_chunk(&[5, 6, 7, 8]);
2129        bv.push(true);
2130        bv.push(false);
2131
2132        assert_eq!(bv.len(), 66);
2133
2134        // Can prune first chunk
2135        bv.prune_chunks(1);
2136        assert_eq!(bv.len(), 34);
2137        assert_eq!(bv.get_chunk(0), &[5, 6, 7, 8]);
2138
2139        // Last partial chunk still has the appended bits
2140        assert!(bv.get(32));
2141        assert!(!bv.get(33));
2142    }
2143
2144    #[test]
2145    fn test_prune_all_chunks_resets_next_bit() {
2146        let mut bv: BitMap<4> = BitMap::new();
2147        bv.push_chunk(&[1, 2, 3, 4]);
2148        bv.push_chunk(&[5, 6, 7, 8]);
2149        bv.push(true);
2150        bv.push(false);
2151        bv.push(true);
2152
2153        // Bitmap has 2 full chunks + 3 bits in partial chunk
2154        assert_eq!(bv.len(), 67);
2155
2156        // Prune all chunks (this leaves chunks empty, triggering the reset path)
2157        bv.prune_chunks(3);
2158
2159        // Regression test: len() should be 0, not the old next_bit value (3)
2160        assert_eq!(bv.len(), 0);
2161        assert!(bv.is_empty());
2162
2163        // Bitmap should behave as freshly created
2164        bv.push(true);
2165        assert_eq!(bv.len(), 1);
2166        assert!(bv.get(0));
2167    }
2168
2169    #[test]
2170    fn test_is_chunk_aligned() {
2171        // Empty bitmap is chunk aligned
2172        let bv: BitMap<4> = BitMap::new();
2173        assert!(bv.is_chunk_aligned());
2174
2175        // Test with various chunk sizes
2176        let mut bv4: BitMap<4> = BitMap::new();
2177        assert!(bv4.is_chunk_aligned());
2178
2179        // Add bits one at a time and check alignment
2180        for i in 1..=32 {
2181            bv4.push(i % 2 == 0);
2182            if i == 32 {
2183                assert!(bv4.is_chunk_aligned()); // Exactly one chunk
2184            } else {
2185                assert!(!bv4.is_chunk_aligned()); // Partial chunk
2186            }
2187        }
2188
2189        // Add more bits
2190        for i in 33..=64 {
2191            bv4.push(i % 2 == 0);
2192            if i == 64 {
2193                assert!(bv4.is_chunk_aligned()); // Exactly two chunks
2194            } else {
2195                assert!(!bv4.is_chunk_aligned()); // Partial chunk
2196            }
2197        }
2198
2199        // Test with push_chunk
2200        let mut bv: BitMap<8> = BitMap::new();
2201        assert!(bv.is_chunk_aligned());
2202        bv.push_chunk(&[0xFF; 8]);
2203        assert!(bv.is_chunk_aligned()); // 64 bits = 1 chunk for N=8
2204        bv.push_chunk(&[0xAA; 8]);
2205        assert!(bv.is_chunk_aligned()); // 128 bits = 2 chunks
2206        bv.push(true);
2207        assert!(!bv.is_chunk_aligned()); // 129 bits = partial chunk
2208
2209        // Test with push_byte
2210        let mut bv: BitMap<4> = BitMap::new();
2211        for _ in 0..4 {
2212            bv.push_byte(0xFF);
2213        }
2214        assert!(bv.is_chunk_aligned()); // 32 bits = 1 chunk for N=4
2215
2216        // Test after pop
2217        bv.pop();
2218        assert!(!bv.is_chunk_aligned()); // 31 bits = partial chunk
2219
2220        // Test with zeroes and ones constructors
2221        let bv_zeroes: BitMap<4> = BitMap::zeroes(64);
2222        assert!(bv_zeroes.is_chunk_aligned());
2223
2224        let bv_ones: BitMap<4> = BitMap::ones(96);
2225        assert!(bv_ones.is_chunk_aligned());
2226
2227        let bv_partial: BitMap<4> = BitMap::zeroes(65);
2228        assert!(!bv_partial.is_chunk_aligned());
2229    }
2230
2231    #[test]
2232    fn test_unprune_restores_length() {
2233        let mut prunable: Prunable<4> = Prunable::new_with_pruned_chunks(1).unwrap();
2234        assert_eq!(prunable.len(), Prunable::<4>::CHUNK_SIZE_BITS);
2235        assert_eq!(prunable.pruned_chunks(), 1);
2236        let chunk = [0xDE, 0xAD, 0xBE, 0xEF];
2237
2238        prunable.unprune_chunks(&[chunk]);
2239
2240        assert_eq!(prunable.pruned_chunks(), 0);
2241        assert_eq!(prunable.len(), Prunable::<4>::CHUNK_SIZE_BITS);
2242        assert_eq!(prunable.get_chunk_containing(0), &chunk);
2243    }
2244
2245    mod proptests {
2246        use super::*;
2247        use proptest::prelude::*;
2248
2249        proptest! {
2250            #[test]
2251            fn is_unset_matches_naive(
2252                bits in prop::collection::vec(any::<bool>(), 1..=512usize),
2253                start in 0u64..=512,
2254                end in 0u64..=512,
2255            ) {
2256                let bitmap: BitMap = BitMap::from(bits.as_slice());
2257                let len = bitmap.len();
2258                let start = start.min(len);
2259                let end = end.max(start).min(len);
2260                let range = start..end;
2261
2262                let expected = range.clone().all(|i| !bitmap.get(i));
2263
2264                prop_assert_eq!(bitmap.is_unset(range), expected);
2265            }
2266        }
2267    }
2268
2269    #[test]
2270    fn is_unset_all_zeros() {
2271        let bitmap = BitMap::<8>::zeroes(256);
2272        assert!(bitmap.is_unset(0..256));
2273    }
2274
2275    #[test]
2276    fn is_unset_all_ones() {
2277        let bitmap = BitMap::<8>::ones(256);
2278        assert!(!bitmap.is_unset(0..256));
2279    }
2280
2281    #[test]
2282    fn is_unset_single_bit() {
2283        let mut bitmap = BitMap::<8>::zeroes(64);
2284        bitmap.set(31, true);
2285        assert!(bitmap.is_unset(0..31));
2286        assert!(!bitmap.is_unset(0..32));
2287        assert!(!bitmap.is_unset(31..32));
2288        assert!(bitmap.is_unset(32..64));
2289    }
2290
2291    #[test]
2292    fn is_unset_empty_range() {
2293        let bitmap = BitMap::<8>::ones(64);
2294        assert!(bitmap.is_unset(0..0));
2295        assert!(bitmap.is_unset(32..32));
2296        assert!(bitmap.is_unset(64..64));
2297    }
2298
2299    #[test]
2300    fn is_unset_chunk_boundaries() {
2301        // N=1 means 8 bits per chunk, so boundaries are more frequent
2302        let mut bitmap = BitMap::<1>::zeroes(32);
2303        bitmap.set(7, true);
2304        assert!(bitmap.is_unset(0..7));
2305        assert!(!bitmap.is_unset(0..8));
2306        assert!(bitmap.is_unset(8..32));
2307    }
2308
2309    #[test]
2310    fn is_unset_small_chunk_multi_span() {
2311        // N=4 means 32 bits per chunk, test spanning 3 chunks
2312        let mut bitmap = BitMap::<4>::zeroes(128);
2313        bitmap.set(96, true);
2314        assert!(bitmap.is_unset(0..96));
2315        assert!(!bitmap.is_unset(0..97));
2316        assert!(bitmap.is_unset(97..128));
2317    }
2318
2319    #[test]
2320    #[should_panic(expected = "out of bounds")]
2321    fn is_unset_out_of_bounds() {
2322        let bitmap = BitMap::<8>::zeroes(64);
2323        bitmap.is_unset(0..65);
2324    }
2325
2326    #[cfg(feature = "arbitrary")]
2327    mod conformance {
2328        use super::*;
2329        use commonware_codec::conformance::CodecConformance;
2330
2331        commonware_conformance::conformance_tests! {
2332            CodecConformance<BitMap>
2333        }
2334    }
2335}