use std::{mem, num, ptr};
use storage::alloc;
use crate::buffer::{resident, storage, storage::regions};
#[repr(transparent)]
#[derive(Debug)]
pub(in crate::buffer) struct Heap<P: crate::buffer::raw::Policy = ()> {
pointer: ptr::NonNull<crate::buffer::raw::Header<P>>,
}
impl<P: crate::buffer::raw::Policy> Heap<P> {
pub(in crate::buffer) fn try_new(
seed: P::Seed,
capacity: num::NonZero<u32>,
) -> Result<Self, alloc::Error<P::Failure>> {
let debit = P::try_acquire(crate::buffer::raw::Debit::new(seed, capacity))
.map_err(alloc::Error::Policy)?;
Self::try_charged(debit).map_err(alloc::Error::Allocation)
}
pub(in crate::buffer) fn try_charged(
debit: P::Charge,
) -> Result<Self, crate::alloc::Exhausted> {
use crate::buffer::raw::Token as _;
let capacity = debit.debit().amount();
let layout = crate::buffer::raw::Header::<P>::layout(capacity);
let pointer = unsafe { crate::alloc::raw::try_new(layout, false)? };
let (policy, capacity) = debit.commit();
unsafe {
pointer.write(crate::buffer::raw::Header {
prefix: regions::Prefix::one(capacity),
policy,
});
}
Ok(Self { pointer })
}
pub(in crate::buffer) fn capacity(&self) -> num::NonZero<u32> {
unsafe { self.pointer.as_ref() }.capacity()
}
pub(in crate::buffer) fn try_reserve(
&mut self,
target: num::NonZero<u32>,
) -> Result<(), alloc::Error<P::Failure>> {
let header = unsafe { self.pointer.as_ref() };
let Some(amount) = num::NonZero::new(target.get().saturating_sub(header.capacity().get()))
else {
return Ok(());
};
let debit = P::try_acquire(crate::buffer::raw::Debit::grow(&header.policy, amount))
.map_err(alloc::Error::Policy)?;
self.pointer =
unsafe { crate::buffer::raw::Growth::try_resize(self.pointer, target, debit) }
.map_err(alloc::Error::Allocation)?;
Ok(())
}
}
impl<P: crate::buffer::raw::Policy> Heap<P> {
pub(in crate::buffer) fn as_ptr(&self) -> *const mem::MaybeUninit<u8> {
crate::buffer::raw::Header::data(self.pointer)
.cast()
.as_ptr()
}
pub(in crate::buffer) fn as_mut_ptr(&mut self) -> *mut mem::MaybeUninit<u8> {
crate::buffer::raw::Header::data(self.pointer)
.cast()
.as_ptr()
}
pub(in crate::buffer) fn into_shared(self) -> crate::buffer::raw::Rc<P> {
let this = mem::ManuallyDrop::new(self);
unsafe { crate::buffer::raw::Rc::from_raw(this.pointer) }
}
}
impl<P: crate::buffer::raw::Policy> Drop for Heap<P> {
fn drop(&mut self) {
unsafe { crate::buffer::raw::Header::destroy(self.pointer) };
}
}
const _: () = assert!(size_of::<Heap<()>>() == size_of::<ptr::NonNull<()>>());
const _: () = assert!(size_of::<Option<Heap<()>>>() == size_of::<ptr::NonNull<()>>());
impl<'d> Heap<resident::Lease<'d>> {
pub(in crate::buffer) fn try_compact(
&mut self,
capacity: num::NonZero<u32>,
) -> Result<(), crate::alloc::Exhausted> {
let current = self.capacity();
if capacity == current {
return Ok(());
}
let old = crate::buffer::raw::Header::<resident::Lease<'d>>::layout(current);
let new = crate::buffer::raw::Header::<resident::Lease<'d>>::layout(capacity);
self.pointer = unsafe { crate::alloc::raw::resize(old, self.pointer.cast(), new)? }.cast();
let header = unsafe { self.pointer.as_mut() };
unsafe { header.set_capacity(capacity) };
resident::Domain::shrink(&mut header.policy, capacity);
Ok(())
}
}