use super::chunk::Chunk;
use super::inner::BumpInner;
use alloc::alloc::{handle_alloc_error, Layout};
use core::cell::UnsafeCell;
use core::ptr::NonNull;
pub unsafe trait IntoLayout: Copy + Into<Layout> {}
pub struct GenericBump<L: IntoLayout>(UnsafeCell<BumpInner<L>>);
impl<L: IntoLayout> GenericBump<L> {
pub fn new(layout: L) -> Self {
Self(UnsafeCell::new(BumpInner::new(layout)))
}
fn inner(&self) -> &BumpInner<L> {
unsafe { &*self.0.get() }
}
pub fn layout(&self) -> Layout {
self.inner().layout()
}
pub fn allocate(&self, layout: Layout) -> Option<NonNull<[u8]>> {
unsafe { &mut *self.0.get() }.allocate(layout)
}
#[allow(clippy::mut_from_ref)]
#[must_use]
pub fn alloc_value<T>(&self, value: T) -> &mut T {
if let Ok(r) = self.try_alloc_value(value) {
return r;
}
if self.can_allocate(Layout::new::<T>()) {
handle_alloc_error(Chunk::full_layout(self.inner().layout()));
}
panic!("this allocator cannot allocate values of this type");
}
#[allow(clippy::mut_from_ref)]
pub fn try_alloc_value<T>(&self, value: T) -> Result<&mut T, T> {
let memory = if let Some(memory) = self.allocate(Layout::new::<T>()) {
memory.cast::<T>()
} else {
return Err(value);
};
unsafe {
memory.as_ptr().write(value);
}
Ok(unsafe { &mut *memory.as_ptr() })
}
pub fn can_allocate(&self, layout: Layout) -> bool {
let cl = Chunk::layout(self.inner().layout());
layout.size() <= cl.size() && layout.align() <= cl.align()
}
}