use std::cell;
use o3::{alloc, alloc::BoxSliceExt as _, base::cell::region, buffer::resident};
use crate::driver::storage::Exhausted;
pub(crate) struct Arena {
slots: Box<[cell::UnsafeCell<resident::Domain>]>,
next: cell::Cell<usize>,
}
#[derive(Clone, Copy)]
pub struct Alloc<'d> {
arena: &'d Arena,
proof: region::Identity<'d>,
}
impl Arena {
pub(in crate::driver) fn try_new(domains: usize) -> Result<Self, alloc::Error> {
Ok(Self {
slots: Box::try_default(domains)?,
next: cell::Cell::new(0),
})
}
pub(in crate::driver) fn enter<'d>(
&'d mut self,
token: ®ion::Token<region::Identity<'d>>,
) -> Alloc<'d> {
self.next.set(0);
Alloc {
arena: self,
proof: token.proof(),
}
}
}
impl<'d> Alloc<'d> {
pub fn try_budget(self, capacity: usize) -> Result<resident::Budget<'d>, Exhausted> {
let index = self.arena.next.get();
let Some(slot) = self.arena.slots.get(index) else {
return Err(Exhausted::Domains {
capacity: self.arena.slots.len(),
});
};
self.arena.next.set(index + 1);
let domain: &'d mut resident::Domain = unsafe { &mut *slot.get() };
domain
.try_budget(capacity, self.proof)
.map_err(|cause| Exhausted::Retained { index, cause })
}
}
const _: () = assert!(size_of::<Alloc<'static>>() == size_of::<usize>());