use crate::{LassoError, LassoErrorKind, LassoResult};
use alloc::alloc::{alloc, dealloc, Layout};
use core::{
mem::{align_of, size_of},
num::NonZeroUsize,
ptr::NonNull,
slice,
};
pub(super) struct Bucket {
index: usize,
items: NonNull<u8>,
capacity: NonZeroUsize,
}
impl Bucket {
pub(crate) fn with_capacity(capacity: NonZeroUsize) -> LassoResult<Self> {
unsafe {
debug_assert!(Layout::from_size_align(
size_of::<u8>() * capacity.get(),
align_of::<u8>(),
)
.is_ok());
let layout = Layout::from_size_align_unchecked(
size_of::<u8>() * capacity.get(),
align_of::<u8>(),
);
let items = NonNull::new(alloc(layout))
.ok_or_else(|| LassoError::new(LassoErrorKind::FailedAllocation))?
.cast();
Ok(Self {
index: 0,
capacity,
items,
})
}
}
pub(crate) fn free_elements(&self) -> usize {
self.capacity.get() - self.index
}
pub(crate) fn is_full(&self) -> bool {
self.index == self.capacity.get()
}
pub(crate) fn clear(&mut self) {
self.index = 0;
}
pub(crate) unsafe fn push_slice(&mut self, slice: &[u8]) -> &'static str {
debug_assert!(!self.is_full());
debug_assert!(slice.len() <= self.capacity.get() - self.index);
unsafe {
let ptr = self.items.as_ptr().add(self.index);
let target = slice::from_raw_parts_mut(ptr, slice.len());
target.copy_from_slice(slice);
self.index += slice.len();
core::str::from_utf8_unchecked(target)
}
}
}
impl Drop for Bucket {
fn drop(&mut self) {
unsafe {
let items = self.items.as_ptr();
debug_assert!(Layout::from_size_align(
size_of::<u8>() * self.capacity.get(),
align_of::<u8>(),
)
.is_ok());
dealloc(
items,
Layout::from_size_align_unchecked(
size_of::<u8>() * self.capacity.get(),
align_of::<u8>(),
),
);
}
}
}
unsafe impl Send for Bucket {}
unsafe impl Sync for Bucket {}