Skip to main content

small_collections/vecs/
heapless_bitvec.rs

1#![cfg(feature = "bitvec")]
2//! Stack-allocated bit vector — the stack half of [`SmallBitVec`](crate::bitvec::SmallBitVec).
3//!
4//! Capacity is measured in **bytes** (`N`); total bit capacity is `N * 8`.
5//! Uses `bitvec`'s `BitOrder` generic to control the bit-within-byte ordering.
6
7use bitvec::prelude::{BitOrder, BitSlice, Lsb0};
8use core::marker::PhantomData;
9use core::ops::{Deref, DerefMut};
10use heapless::Vec as HVec;
11use std::borrow::{Borrow, BorrowMut};
12
13use crate::AnyBitVec;
14
15/// A **stack-allocated** bit vector backed by a `heapless::Vec<u8, N>`.
16///
17/// # Capacity
18/// `N` is the byte capacity.  The maximum number of bits is `N * 8`.
19///
20/// # Bit ordering
21/// The `O: BitOrder` generic controls how bits are arranged within each byte.
22/// The default is `Lsb0` (least-significant-bit first), matching `bitvec`'s default.
23///
24/// # Design Consideration
25/// Bits are stored as packed `u8` bytes.  Individual bit access uses manual
26/// shift/mask arithmetic rather than a full `BitVec` view to avoid the overhead
27/// of slice pointer metadata on the stack.
28///
29/// # Pseudo-code Implementation
30/// `HeaplessBitVec` packs bits into a `u8` vector.
31///
32/// ```text
33/// // 1. Push (push)
34/// if bit_len % 8 == 0:
35///     if bytes.push(0) is full: return Err
36/// if val is true:
37///     bytes[bit_len / 8] |= mask(bit_len % 8)
38/// bit_len += 1
39///
40/// // 2. Pop (pop)
41/// if bit_len == 0: return None
42/// bit_len -= 1
43/// val = (bytes[bit_len / 8] & mask(bit_len % 8)) != 0
44/// if bit_len % 8 == 0:
45///     bytes.pop()
46/// return val
47///
48/// // 3. Get (get)
49/// byte = bytes[index / 8]
50/// return (byte & mask(index % 8)) != 0
51/// ```
52#[derive(Debug)]
53pub struct HeaplessBitVec<const N: usize, O: BitOrder = Lsb0> {
54    bytes: HVec<u8, N>,
55    /// Number of valid bits (may be less than `bytes.len() * 8`).
56    bit_len: usize,
57    _order: PhantomData<O>,
58}
59
60impl<const N: usize, O: BitOrder> Clone for HeaplessBitVec<N, O> {
61    fn clone(&self) -> Self {
62        Self {
63            bytes: self.bytes.clone(),
64            bit_len: self.bit_len,
65            _order: PhantomData,
66        }
67    }
68}
69
70impl<const N: usize, O: BitOrder> HeaplessBitVec<N, O> {
71    /// Automatically generated documentation for this item.
72    pub fn new() -> Self {
73        const {
74            assert!(
75                std::mem::size_of::<Self>() <= 16 * 1024,
76                "HeaplessBitVec is too large! The struct size exceeds the 16KB limit. Reduce N."
77            );
78        }
79        Self {
80            bytes: HVec::new(),
81            bit_len: 0,
82            _order: PhantomData,
83        }
84    }
85
86    /// Returns the number of elements.
87    pub fn len(&self) -> usize {
88        self.bit_len
89    }
90
91    /// Returns `true` if the collection is empty.
92    pub fn is_empty(&self) -> bool {
93        self.bit_len == 0
94    }
95
96    /// Push a bit. Returns `Err(val)` if the stack is full.
97    pub fn push(&mut self, val: bool) -> Result<(), bool> {
98        let bit_idx = self.bit_len % 8;
99
100        // If we are starting a new byte, we need to push a zero-byte to the underlying Vec.
101        if bit_idx == 0 {
102            if self.bytes.push(0).is_err() {
103                return Err(val); // Stack Full
104            }
105        }
106
107        if val {
108            self.set(self.bit_len, true);
109        }
110
111        self.bit_len += 1;
112        Ok(())
113    }
114
115    /// Removes and returns an item from the collection.
116    pub fn pop(&mut self) -> Option<bool> {
117        if self.bit_len == 0 {
118            return None;
119        }
120
121        let val = self.get(self.bit_len - 1).unwrap();
122        self.bit_len -= 1;
123
124        // If we just removed the last bit of a byte, pop the byte to save space
125        if self.bit_len % 8 == 0 {
126            self.bytes.pop();
127        }
128
129        Some(val)
130    }
131
132    /// Returns a reference to the value corresponding to the key.
133    pub fn get(&self, index: usize) -> Option<bool> {
134        if index >= self.bit_len {
135            return None;
136        }
137        let byte_idx = index / 8;
138        let bit_idx = index % 8;
139
140        use bitvec::slice::BitSlice;
141        let byte = self.bytes[byte_idx];
142        let slice = BitSlice::<u8, O>::from_element(&byte);
143        slice.get(bit_idx).as_deref().copied()
144    }
145
146    /// Automatically generated documentation for this item.
147    pub fn set(&mut self, index: usize, value: bool) {
148        if index >= self.bit_len && index != self.bit_len {
149            panic!("Index out of bounds");
150        }
151        let byte_idx = index / 8;
152        let bit_idx = index % 8;
153
154        use bitvec::slice::BitSlice;
155        let byte = &mut self.bytes[byte_idx];
156        let slice = BitSlice::<u8, O>::from_element_mut(byte);
157        slice.set(bit_idx, value);
158    }
159
160    /// Returns the raw underlying bytes.
161    pub fn as_raw_slice(&self) -> &[u8] {
162        &self.bytes
163    }
164
165    /// Returns a `BitSlice` view of the bits.
166    pub fn as_bitslice(&self) -> &BitSlice<u8, O> {
167        let slice = BitSlice::<u8, O>::from_slice(self.bytes.as_slice());
168        &slice[..self.bit_len]
169    }
170
171    /// Returns a mutable `BitSlice` view of the bits.
172    pub fn as_bitslice_mut(&mut self) -> &mut BitSlice<u8, O> {
173        let slice = BitSlice::<u8, O>::from_slice_mut(self.bytes.as_mut_slice());
174        &mut slice[..self.bit_len]
175    }
176}
177
178impl<const N: usize, O: BitOrder> Deref for HeaplessBitVec<N, O> {
179    type Target = BitSlice<u8, O>;
180
181    fn deref(&self) -> &Self::Target {
182        self.as_bitslice()
183    }
184}
185
186impl<const N: usize, O: BitOrder> DerefMut for HeaplessBitVec<N, O> {
187    fn deref_mut(&mut self) -> &mut Self::Target {
188        self.as_bitslice_mut()
189    }
190}
191
192impl<const N: usize, O: BitOrder> Borrow<BitSlice<u8, O>> for HeaplessBitVec<N, O> {
193    fn borrow(&self) -> &BitSlice<u8, O> {
194        self.as_bitslice()
195    }
196}
197
198impl<const N: usize, O: BitOrder> BorrowMut<BitSlice<u8, O>> for HeaplessBitVec<N, O> {
199    fn borrow_mut(&mut self) -> &mut BitSlice<u8, O> {
200        self.as_bitslice_mut()
201    }
202}
203
204impl<const N: usize, O: BitOrder> Default for HeaplessBitVec<N, O> {
205    fn default() -> Self {
206        Self::new()
207    }
208}
209
210impl<const N: usize, O: BitOrder> AnyBitVec for HeaplessBitVec<N, O> {
211    fn len(&self) -> usize {
212        self.len()
213    }
214
215    fn get(&self, index: usize) -> Option<bool> {
216        self.get(index)
217    }
218}
219
220#[cfg(test)]
221mod heapless_bitvec_basic_tests {
222    use super::*;
223    use bitvec::prelude::{Lsb0, Msb0};
224
225    #[test]
226    fn test_heapless_bitvec_traits_bitslice() {
227        use std::borrow::BorrowMut;
228        let mut bv: HeaplessBitVec<1, Lsb0> = HeaplessBitVec::new();
229        bv.push(true).unwrap();
230        bv.push(false).unwrap();
231
232        // Deref to BitSlice
233        let slice: &bitvec::slice::BitSlice<u8, Lsb0> = &bv;
234        assert_eq!(slice.len(), 2);
235        assert_eq!(slice[0], true);
236
237        // BorrowMut
238        let slice_mut: &mut bitvec::slice::BitSlice<u8, Lsb0> = bv.borrow_mut();
239        slice_mut.set(1, true);
240        assert_eq!(bv.get(1), Some(true));
241    }
242
243    #[test]
244    fn test_heapless_bitvec_stack_ops_lsb0() {
245        let mut bv: HeaplessBitVec<1, Lsb0> = HeaplessBitVec::new();
246        bv.push(true).unwrap(); // 0b00000001
247        bv.push(false).unwrap(); // 0b00000001
248        bv.push(true).unwrap(); // 0b00000101
249        assert_eq!(bv.as_raw_slice()[0], 0b00000101);
250        assert_eq!(bv.get(0), Some(true));
251        assert_eq!(bv.get(1), Some(false));
252        assert_eq!(bv.get(2), Some(true));
253    }
254
255    #[test]
256    fn test_heapless_bitvec_stack_ops_msb0() {
257        let mut bv: HeaplessBitVec<1, Msb0> = HeaplessBitVec::new();
258        bv.push(true).unwrap(); // 0b10000000
259        bv.push(false).unwrap(); // 0b10000000
260        bv.push(true).unwrap(); // 0b10100000
261        assert_eq!(bv.as_raw_slice()[0], 0b10100000);
262        assert_eq!(bv.get(0), Some(true));
263        assert_eq!(bv.get(1), Some(false));
264        assert_eq!(bv.get(2), Some(true));
265    }
266
267    #[test]
268    fn test_heapless_bitvec_stack_ops_set_get() {
269        let mut bv: HeaplessBitVec<1, Lsb0> = HeaplessBitVec::new();
270        for _ in 0..8 {
271            bv.push(false).unwrap();
272        }
273        bv.set(0, true);
274        bv.set(7, true);
275        assert_eq!(bv.get(0), Some(true));
276        assert_eq!(bv.get(7), Some(true));
277        assert_eq!(bv.get(1), Some(false));
278    }
279
280    #[test]
281    fn test_heapless_bitvec_stack_ops_empty_len() {
282        let mut bv: HeaplessBitVec<1, Lsb0> = HeaplessBitVec::new();
283        assert!(bv.is_empty());
284        bv.push(true).unwrap();
285        assert!(!bv.is_empty());
286        assert_eq!(bv.len(), 1);
287    }
288
289    #[test]
290    fn test_heapless_bitvec_traits_clone_default() {
291        let bv1: HeaplessBitVec<1, Lsb0> = HeaplessBitVec::default();
292        let mut bv2 = bv1.clone();
293        bv2.push(true).unwrap();
294        assert_eq!(bv2.len(), 1);
295        assert_eq!(bv1.len(), 0);
296    }
297
298    #[test]
299    fn test_heapless_bitvec_stack_ops_boundary_fill() {
300        let mut bv: HeaplessBitVec<1, Lsb0> = HeaplessBitVec::new();
301        for _ in 0..8 {
302            bv.push(true).unwrap();
303        }
304        assert!(bv.push(true).is_err());
305        assert_eq!(bv.len(), 8);
306    }
307
308    #[test]
309    fn test_heapless_bitvec_stack_ops_pop() {
310        let mut bv: HeaplessBitVec<1, Lsb0> = HeaplessBitVec::new();
311        bv.push(true).unwrap();
312        bv.push(false).unwrap();
313        assert_eq!(bv.pop(), Some(false));
314        assert_eq!(bv.pop(), Some(true));
315        assert_eq!(bv.pop(), None);
316    }
317
318    #[test]
319    fn test_heapless_bitvec_traits_any_bitvec_impl() {
320        let mut bv: HeaplessBitVec<1, Lsb0> = HeaplessBitVec::new();
321        bv.push(true).unwrap();
322
323        let any: &dyn AnyBitVec = &bv;
324        assert_eq!(any.len(), 1);
325        assert_eq!(any.get(0), Some(true));
326    }
327}
328
329#[cfg(test)]
330mod heapless_bitvec_coverage_tests {
331    use super::*;
332    use bitvec::prelude::Lsb0;
333    use std::borrow::Borrow;
334
335    #[test]
336    #[should_panic(expected = "Index out of bounds")]
337    fn test_set_out_of_bounds() {
338        let mut bv: HeaplessBitVec<1, Lsb0> = HeaplessBitVec::new();
339        bv.set(10, true);
340    }
341
342    #[test]
343    fn test_deref_mut_and_borrow() {
344        let mut bv: HeaplessBitVec<1, Lsb0> = HeaplessBitVec::new();
345        bv.push(true).unwrap();
346
347        // DerefMut
348        use core::ops::DerefMut;
349        let slice = bv.deref_mut();
350        slice.set(0, false);
351
352        // Borrow
353        let borrowed: &bitvec::slice::BitSlice<u8, Lsb0> = bv.borrow();
354        assert_eq!(borrowed.len(), 1);
355    }
356}