use std::{cell, ptr};
use crate::{
buffer::{
resident,
storage::{
provided,
provided::{account, arena},
},
},
mem::rc,
};
#[repr(transparent)]
#[derive(Default)]
pub(super) struct Counter(cell::Cell<u32>);
pub(in crate::buffer) struct Charge<'d> {
entry: ptr::NonNull<arena::Entry<'d>>,
pub(super) count: cell::Cell<crate::mem::raw::Live>,
value: resident::Charge<'d>,
}
impl<'d> Charge<'d> {
pub(super) fn try_new(
owner: &provided::Owner<'d>,
budget: resident::Budget<'d>,
) -> Result<Self, account::Cause> {
let entry = owner.entry;
let domain = unsafe { entry.as_ref() }.domain;
let count = domain.accounted.0.get();
let limit = domain.limit;
if count >= limit {
return Err(account::Cause::Exhausted { count, limit });
}
let value = budget
.try_charge(unsafe { arena::Entry::resident(entry) } as usize)
.map_err(account::Cause::Budget)?;
domain.accounted.0.set(count + 1);
Ok(Self {
entry,
count: cell::Cell::new(crate::mem::raw::Live::ONE),
value,
})
}
pub(super) const fn entry(&self) -> ptr::NonNull<arena::Entry<'d>> {
self.entry
}
pub(super) fn budget(&self) -> resident::Budget<'d> {
self.value.budget()
}
pub(in crate::buffer) const fn resident(&self) -> usize {
self.value.capacity()
}
pub(super) fn try_retain(&self) -> Result<(), rc::Error> {
let next = self.count.get().try_retain()?;
self.count.set(next);
Ok(())
}
}
impl Drop for Charge<'_> {
fn drop(&mut self) {
let domain = unsafe { self.entry.as_ref() }.domain;
domain.accounted.0.set(domain.accounted.0.get() - 1);
}
}
const _: () = {
assert!(size_of::<Charge<'_>>() == 4 * size_of::<usize>());
assert!(size_of::<Option<Charge<'_>>>() == size_of::<Charge<'_>>());
};