#![cfg(feature = "bitvec")]
use crate::HeaplessBitVec;
use bitvec::prelude::{BitOrder, BitSlice, BitVec, Lsb0};
use core::mem::ManuallyDrop;
use core::ops::{Deref, DerefMut};
use core::ptr;
use std::borrow::{Borrow, BorrowMut};
pub trait AnyBitVec {
fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
fn get(&self, index: usize) -> Option<bool>;
}
impl<O: BitOrder> AnyBitVec for BitVec<u8, O> {
fn len(&self) -> usize {
self.as_bitslice().len()
}
fn get(&self, index: usize) -> Option<bool> {
self.as_bitslice().get(index).map(|b| *b)
}
}
pub struct SmallBitVec<const N: usize, O: BitOrder = Lsb0> {
on_stack: bool,
data: BitData<N, O>,
}
union BitData<const N: usize, O: BitOrder> {
stack: ManuallyDrop<HeaplessBitVec<N, O>>,
heap: ManuallyDrop<BitVec<u8, O>>,
}
impl<const N: usize, O: BitOrder> SmallBitVec<N, O> {
pub fn new() -> Self {
const {
assert!(
std::mem::size_of::<Self>() <= 16 * 1024,
"SmallBitVec is too large! Reduce N."
);
}
Self {
on_stack: true,
data: BitData {
stack: ManuallyDrop::new(HeaplessBitVec::new()),
},
}
}
#[inline(always)]
pub fn len(&self) -> usize {
unsafe {
if self.on_stack {
self.data.stack.len()
} else {
self.data.heap.len()
}
}
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline(always)]
pub fn is_on_stack(&self) -> bool {
self.on_stack
}
#[inline(always)]
pub fn push(&mut self, value: bool) {
unsafe {
if self.on_stack {
let stack = &mut *self.data.stack;
if let Err(_) = stack.push(value) {
self.spill_to_heap();
(*self.data.heap).push(value);
}
} else {
(*self.data.heap).push(value);
}
}
}
#[inline(always)]
pub fn pop(&mut self) -> Option<bool> {
unsafe {
if self.on_stack {
(*self.data.stack).pop()
} else {
(*self.data.heap).pop()
}
}
}
#[inline(always)]
pub fn get(&self, index: usize) -> Option<bool> {
unsafe {
if self.on_stack {
self.data.stack.get(index)
} else {
self.data.heap.get(index)
}
}
}
#[inline(always)]
pub fn set(&mut self, index: usize, value: bool) {
unsafe {
if self.on_stack {
(*self.data.stack).set(index, value);
} else {
(*self.data.heap).set(index, value);
}
}
}
pub fn as_bitslice(&self) -> &BitSlice<u8, O> {
unsafe {
if self.on_stack {
self.data.stack.as_bitslice()
} else {
self.data.heap.as_bitslice()
}
}
}
pub fn as_bitslice_mut(&mut self) -> &mut BitSlice<u8, O> {
unsafe {
if self.on_stack {
(*self.data.stack).as_bitslice_mut()
} else {
(*self.data.heap).as_mut_bitslice()
}
}
}
#[inline(never)]
unsafe fn spill_to_heap(&mut self) {
unsafe {
let stack = ManuallyDrop::take(&mut self.data.stack);
let mut heap_vec: BitVec<u8, O> = BitVec::from_slice(stack.as_raw_slice());
heap_vec.truncate(stack.len());
heap_vec.reserve(stack.len());
ptr::write(&mut self.data.heap, ManuallyDrop::new(heap_vec));
self.on_stack = false;
}
}
}
impl<const N: usize, O: BitOrder> Deref for SmallBitVec<N, O> {
type Target = BitSlice<u8, O>;
fn deref(&self) -> &Self::Target {
self.as_bitslice()
}
}
impl<const N: usize, O: BitOrder> DerefMut for SmallBitVec<N, O> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_bitslice_mut()
}
}
impl<const N: usize, O: BitOrder> Borrow<BitSlice<u8, O>> for SmallBitVec<N, O> {
fn borrow(&self) -> &BitSlice<u8, O> {
self.as_bitslice()
}
}
impl<const N: usize, O: BitOrder> BorrowMut<BitSlice<u8, O>> for SmallBitVec<N, O> {
fn borrow_mut(&mut self) -> &mut BitSlice<u8, O> {
self.as_bitslice_mut()
}
}
impl<const N: usize, O: BitOrder> AnyBitVec for SmallBitVec<N, O> {
fn len(&self) -> usize {
self.len()
}
fn get(&self, index: usize) -> Option<bool> {
self.get(index)
}
}
impl<const N: usize, O: BitOrder> Drop for SmallBitVec<N, O> {
fn drop(&mut self) {
unsafe {
if self.on_stack {
ManuallyDrop::drop(&mut self.data.stack);
} else {
ManuallyDrop::drop(&mut self.data.heap);
}
}
}
}
impl<const N: usize, O: BitOrder> Clone for SmallBitVec<N, O> {
fn clone(&self) -> Self {
unsafe {
if self.on_stack {
SmallBitVec {
on_stack: true,
data: BitData {
stack: self.data.stack.clone(),
},
}
} else {
SmallBitVec {
on_stack: false,
data: BitData {
heap: self.data.heap.clone(),
},
}
}
}
}
}
impl<const N: usize, O: BitOrder> core::fmt::Debug for SmallBitVec<N, O> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("SmallBitVec [")?;
for i in 0..self.len() {
if self.get(i).unwrap_or(false) {
f.write_str("1")?;
} else {
f.write_str("0")?;
}
if (i + 1) % 8 == 0 && i + 1 != self.len() {
f.write_str("_")?;
}
}
f.write_str("]")
}
}
impl<const N: usize, O: BitOrder> Default for SmallBitVec<N, O> {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod bitvec_basic_tests {
use super::*;
use bitvec::prelude::{Lsb0, Msb0};
#[test]
fn test_bitvec_traits_bitslice() {
use std::borrow::BorrowMut;
let mut sbv: SmallBitVec<1, Lsb0> = SmallBitVec::new();
sbv.push(true);
sbv.push(false);
let slice: &bitvec::slice::BitSlice<u8, Lsb0> = &sbv;
assert_eq!(slice.len(), 2);
let slice_mut: &mut bitvec::slice::BitSlice<u8, Lsb0> = sbv.borrow_mut();
slice_mut.set(1, true);
assert_eq!(sbv.get(1), Some(true));
for _ in 0..10 {
sbv.push(true);
}
assert!(!sbv.is_on_stack());
let slice_heap: &bitvec::slice::BitSlice<u8, Lsb0> = &sbv;
assert_eq!(slice_heap.len(), 12);
}
#[test]
fn test_bitvec_spill_trigger_lsb0() {
let mut sbv: SmallBitVec<1, Lsb0> = SmallBitVec::new();
for _ in 0..8 {
sbv.push(true);
}
assert!(sbv.is_on_stack());
assert_eq!(sbv.len(), 8);
sbv.push(false); assert!(!sbv.is_on_stack());
assert_eq!(sbv.len(), 9);
assert_eq!(sbv.get(0), Some(true));
assert_eq!(sbv.get(8), Some(false));
}
#[test]
fn test_bitvec_spill_trigger_msb0() {
let mut sbv: SmallBitVec<1, Msb0> = SmallBitVec::new();
sbv.push(true); sbv.push(false); for _ in 0..6 {
sbv.push(true);
}
assert!(sbv.is_on_stack());
sbv.push(true); assert!(!sbv.is_on_stack());
assert_eq!(sbv.get(0), Some(true));
assert_eq!(sbv.get(1), Some(false));
}
#[test]
fn test_bitvec_any_storage_pop_set() {
let mut sbv: SmallBitVec<1, Lsb0> = SmallBitVec::new();
sbv.push(true);
sbv.push(false);
assert_eq!(sbv.pop(), Some(false));
sbv.set(0, false);
assert_eq!(sbv.get(0), Some(false));
for _ in 0..10 {
sbv.push(true);
}
assert!(!sbv.is_on_stack());
sbv.set(10, false);
assert_eq!(sbv.get(10), Some(false));
assert_eq!(sbv.pop(), Some(false));
}
#[test]
fn test_bitvec_traits_debug_default() {
let sbv: SmallBitVec<1, Lsb0> = SmallBitVec::default();
assert!(sbv.is_empty());
let mut sbv2 = SmallBitVec::<1, Lsb0>::new();
sbv2.push(true);
sbv2.push(false);
let debug = format!("{:?}", sbv2);
assert!(debug.contains("10"));
}
#[test]
fn test_bitvec_any_storage_pop_empty() {
let mut sbv: SmallBitVec<1, Lsb0> = SmallBitVec::new();
assert_eq!(sbv.pop(), None);
}
#[test]
fn test_bitvec_any_storage_get_none() {
let mut sbv: SmallBitVec<1, Lsb0> = SmallBitVec::new();
assert_eq!(sbv.get(10), None);
for _ in 0..10 {
sbv.push(true);
}
assert_eq!(sbv.get(100), None);
}
#[test]
fn test_bitvec_traits_debug_multi_byte() {
let mut sbv2: SmallBitVec<2, Lsb0> = SmallBitVec::new();
for _ in 0..16 {
sbv2.push(true);
}
let debug = format!("{:?}", sbv2);
assert!(debug.contains("_"));
}
#[test]
fn test_bitvec_traits_any_bitvec_impl() {
let mut sbv: SmallBitVec<1, Lsb0> = SmallBitVec::new();
sbv.push(true);
sbv.push(false);
let any: &dyn AnyBitVec = &sbv;
assert_eq!(any.len(), 2);
assert_eq!(any.get(0), Some(true));
assert_eq!(any.get(1), Some(false));
}
}
#[cfg(test)]
mod bitvec_coverage_tests {
use super::*;
use bitvec::prelude::Lsb0;
#[test]
fn test_any_bitvec_is_empty() {
struct MockAny;
impl AnyBitVec for MockAny {
fn len(&self) -> usize {
0
}
fn get(&self, _index: usize) -> Option<bool> {
None
}
}
let m = MockAny;
assert!(m.is_empty());
let mut b: BitVec<u8, Lsb0> = BitVec::new();
{
let any_b: &dyn AnyBitVec = &b;
assert_eq!(any_b.len(), 0);
}
b.push(true);
{
let any_b: &dyn AnyBitVec = &b;
assert_eq!(any_b.get(0), Some(true));
}
}
#[test]
fn test_small_bitvec_traits_and_heap() {
use core::ops::DerefMut;
use std::borrow::Borrow;
let mut sbv: SmallBitVec<1, Lsb0> = SmallBitVec::new();
sbv.push(true);
let any: &dyn AnyBitVec = &sbv;
assert_eq!(any.len(), 1);
assert_eq!(any.get(0), Some(true));
let borrowed: &bitvec::slice::BitSlice<u8, Lsb0> = sbv.borrow();
assert_eq!(borrowed.len(), 1);
let cloned_stack = sbv.clone();
assert_eq!(cloned_stack.len(), 1);
for _ in 0..10 {
sbv.push(false);
}
let mut_slice = sbv.deref_mut();
mut_slice.set(1, true);
let cloned_heap = sbv.clone();
assert_eq!(cloned_heap.len(), 11);
}
}