use std::{marker, num, ptr};
use crate::{
alloc,
buffer::{
pool,
pool::{owners, state},
resident,
storage::regions,
},
};
pub(in crate::buffer::pool) struct Accounted;
#[derive(Debug)]
pub(in crate::buffer::pool) struct Any;
pub(in crate::buffer::pool) struct Block<K, S> {
base: Base<K>,
shape: super::Shape<K>,
state: marker::PhantomData<S>,
}
#[repr(transparent)]
#[derive(Debug)]
pub(super) struct Base<K>(ptr::NonNull<super::Header<K>>);
impl<K> Base<K> {
pub(super) const unsafe fn from_raw(raw: ptr::NonNull<super::Header<K>>) -> Self {
Self(raw)
}
pub(super) const fn as_raw(&self) -> ptr::NonNull<super::Header<K>> {
self.0
}
pub(super) unsafe fn slots(self) -> ptr::NonNull<super::Slot> {
unsafe { self.0.add(1).cast() }
}
pub(super) const unsafe fn publish<S>(self) -> Ptr<K, S> {
Ptr {
raw: self.0,
kind: marker::PhantomData,
}
}
}
impl<K> Clone for Base<K> {
fn clone(&self) -> Self {
*self
}
}
impl<K> Copy for Base<K> {}
impl<'d> Base<super::Resident<'d>> {
pub(super) unsafe fn accounts(self, slots: u32) -> ptr::NonNull<super::Accounts<'d>> {
unsafe { self.slots().add(slots as usize).cast() }
}
}
impl<K, S: state::State> Block<K, S> {
fn allocate(shape: super::Shape<K>) -> Result<Self, alloc::Exhausted> {
let layout = shape.allocation();
let block = unsafe { alloc::raw::try_new(layout, S::ZEROED) }?;
let base = unsafe { Base::from_raw(block) };
Ok(Self {
base,
shape,
state: marker::PhantomData,
})
}
fn initialize(&self) {
let header = super::Header::new(self.shape);
unsafe { self.base.as_raw().write(header) };
unsafe { super::Slot::initialize(self.base, self.shape.slots()) };
}
}
impl<L, S: state::State> Block<super::Plain<L>, S> {
fn init(self) -> Ptr<super::Plain<L>, S> {
self.initialize();
unsafe { self.base.publish() }
}
}
impl<L: Into<pool::Layout>, S: state::State> Block<super::Plain<L>, S> {
pub(in crate::buffer::pool) fn try_new(
public: L,
) -> Result<Ptr<super::Plain<L>, S>, alloc::Exhausted> {
Ok(Self::allocate(super::Shape::new(public))?.init())
}
}
impl<S: state::State> Block<super::Plain<pool::Layout>, S> {
pub(in crate::buffer::pool) fn try_seed(
public: pool::NonEmpty,
) -> Result<super::Seed<super::Plain<pool::Layout>, S>, alloc::Exhausted> {
let core = Self::try_new(public.into_layout())?;
Ok(unsafe { super::Seed::from_ptr(core) })
}
}
impl<S: state::State> Block<Accounted, S> {
pub(in crate::buffer::pool) fn try_seed<'d>(
public: pool::NonEmpty,
budget: resident::Budget<'d>,
) -> Result<super::Seed<super::Resident<'d>, S>, resident::AllocError> {
let core = Self::try_new(public.into(), budget)?;
Ok(unsafe { super::Seed::from_ptr(core) })
}
pub(in crate::buffer::pool) fn try_new<'d>(
tally: pool::Tally,
budget: resident::Budget<'d>,
) -> Result<Ptr<super::Resident<'d>, S>, resident::AllocError> {
let shape = super::Shape::try_new(tally).map_err(resident::AllocError::Layout)?;
let (layout, limit) = tally.into_parts();
let charge = budget
.try_charge(layout.bytes())
.map_err(resident::AllocError::Budget)?;
let block = Self::allocate(shape).map_err(resident::AllocError::Exhausted)?;
let slots = block.shape.slots();
block.initialize();
let base = unsafe { super::Accounts::initialize(block.base, slots, charge, limit) };
Ok(unsafe { base.publish() })
}
}
#[repr(transparent)]
#[derive(Debug)]
pub struct Ptr<K, S = state::Uninit> {
raw: ptr::NonNull<super::Header<K>>,
kind: marker::PhantomData<(K, S)>,
}
impl<K, S> Ptr<K, S> {
pub(super) const fn as_raw(&self) -> ptr::NonNull<super::Header<K>> {
self.raw
}
pub(super) fn header(&self) -> &super::Header<K> {
unsafe { self.raw.as_ref() }
}
pub(in crate::buffer::pool) fn capacity(self) -> num::NonZero<u32> {
self.header().capacity()
}
pub(in crate::buffer::pool) fn slots(self) -> usize {
self.header().slots() as usize
}
pub(in crate::buffer::pool) fn available(self) -> usize {
self.header().available.get() as usize
}
pub(in crate::buffer::pool) const fn erase_state(self) -> Ptr<K, pool::Frozen> {
Ptr {
raw: self.raw,
kind: marker::PhantomData,
}
}
pub(in crate::buffer) unsafe fn deallocate(self) {
unsafe { alloc::raw::dealloc(self.header().allocation(), self.raw) };
}
}
impl<'d, S> Ptr<super::Resident<'d>, S> {
pub(in crate::buffer) unsafe fn uncharge(self) {
unsafe { owners::Accounts::release(self) };
}
pub(super) const fn base(self) -> Base<super::Resident<'d>> {
Base(self.raw)
}
}
impl<K, S> Clone for Ptr<K, S> {
fn clone(&self) -> Self {
*self
}
}
impl<K, S> Copy for Ptr<K, S> {}
const _: () = {
assert!(size_of::<Base<super::Plain>>() == size_of::<usize>());
assert!(size_of::<Base<Accounted>>() == size_of::<usize>());
assert!(size_of::<Base<super::Resident<'static>>>() == size_of::<usize>());
assert!(
size_of::<Block<super::Plain<pool::Fixed<1, 1>>, state::Uninit>>()
== 3 * size_of::<usize>()
);
assert!(
size_of::<Block<super::Plain<pool::Layout>, state::Uninit>>() == 3 * size_of::<usize>()
);
assert!(
size_of::<Block<super::Plain<pool::Width<1>>, state::Uninit>>() == 3 * size_of::<usize>()
);
assert!(size_of::<Block<Accounted, state::Uninit>>() == 3 * size_of::<usize>());
assert!(size_of::<Ptr<super::Plain>>() == size_of::<usize>());
assert!(size_of::<Ptr<super::Resident<'static>>>() == size_of::<usize>());
assert!(size_of::<Ptr<Accounted>>() == size_of::<usize>());
};
pub(super) struct Binding<K> {
pub(super) slots: super::Ptr<K, super::Any>,
pub(super) key: super::Key,
}
impl<K, S> Ptr<K, S> {
pub(super) fn is_unique(&self, key: super::Key) -> bool {
use crate::mem::raw::Edge;
self.slot(key).is_unique()
}
pub(super) fn data(self, key: super::Key) -> *mut u8 {
let header = self.header();
unsafe {
self.as_raw().as_ptr().cast::<u8>().add(
header.data_offset().get() + key.get() as usize * header.capacity().get() as usize,
)
}
}
pub(super) fn owner(self, key: super::Key) -> ptr::NonNull<regions::Prefix> {
self.ptr(key).cast()
}
pub(super) fn ptr(self, key: super::Key) -> ptr::NonNull<super::Slot> {
unsafe {
super::Base::from_raw(self.as_raw())
.slots()
.add(key.get() as usize)
}
}
pub(super) fn slot(&self, key: super::Key) -> &super::Slot {
unsafe { self.ptr(key).as_ref() }
}
}
impl<K> Ptr<K, Any> {
pub(super) unsafe fn from_owner(owner: ptr::NonNull<()>) -> Binding<K> {
let slot = owner.cast::<super::Slot>();
let key = unsafe { slot.as_ref() }.key();
let offset = size_of::<super::Header>() + key.get() as usize * size_of::<super::Slot>();
let raw = unsafe { slot.cast::<u8>().sub(offset).cast() };
let base = unsafe { super::Base::from_raw(raw) };
let core = unsafe { base.publish() };
Binding { slots: core, key }
}
}