binvec/
lib.rs

1pub mod error;
2
3mod iter;
4pub use iter::*;
5
6
7/// A fixed-length array type that stores `0` or `1`.
8/// It uses up to 8 times less memory compared to a [`bool`] array.
9/// 
10/// ---
11/// # Note
12/// The [`bool`] type uses 1 byte (8 bits). Therefore, storing 100 [`bool`]s requires 100 bytes (800 bits).
13/// In general situations, this is not a big problem,
14/// but when the array length exceeds thousands or in embedded environments with limited memory capacity,
15/// this memory usage cannot be ignored.
16/// 
17/// To use minimal memory, calculate the minimum byte array size `N` needed to store `L` bits. The formula is as follows:
18/// ```text
19/// N = (L + 7) / 8
20/// ```
21/// 
22/// For example, to store 10 bits, 2 bytes are used. In this case, the remaining 6 bits are unused.
23/// ```text
24/// |----- byte0 -----|----- byte1 -----|
25/// | 0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0 |
26///   ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^
27///       10 bits used       Not used
28/// ```
29/// 
30/// ---
31/// # Generics
32/// - `L`: The number of bits to store.
33/// - `N`: The minimum byte array length required to store `L`.
34/// 
35/// ---
36/// # Examples
37/// ```
38/// use binvec::*;
39/// 
40/// // A binvec storing 12 bits initialized to 0
41/// let mut binvec = binvec!(12, false);
42/// ```
43/// 
44#[derive(Debug, Clone, PartialEq, Eq)]
45pub struct Binvec<const L: usize, const N: usize> {
46    inner: [u8; N],
47}
48
49
50// impl
51impl<const L: usize, const N: usize> Binvec<L, N> {
52    /// Creates a new [`Binvec`].
53    /// 
54    /// **It is not recommended to use this function. Please use [`binvec!`] macro instead.**
55    /// 
56    /// ---
57    /// # Arguments
58    /// - `initial_value`: The initial value to initialize the array.
59    /// 
60    /// ---
61    /// # Returns
62    /// An `L` length [`Binvec`] initialized with `initial_value`.
63    /// 
64    /// ---
65    /// # Examples
66    /// ```
67    /// use binvec::Binvec;
68    /// 
69    /// let binvec = Binvec::<12, 2>::new(false);
70    /// ```
71    /// 
72    #[deprecated(note = "Use the `binvec!` macro instead.")]
73    #[doc(hidden)]
74    pub const fn new(initial_value: bool) -> Self {
75        let mut new: Binvec<L, N> = Self { inner: [0x00; N] };
76        new.fill(initial_value);
77        new
78    }
79
80    /// Returns the length in bits of the [`Binvec`].
81    ///
82    /// ---
83    /// # Returns
84    /// The number of bits stored in the [`Binvec`].
85    ///
86    /// ---
87    /// # Examples
88    /// ```
89    /// use binvec::*;
90    ///
91    /// let binvec = binvec!(12, false);
92    /// assert_eq!(binvec.len(), 12);
93    /// ```
94    /// 
95    #[inline(always)]
96    pub const fn len(&self) -> usize {
97        L
98    }
99
100    /// Returns the bit value at the given index without performing bounds checking.
101    ///
102    /// ---
103    /// # Safety
104    /// Calling this method with an out-of-bounds index is undefined behavior.
105    ///
106    /// ---
107    /// # Arguments
108    /// - `index`: The bit index to retrieve.
109    ///
110    /// ---
111    /// # Returns
112    /// - `true` if the bit at `index` is 1.
113    /// - `false` if the bit at `index` is 0.
114    ///
115    /// ---
116    /// # Examples
117    /// ```
118    /// use binvec::*;
119    ///
120    /// let binvec = binvec!(12, true);
121    /// let bit = unsafe { binvec.get_unchecked(5) };
122    /// assert_eq!(bit, true);
123    /// ```
124    /// 
125    pub const unsafe fn get_unchecked(&self, index: usize) -> bool {
126        let byte_index: usize = index >> 3; // same as `index / 8`
127        let bit_offset: usize = index & 0b111; // same as `index % 8`
128        let byte: u8 = self.inner[byte_index];
129        ((byte >> bit_offset) & 1) != 0
130    }
131
132    /// Returns the bit value at the given index with bounds checking.
133    ///
134    /// ---
135    /// # Arguments
136    /// - `index`: The bit index to retrieve.
137    ///
138    /// ---
139    /// # Returns
140    /// - `Some(true)` if the bit at `index` is 1.
141    /// - `Some(false)` if the bit at `index` is 0.
142    /// - `None` if `index` is out of bounds.
143    ///
144    /// # Examples
145    /// ```
146    /// use binvec::*;
147    ///
148    /// let binvec = binvec!(12, true);
149    /// assert_eq!(binvec.get(5), Some(true));
150    /// assert_eq!(binvec.get(20), None);
151    /// ```
152    /// 
153    #[inline]
154    pub fn get(&self, index: usize) -> Option<bool> {
155        if index < L {
156            Some(unsafe { self.get_unchecked(index) })
157        } else {
158            None
159        }
160    }
161
162    /// Sets the bit value at the given index without performing bounds checking.
163    ///
164    /// ---
165    /// # Safety
166    /// Calling this method with an out-of-bounds index is undefined behavior.
167    ///
168    /// ---
169    /// # Arguments
170    /// - `index`: The bit index to set.
171    /// - `value`: The bit value to set (`true` for 1, `false` for 0).
172    ///
173    /// ---
174    /// # Examples
175    /// ```
176    /// use binvec::*;
177    ///
178    /// let mut binvec = binvec!(12, false);
179    /// unsafe { binvec.set_unchecked(3, true); }
180    /// assert_eq!(binvec.get(3), Some(true));
181    /// ```
182    /// 
183    pub unsafe fn set_unchecked(&mut self, index: usize, value: bool) {
184        let byte_index: usize = index >> 3; // same as `index / 8`
185        let bit_offset: usize = index & 0b111; // same as `index % 8`
186        let mask: u8 = 1 << bit_offset;
187        let byte: &mut u8 = &mut self.inner[byte_index];
188        if value == true {
189            *byte |= mask;
190        } else {
191            *byte &= !mask;
192        }
193    }
194
195    /// Sets the bit value at the given index with bounds checking.
196    ///
197    /// ---
198    /// # Arguments
199    /// - `index`: The bit index to set.
200    /// - `value`: The bit value to set (`true` for 1, `false` for 0).
201    ///
202    /// ---
203    /// # Returns
204    /// - `Ok(())` if the bit was successfully set.
205    /// - `Err(())` if the index is out of bounds.
206    ///
207    /// ---
208    /// # Examples
209    /// ```
210    /// use binvec::*;
211    ///
212    /// let mut binvec = binvec!(12, false);
213    /// assert_eq!(binvec.set(5, true), Ok(()));
214    /// assert_eq!(binvec.get(5), Some(true));
215    ///
216    /// assert_eq!(binvec.set(20, true), Err(error::IndexOutOfBounds));
217    /// ```
218    /// 
219    #[inline]
220    pub fn set(&mut self, index: usize, value: bool) -> Result<(), error::IndexOutOfBounds> {
221        if index < L {
222            unsafe { self.set_unchecked(index, value); }
223            Ok(())
224        } else {
225            Err(error::IndexOutOfBounds)
226        }
227    }
228
229    /// Fills the entire [`Binvec`] with the specified bit value.
230    ///
231    /// This method sets all bits in the [`Binvec`] to either `true` (1) or `false` (0).
232    /// For bits beyond the length `L` in the last byte, those bits are cleared to zero.
233    ///
234    /// ---
235    /// # Arguments
236    /// - `value`: The bit value to fill the [`Binvec`] with (`true` for 1, `false` for 0).
237    ///
238    /// ---
239    /// # Examples
240    /// ```
241    /// use binvec::*;
242    ///
243    /// let mut binvec = binvec!(12, false);
244    /// binvec.fill(true);
245    /// assert_eq!(binvec.is_all_one(), true);
246    /// ```
247    /// 
248    pub const fn fill(&mut self, value: bool) {
249        let byte: u8 = if value == true { 0xFF } else { 0x00 };
250        let mut inner: [u8; N] = [byte; N];
251        if L > 0
252        && L % 8 != 0 {
253            let last_bits: usize = L % 8;
254            let mask: u8 = (1u8 << last_bits) - 1;
255            inner[N - 1] &= mask;
256        }
257        self.inner = inner;
258    }
259
260    /// Counts the number of bits set to `1` in the [`Binvec`].
261    ///
262    /// ---
263    /// # Returns
264    /// The total count of bits that are set to `1`.
265    ///
266    /// ---
267    /// # Examples
268    /// ```
269    /// use binvec::*;
270    ///
271    /// let binvec = binvec!(12, true);
272    /// assert_eq!(binvec.count_ones(), 12);
273    ///
274    /// let mut binvec = binvec!(12, false);
275    /// binvec.set(3, true).unwrap();
276    /// assert_eq!(binvec.count_ones(), 1);
277    /// ```
278    /// 
279    pub const fn count_ones(&self) -> usize {
280        let mut count: usize = 0;
281        let mut i: usize = 0;
282        while i < N {
283            count += self.inner[i].count_ones() as usize;
284            i += 1;
285        }
286        count // unused value is always filled with 0
287    }
288
289    /// Counts the number of bits set to `0` in the [`Binvec`].
290    ///
291    /// ---
292    /// # Returns
293    /// The total count of bits that are set to `0`.
294    ///
295    /// ---
296    /// # Examples
297    /// ```
298    /// use binvec::*;
299    ///
300    /// let binvec = binvec!(12, false);
301    /// assert_eq!(binvec.count_zeros(), 12);
302    ///
303    /// let mut binvec = binvec!(12, true);
304    /// binvec.set(3, false).unwrap();
305    /// assert_eq!(binvec.count_zeros(), 1);
306    /// ```
307    /// 
308    pub const fn count_zeros(&self) -> usize {
309        let mut count: usize = 0;
310        let mut i: usize = 0;
311        while i < N {
312            count += self.inner[i].count_zeros() as usize;
313            i += 1;
314        }
315        count - ((N * 8) - L) // unused value is always filled with 0
316    }
317
318    /// Checks if all bits in the [`Binvec`] are set to `1`.
319    ///
320    /// ---
321    /// # Returns
322    /// `true` if all bits that are using is `1`, otherwise `false`.
323    ///
324    /// ---
325    /// # Examples
326    /// ```
327    /// use binvec::*;
328    ///
329    /// let binvec = binvec!(12, true);
330    /// assert_eq!(binvec.is_all_one(), true);
331    ///
332    /// let mut binvec = binvec!(12, false);
333    /// assert_eq!(binvec.is_all_one(), false);
334    /// binvec.fill(true);
335    /// assert_eq!(binvec.is_all_one(), true);
336    /// ```
337    /// 
338    #[inline(always)]
339    pub const fn is_all_one(&self) -> bool {
340        self.count_ones() == L
341    }
342
343    /// Checks if all bits in the [`Binvec`] are set to `0`.
344    ///
345    /// ---
346    /// # Returns
347    /// `true` if all bits that are using is `0`, otherwise `false`.
348    ///
349    /// ---
350    /// # Examples
351    /// ```
352    /// use binvec::*;
353    ///
354    /// let binvec = binvec!(12, false);
355    /// assert_eq!(binvec.is_all_zero(), true);
356    ///
357    /// let mut binvec = binvec!(12, true);
358    /// assert_eq!(binvec.is_all_zero(), false);
359    /// binvec.fill(false);
360    /// assert_eq!(binvec.is_all_zero(), true);
361    /// ```
362    /// 
363    #[inline(always)]
364    pub const fn is_all_zero(&self) -> bool {
365        self.count_zeros() == L
366    }
367
368    /// Returns an iterator over the bits of the [`Binvec`].
369    ///
370    /// ---
371    /// # Returns
372    /// A [`BinvecIter`] that yields each bit as a `bool`.
373    ///
374    /// ---
375    /// # Examples
376    /// ```
377    /// use binvec::*;
378    ///
379    /// let binvec = binvec!(12, true);
380    /// for bit in binvec.iter() {
381    ///     assert_eq!(bit, true);
382    /// }
383    /// ```
384    /// 
385    #[inline(always)]
386    pub fn iter(&self) -> BinvecIter<'_, L, N> {
387        BinvecIter::new(self)
388    }
389}
390
391
392// impl IntoIterator
393impl<'a, const L: usize, const N: usize> IntoIterator for &'a Binvec<L, N> {
394    type Item = bool;
395    type IntoIter = BinvecIter<'a, L, N>;
396
397    fn into_iter(self) -> Self::IntoIter {
398        self.iter()
399    }
400}
401
402
403/// Creates a new [`Binvec`].
404/// 
405/// ---
406/// # Arguments
407/// - `len`: Number of bits to store
408/// - `initial_value`: Initial value of the array
409/// 
410/// ---
411/// # Returns
412/// An `len` length [`Binvec`] initialized with `initial_value`.
413/// 
414/// ---
415/// # Examples
416/// ```
417/// use binvec::*;
418/// 
419/// let binvec = binvec!(12, false);
420/// ```
421/// 
422#[macro_export]
423macro_rules! binvec {
424    ($len:expr, $initial_value:expr) => {{
425        const L: usize = $len;
426        const N: usize = (L + 7) >> 3; // same as (L + 7) / 8
427        #[allow(deprecated)]
428        Binvec::<L, N>::new($initial_value)
429    }};
430}
431
432
433// impl Display
434impl<const L: usize, const N: usize> core::fmt::Display for Binvec<L, N> {
435    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
436        write!(f, "[")?;
437        let mut iter: BinvecIter<'_, L, N> = self.iter();
438        if let Some(first) = iter.next() {
439            write!(f, "{}", if first { "1" } else { "0" })?;
440            for bit in iter {
441                write!(f, ", {}", if bit { "1" } else { "0" })?;
442            }
443        }
444        write!(f, "]")
445    }
446}