Skip to main content

small_collections/vecs/
bitvec.rs

1#![cfg(feature = "bitvec")]
2//! Bit vector that lives on the stack and spills to the heap.
3//!
4//! Provides [`SmallBitVec`] — backed by [`HeaplessBitVec`] on the stack and
5//! `bitvec::prelude::BitVec` on the heap.  [`AnyBitVec`] is the object-safe
6//! inspection trait implemented by both.
7
8use crate::HeaplessBitVec;
9use bitvec::prelude::{BitOrder, BitSlice, BitVec, Lsb0};
10use core::mem::ManuallyDrop;
11use core::ops::{Deref, DerefMut};
12use core::ptr;
13use std::borrow::{Borrow, BorrowMut};
14
15/// A trait for uniform inspection of bit vectors.
16pub trait AnyBitVec {
17    /// Returns the number of bits in the bit vector.
18    fn len(&self) -> usize;
19
20    /// Returns `true` if the bit vector contains no bits.
21    fn is_empty(&self) -> bool {
22        self.len() == 0
23    }
24
25    /// Returns the bit value at the given index, or `None` if out of bounds.
26    fn get(&self, index: usize) -> Option<bool>;
27}
28
29impl<O: BitOrder> AnyBitVec for BitVec<u8, O> {
30    fn len(&self) -> usize {
31        self.as_bitslice().len()
32    }
33    fn get(&self, index: usize) -> Option<bool> {
34        self.as_bitslice().get(index).map(|b| *b)
35    }
36}
37
38/// A bit vector that lives on the stack for `N * 8` bits, then spills to a heap
39/// `bitvec::BitVec`.
40///
41/// # Capacity
42/// `N` is measured in **bytes**; total bit capacity is `N * 8`.
43///
44/// # Generic parameters
45/// | Parameter | Meaning |
46/// |-----------|--------|
47/// | `N` | Stack capacity in bytes |
48/// | `O` | Bit ordering within each byte; defaults to `Lsb0` |
49///
50/// # Design Considerations
51/// - **Byte-granular storage**: bits are packed into `u8` bytes by `HeaplessBitVec`.
52///   Spill copies them directly into a `BitVec<u8, O>`, keeping the same byte layout.
53/// - **`on_stack` tag**: the `BitData` union is discriminated by `on_stack`, just like
54///   all other `Small*` types in this crate.
55///
56/// # Safety
57/// `on_stack` determines which variant of `BitData` is active.  Only the active
58/// variant may be accessed.
59pub struct SmallBitVec<const N: usize, O: BitOrder = Lsb0> {
60    on_stack: bool,
61    data: BitData<N, O>,
62}
63
64/// Internal storage for `SmallBitVec`.
65union BitData<const N: usize, O: BitOrder> {
66    stack: ManuallyDrop<HeaplessBitVec<N, O>>,
67    // We use u8 as the storage primitive to match HeaplessBitVec.
68    heap: ManuallyDrop<BitVec<u8, O>>,
69}
70
71impl<const N: usize, O: BitOrder> SmallBitVec<N, O> {
72    /// Creates a new empty SmallBitVec.
73    ///
74    /// # Capacity
75    /// `N` represents **BYTES**.
76    /// Stack bit capacity = `N * 8`.
77    pub fn new() -> Self {
78        const {
79            assert!(
80                std::mem::size_of::<Self>() <= 16 * 1024,
81                "SmallBitVec is too large! Reduce N."
82            );
83        }
84        Self {
85            on_stack: true,
86            data: BitData {
87                stack: ManuallyDrop::new(HeaplessBitVec::new()),
88            },
89        }
90    }
91
92    /// Returns the number of bits in the vector.
93    #[inline(always)]
94    pub fn len(&self) -> usize {
95        unsafe {
96            if self.on_stack {
97                self.data.stack.len()
98            } else {
99                self.data.heap.len()
100            }
101        }
102    }
103
104    /// Returns `true` if the vector contains no bits.
105    #[inline(always)]
106    pub fn is_empty(&self) -> bool {
107        self.len() == 0
108    }
109
110    /// Returns `true` if the vector is currently storing data on the stack.
111    #[inline(always)]
112    pub fn is_on_stack(&self) -> bool {
113        self.on_stack
114    }
115
116    /// Appends a bit to the back of the collection.
117    ///
118    /// If the stack capacity `N` is exceeded, this triggers a transparent spill to the heap.
119    #[inline(always)]
120    pub fn push(&mut self, value: bool) {
121        unsafe {
122            if self.on_stack {
123                let stack = &mut *self.data.stack;
124                // Attempt to push to stack
125                if let Err(_) = stack.push(value) {
126                    // Failure means full: Spill and retry
127                    self.spill_to_heap();
128                    (*self.data.heap).push(value);
129                }
130            } else {
131                (*self.data.heap).push(value);
132            }
133        }
134    }
135
136    /// Removes the last bit from a vector and returns it, or `None` if it is empty.
137    #[inline(always)]
138    pub fn pop(&mut self) -> Option<bool> {
139        unsafe {
140            if self.on_stack {
141                (*self.data.stack).pop()
142            } else {
143                (*self.data.heap).pop()
144            }
145        }
146    }
147
148    /// Returns the bit value at the given index, or `None` if out of bounds.
149    #[inline(always)]
150    pub fn get(&self, index: usize) -> Option<bool> {
151        unsafe {
152            if self.on_stack {
153                self.data.stack.get(index)
154            } else {
155                self.data.heap.get(index)
156            }
157        }
158    }
159
160    /// Sets the bit value at the given index.
161    ///
162    /// # Panics
163    /// Panics if `index` is out of bounds.
164    #[inline(always)]
165    pub fn set(&mut self, index: usize, value: bool) {
166        unsafe {
167            if self.on_stack {
168                (*self.data.stack).set(index, value);
169            } else {
170                (*self.data.heap).set(index, value);
171            }
172        }
173    }
174
175    /// Returns a `BitSlice` view of the bits.
176    pub fn as_bitslice(&self) -> &BitSlice<u8, O> {
177        unsafe {
178            if self.on_stack {
179                self.data.stack.as_bitslice()
180            } else {
181                self.data.heap.as_bitslice()
182            }
183        }
184    }
185
186    /// Returns a mutable `BitSlice` view of the bits.
187    pub fn as_bitslice_mut(&mut self) -> &mut BitSlice<u8, O> {
188        unsafe {
189            if self.on_stack {
190                (*self.data.stack).as_bitslice_mut()
191            } else {
192                (*self.data.heap).as_mut_bitslice()
193            }
194        }
195    }
196
197    /// The Critical Spill Function
198    /// Moves data from HeaplessBitVec -> bitvec::BitVec
199    #[inline(never)]
200    unsafe fn spill_to_heap(&mut self) {
201        unsafe {
202            let stack = ManuallyDrop::take(&mut self.data.stack);
203
204            // 2. Create BitVec from the raw bytes
205            let mut heap_vec: BitVec<u8, O> = BitVec::from_slice(stack.as_raw_slice());
206
207            // 3. Truncate to exact length
208            heap_vec.truncate(stack.len());
209
210            // 4. Reserve extra capacity
211            heap_vec.reserve(stack.len());
212
213            // 5. Update state
214            // CRITICAL: We use ptr::write to avoid dropping the "old" bits (garbage data)
215            // in the target union slot.
216            ptr::write(&mut self.data.heap, ManuallyDrop::new(heap_vec));
217            self.on_stack = false;
218        }
219    }
220}
221
222impl<const N: usize, O: BitOrder> Deref for SmallBitVec<N, O> {
223    type Target = BitSlice<u8, O>;
224
225    fn deref(&self) -> &Self::Target {
226        self.as_bitslice()
227    }
228}
229
230impl<const N: usize, O: BitOrder> DerefMut for SmallBitVec<N, O> {
231    fn deref_mut(&mut self) -> &mut Self::Target {
232        self.as_bitslice_mut()
233    }
234}
235
236impl<const N: usize, O: BitOrder> Borrow<BitSlice<u8, O>> for SmallBitVec<N, O> {
237    fn borrow(&self) -> &BitSlice<u8, O> {
238        self.as_bitslice()
239    }
240}
241
242impl<const N: usize, O: BitOrder> BorrowMut<BitSlice<u8, O>> for SmallBitVec<N, O> {
243    fn borrow_mut(&mut self) -> &mut BitSlice<u8, O> {
244        self.as_bitslice_mut()
245    }
246}
247
248// --- Trait Impls ---
249
250impl<const N: usize, O: BitOrder> AnyBitVec for SmallBitVec<N, O> {
251    fn len(&self) -> usize {
252        self.len()
253    }
254
255    fn get(&self, index: usize) -> Option<bool> {
256        self.get(index)
257    }
258}
259
260impl<const N: usize, O: BitOrder> Drop for SmallBitVec<N, O> {
261    fn drop(&mut self) {
262        unsafe {
263            if self.on_stack {
264                ManuallyDrop::drop(&mut self.data.stack);
265            } else {
266                ManuallyDrop::drop(&mut self.data.heap);
267            }
268        }
269    }
270}
271
272impl<const N: usize, O: BitOrder> Clone for SmallBitVec<N, O> {
273    fn clone(&self) -> Self {
274        unsafe {
275            if self.on_stack {
276                SmallBitVec {
277                    on_stack: true,
278                    data: BitData {
279                        stack: self.data.stack.clone(),
280                    },
281                }
282            } else {
283                SmallBitVec {
284                    on_stack: false,
285                    data: BitData {
286                        heap: self.data.heap.clone(),
287                    },
288                }
289            }
290        }
291    }
292}
293
294impl<const N: usize, O: BitOrder> core::fmt::Debug for SmallBitVec<N, O> {
295    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
296        f.write_str("SmallBitVec [")?;
297        for i in 0..self.len() {
298            if self.get(i).unwrap_or(false) {
299                f.write_str("1")?;
300            } else {
301                f.write_str("0")?;
302            }
303            if (i + 1) % 8 == 0 && i + 1 != self.len() {
304                f.write_str("_")?;
305            }
306        }
307        f.write_str("]")
308    }
309}
310
311impl<const N: usize, O: BitOrder> Default for SmallBitVec<N, O> {
312    fn default() -> Self {
313        Self::new()
314    }
315}
316
317#[cfg(test)]
318mod bitvec_basic_tests {
319    use super::*;
320    use bitvec::prelude::{Lsb0, Msb0};
321
322    #[test]
323    fn test_bitvec_traits_bitslice() {
324        use std::borrow::BorrowMut;
325        let mut sbv: SmallBitVec<1, Lsb0> = SmallBitVec::new();
326        sbv.push(true);
327        sbv.push(false);
328
329        // Deref to BitSlice
330        let slice: &bitvec::slice::BitSlice<u8, Lsb0> = &sbv;
331        assert_eq!(slice.len(), 2);
332
333        // BorrowMut
334        let slice_mut: &mut bitvec::slice::BitSlice<u8, Lsb0> = sbv.borrow_mut();
335        slice_mut.set(1, true);
336        assert_eq!(sbv.get(1), Some(true));
337
338        // Spill and test again
339        for _ in 0..10 {
340            sbv.push(true);
341        }
342        assert!(!sbv.is_on_stack());
343
344        let slice_heap: &bitvec::slice::BitSlice<u8, Lsb0> = &sbv;
345        assert_eq!(slice_heap.len(), 12);
346    }
347
348    #[test]
349    fn test_bitvec_spill_trigger_lsb0() {
350        let mut sbv: SmallBitVec<1, Lsb0> = SmallBitVec::new();
351        for _ in 0..8 {
352            sbv.push(true);
353        }
354        assert!(sbv.is_on_stack());
355        assert_eq!(sbv.len(), 8);
356
357        sbv.push(false); // Should spill
358        assert!(!sbv.is_on_stack());
359        assert_eq!(sbv.len(), 9);
360        assert_eq!(sbv.get(0), Some(true));
361        assert_eq!(sbv.get(8), Some(false));
362    }
363
364    #[test]
365    fn test_bitvec_spill_trigger_msb0() {
366        let mut sbv: SmallBitVec<1, Msb0> = SmallBitVec::new();
367        sbv.push(true); // bit 0
368        sbv.push(false); // bit 1
369        for _ in 0..6 {
370            sbv.push(true);
371        }
372        assert!(sbv.is_on_stack());
373
374        sbv.push(true); // Should spill
375        assert!(!sbv.is_on_stack());
376        assert_eq!(sbv.get(0), Some(true));
377        assert_eq!(sbv.get(1), Some(false));
378    }
379
380    #[test]
381    fn test_bitvec_any_storage_pop_set() {
382        let mut sbv: SmallBitVec<1, Lsb0> = SmallBitVec::new();
383        sbv.push(true);
384        sbv.push(false);
385        assert_eq!(sbv.pop(), Some(false));
386        sbv.set(0, false);
387        assert_eq!(sbv.get(0), Some(false));
388
389        for _ in 0..10 {
390            sbv.push(true);
391        }
392        assert!(!sbv.is_on_stack());
393        sbv.set(10, false);
394        assert_eq!(sbv.get(10), Some(false));
395        assert_eq!(sbv.pop(), Some(false));
396    }
397
398    #[test]
399    fn test_bitvec_traits_debug_default() {
400        let sbv: SmallBitVec<1, Lsb0> = SmallBitVec::default();
401        assert!(sbv.is_empty());
402
403        let mut sbv2 = SmallBitVec::<1, Lsb0>::new();
404        sbv2.push(true);
405        sbv2.push(false);
406        let debug = format!("{:?}", sbv2);
407        assert!(debug.contains("10"));
408    }
409
410    #[test]
411    fn test_bitvec_any_storage_pop_empty() {
412        let mut sbv: SmallBitVec<1, Lsb0> = SmallBitVec::new();
413        assert_eq!(sbv.pop(), None);
414    }
415
416    #[test]
417    fn test_bitvec_any_storage_get_none() {
418        let mut sbv: SmallBitVec<1, Lsb0> = SmallBitVec::new();
419        assert_eq!(sbv.get(10), None);
420
421        for _ in 0..10 {
422            sbv.push(true);
423        }
424        assert_eq!(sbv.get(100), None);
425    }
426
427    #[test]
428    fn test_bitvec_traits_debug_multi_byte() {
429        let mut sbv2: SmallBitVec<2, Lsb0> = SmallBitVec::new();
430        for _ in 0..16 {
431            sbv2.push(true);
432        }
433        let debug = format!("{:?}", sbv2);
434        assert!(debug.contains("_"));
435    }
436
437    #[test]
438    fn test_bitvec_traits_any_bitvec_impl() {
439        let mut sbv: SmallBitVec<1, Lsb0> = SmallBitVec::new();
440        sbv.push(true);
441        sbv.push(false);
442
443        let any: &dyn AnyBitVec = &sbv;
444        assert_eq!(any.len(), 2);
445        assert_eq!(any.get(0), Some(true));
446        assert_eq!(any.get(1), Some(false));
447    }
448}
449
450#[cfg(test)]
451mod bitvec_coverage_tests {
452    use super::*;
453    use bitvec::prelude::Lsb0;
454
455    #[test]
456    fn test_any_bitvec_is_empty() {
457        struct MockAny;
458        impl AnyBitVec for MockAny {
459            fn len(&self) -> usize {
460                0
461            }
462            fn get(&self, _index: usize) -> Option<bool> {
463                None
464            }
465        }
466        let m = MockAny;
467        assert!(m.is_empty());
468
469        let mut b: BitVec<u8, Lsb0> = BitVec::new();
470        {
471            let any_b: &dyn AnyBitVec = &b;
472            assert_eq!(any_b.len(), 0);
473        }
474        b.push(true);
475        {
476            let any_b: &dyn AnyBitVec = &b;
477            assert_eq!(any_b.get(0), Some(true));
478        }
479    }
480
481    #[test]
482    fn test_small_bitvec_traits_and_heap() {
483        use core::ops::DerefMut;
484        use std::borrow::Borrow;
485
486        let mut sbv: SmallBitVec<1, Lsb0> = SmallBitVec::new();
487        sbv.push(true);
488
489        // AnyBitVec len / get
490        let any: &dyn AnyBitVec = &sbv;
491        assert_eq!(any.len(), 1);
492        assert_eq!(any.get(0), Some(true));
493
494        // Borrow
495        let borrowed: &bitvec::slice::BitSlice<u8, Lsb0> = sbv.borrow();
496        assert_eq!(borrowed.len(), 1);
497
498        // Clone stack
499        let cloned_stack = sbv.clone();
500        assert_eq!(cloned_stack.len(), 1);
501
502        // DerefMut heap
503        for _ in 0..10 {
504            sbv.push(false);
505        }
506        let mut_slice = sbv.deref_mut();
507        mut_slice.set(1, true);
508
509        // Clone heap
510        let cloned_heap = sbv.clone();
511        assert_eq!(cloned_heap.len(), 11);
512    }
513}