bit-byte-bit 0.2.2

Implements a bit string using a collection of bytes.
Documentation
use std::{alloc, ptr, slice};
use std::alloc::Layout;
use std::ops::Deref;
use std::ptr::NonNull;


pub(crate) struct RawBytes {
    pub(crate) cap: usize,
    pub(crate) bytes: NonNull<u8>,
    pub(crate) nbytes: usize
}

impl RawBytes {
    pub fn as_ptr_const(&self) -> *const u8 { self.bytes.as_ptr().cast_const() }

    pub fn as_ptr_mut(&self) -> *mut u8 { self.bytes.as_ptr() }

    pub fn expand_to(&mut self, nbytes: usize) {
        let new_layout = Layout::array::<u8>(nbytes).unwrap();

        assert!(new_layout.size() <= isize::MAX as usize, "Allocation too large");

        let pointer = if self.cap == 0 {
            unsafe { alloc::alloc(new_layout) }
        } else {
            let old_layout = Layout::array::<u8>(self.cap).unwrap();
            let old_pointer = self.bytes.as_ptr();

            unsafe { alloc::realloc(old_pointer, old_layout, new_layout.size()) }
        };

        self.bytes = match NonNull::new(pointer) {
            Some(p) => p,
            None => alloc::handle_alloc_error(new_layout)
        };

        self.cap = nbytes;
    }

    pub fn shift_right(&mut self, end: usize, mask: u8, up: usize, down: usize) {
        unsafe {
            let pointer = self.bytes.as_ptr();

            for i in 0..(end - 1) {
                *pointer.add(i) >>= down;
                *pointer.add(i) |= (*pointer.add(i + 1) & mask) << up;
            }

            *pointer.add(end - 1) >>= down;
        }
    }

    pub fn shift_right_from(&mut self, start: usize, end: usize, mask: u8, up: usize, down: usize) {
        unsafe {
            let pointer = self.bytes.as_ptr();

            for i in start..end {
                *pointer.add(i - 1) |= (*pointer.add(i) & mask) << up;
                *pointer.add(i) >>= down;
            }
        }
    }

    pub fn shrink_to(&mut self, nbytes: usize) {
        if self.cap <= nbytes { return; }

        let old_layout = Layout::array::<u8>(self.cap).unwrap();
        let old_pointer = self.bytes.as_ptr();

        unsafe {
            for i in nbytes..self.nbytes { ptr::read(old_pointer.add(i)); }

            if nbytes == 0 {
                alloc::dealloc(old_pointer, old_layout);
                self.bytes = NonNull::dangling();
            } else {
                let new_layout = Layout::array::<u8>(nbytes).unwrap();
                let pointer = alloc::realloc(old_pointer, old_layout, new_layout.size());

                self.bytes = match NonNull::new(pointer) {
                    Some(p) => p,
                    None => alloc::handle_alloc_error(new_layout)
                };
            }
        }

        self.cap = nbytes;
        self.nbytes = nbytes;
    }
}

impl Deref for RawBytes {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        unsafe { slice::from_raw_parts(self.as_ptr_const(), self.nbytes) }
    }
}

impl Drop for RawBytes {
    fn drop(&mut self) {

        if self.cap != 0 {
            unsafe {
                alloc::dealloc(self.bytes.as_ptr(), Layout::array::<u8>(self.cap).unwrap());
            }
        }
    }
}

unsafe impl Send for RawBytes {}

unsafe impl Sync for RawBytes {}