#![no_std]
#![doc = include_str!("../README.md")]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
)]
mod errors;
mod iter;
mod tagged_len;
pub use errors::IndexOutOfBounds;
pub use iter::Iter;
use core::{
cell::UnsafeCell,
fmt::{self, Debug},
iter::IntoIterator,
ops::{Index, IndexMut, Range, RangeFrom, RangeFull, RangeTo},
panic::RefUnwindSafe,
ptr, slice,
};
use tagged_len::TaggedLen;
#[repr(transparent)]
pub struct BitSlice {
inner: [Inner],
}
type Inner = UnsafeCell<()>;
impl BitSlice {
#[must_use]
pub const fn new(bytes: &[u8]) -> &Self {
Self::new_with_offsets(bytes, 0, 0)
}
#[inline]
const fn new_with_offsets(bytes: &[u8], head_offset: usize, tail_offset: usize) -> &Self {
let len = TaggedLen::new(bytes.len(), head_offset, tail_offset).encode();
let slice = unsafe { slice::from_raw_parts::<Inner>(bytes.as_ptr().cast(), len) };
unsafe { &*(ptr::from_ref(slice) as *const Self) }
}
#[must_use]
pub const fn new_mut(bytes: &mut [u8]) -> &mut Self {
Self::new_mut_with_offsets(bytes, 0, 0)
}
#[must_use]
const fn new_mut_with_offsets(
bytes: &mut [u8],
head_offset: usize,
tail_offset: usize,
) -> &mut Self {
let len = TaggedLen::new(bytes.len(), head_offset, tail_offset).encode();
let slice = unsafe { slice::from_raw_parts_mut::<Inner>(bytes.as_mut_ptr().cast(), len) };
unsafe { &mut *(ptr::from_mut(slice) as *mut Self) }
}
#[must_use]
const fn as_raw_bytes(&self) -> &[u8] {
let ptr = self.inner.as_ptr();
let len = self.tagged_len().byte_len();
unsafe { slice::from_raw_parts(ptr.cast(), len) }
}
#[must_use]
const fn as_mut_raw_bytes(&mut self) -> &mut [u8] {
let ptr = self.inner.as_mut_ptr();
let len = self.tagged_len().byte_len();
unsafe { slice::from_raw_parts_mut(ptr.cast(), len) }
}
const fn tagged_len(&self) -> TaggedLen {
TaggedLen::decode(self.inner.len())
}
pub const fn len(&self) -> usize {
self.tagged_len().bit_len()
}
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn iter(&self) -> Iter<'_> {
Iter::new(self)
}
pub const fn first(&self) -> Option<bool> {
match self.get_bit(0) {
Ok(bit) => Some(bit),
Err(_) => None,
}
}
pub const fn get_bit(&self, index: usize) -> Result<bool, IndexOutOfBounds> {
match self.tagged_len().offset_and_mask(index) {
Ok((offset, mask)) => Ok(self.as_raw_bytes()[offset] & mask != 0),
Err(e) => Err(e),
}
}
pub const fn get_slice(&self, bits: Range<usize>) -> Result<&Self, IndexOutOfBounds> {
match self.tagged_len().slice(bits) {
Ok((len, offset)) => {
let tail = self.as_raw_bytes().split_at(offset).1;
let bytes = tail.split_at(len.byte_len()).0;
Ok(Self::new_with_offsets(
bytes,
len.head_offset(),
len.tail_offset(),
))
}
Err(e) => Err(e),
}
}
pub const fn get_mut_slice(
&mut self,
bits: Range<usize>,
) -> Result<&mut Self, IndexOutOfBounds> {
match self.tagged_len().slice(bits) {
Ok((len, offset)) => {
let tail = self.as_mut_raw_bytes().split_at_mut(offset).1;
let bytes = tail.split_at_mut(len.byte_len()).0;
Ok(Self::new_mut_with_offsets(
bytes,
len.head_offset(),
len.tail_offset(),
))
}
Err(e) => Err(e),
}
}
pub const fn set_bit(&mut self, index: usize, value: bool) -> Result<(), IndexOutOfBounds> {
if let Err(e) = self.replace_bit(index, value) {
return Err(e);
}
Ok(())
}
pub const fn replace_bit(
&mut self,
index: usize,
value: bool,
) -> Result<bool, IndexOutOfBounds> {
match self.tagged_len().offset_and_mask(index) {
Ok((offset, mask)) => {
let orig = self.as_raw_bytes()[offset] & mask != 0;
if value {
self.as_mut_raw_bytes()[offset] |= mask;
} else {
self.as_mut_raw_bytes()[offset] &= !mask;
}
Ok(orig)
}
Err(e) => Err(e),
}
}
pub const fn split_first(&self) -> Option<(bool, &Self)> {
match (self.first(), self.get_slice(1..self.len())) {
(Some(bit), Ok(rest)) => Some((bit, rest)),
_ => None,
}
}
}
impl Debug for BitSlice {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "BitSlice([")?;
for bit in self {
write!(f, "{}", u8::from(bit))?;
}
write!(f, "])")
}
}
impl<'a> From<&'a [u8]> for &'a BitSlice {
fn from(bytes: &'a [u8]) -> Self {
BitSlice::new(bytes)
}
}
impl<'a> From<&'a mut [u8]> for &'a mut BitSlice {
fn from(bytes: &'a mut [u8]) -> Self {
BitSlice::new_mut(bytes)
}
}
impl Index<usize> for BitSlice {
type Output = bool;
fn index(&self, index: usize) -> &bool {
if self.get_bit(index).expect("index out of bounds") {
&true
} else {
&false
}
}
}
impl Index<Range<usize>> for BitSlice {
type Output = Self;
fn index(&self, range: Range<usize>) -> &Self {
self.get_slice(range).expect("index out of bounds")
}
}
impl Index<RangeFull> for BitSlice {
type Output = Self;
fn index(&self, _range: RangeFull) -> &Self {
self
}
}
impl Index<RangeFrom<usize>> for BitSlice {
type Output = Self;
fn index(&self, range: RangeFrom<usize>) -> &Self {
self.get_slice(range.start..self.len())
.expect("index out of bounds")
}
}
impl Index<RangeTo<usize>> for BitSlice {
type Output = Self;
fn index(&self, range: RangeTo<usize>) -> &Self {
self.get_slice(0..range.end).expect("index out of bounds")
}
}
impl IndexMut<Range<usize>> for BitSlice {
fn index_mut(&mut self, range: Range<usize>) -> &mut Self {
self.get_mut_slice(range).expect("index out of bounds")
}
}
impl IndexMut<RangeFull> for BitSlice {
fn index_mut(&mut self, _range: RangeFull) -> &mut Self {
self
}
}
impl IndexMut<RangeFrom<usize>> for BitSlice {
fn index_mut(&mut self, range: RangeFrom<usize>) -> &mut Self {
self.get_mut_slice(range.start..self.len())
.expect("index out of bounds")
}
}
impl IndexMut<RangeTo<usize>> for BitSlice {
fn index_mut(&mut self, range: RangeTo<usize>) -> &mut Self {
self.get_mut_slice(0..range.end)
.expect("index out of bounds")
}
}
impl<'a> IntoIterator for &'a BitSlice {
type Item = bool;
type IntoIter = Iter<'a>;
fn into_iter(self) -> Iter<'a> {
self.iter()
}
}
impl RefUnwindSafe for BitSlice {}
#[cfg(test)]
mod tests {
use crate::BitSlice;
const BYTES: [u8; 2] = [0xa0, 0x0a];
#[test]
fn as_raw_bytes() {
assert_eq!(BitSlice::new(&BYTES).as_raw_bytes(), BYTES);
}
#[test]
fn as_mut_raw_bytes() {
let mut bytes = BYTES;
let bits = BitSlice::new_mut(&mut bytes);
assert_eq!(bits.as_mut_raw_bytes(), BYTES);
}
}