use crate::common::{self, AllocHandle, ArenaBacking, ArenaError};
use std::cell::Cell;
use std::ptr::NonNull;
#[derive(Debug)]
pub struct Arena {
head: NonNull<u8>,
pos: Cell<usize>,
cap: usize,
backing: ArenaBacking,
locked: Cell<bool>,
}
#[derive(Debug)]
pub struct ArenaToken<'a> {
inner: &'a Arena,
}
#[derive(Debug, Clone)]
pub struct ArenaHandle<'a>(&'a ArenaToken<'a>);
pub type Slice<'a, T> = common::Slice<T, ArenaHandle<'a>>;
pub type SliceVec<'a, T> = common::SliceVec<T, ArenaHandle<'a>>;
impl Arena {
pub fn init_capacity(backing: ArenaBacking, cap: usize) -> Result<Self, ArenaError> {
let head = NonNull::new(match backing {
ArenaBacking::MemoryMap => common::create_mapping(cap),
ArenaBacking::SystemAllocation => common::create_mapping_alloc(cap),
})
.ok_or(ArenaError::AllocationFailed)?;
let pos = Cell::new(0);
let locked = Cell::new(false);
Ok(Arena {
head,
pos,
cap,
backing,
locked,
})
}
pub fn generation_token<'a>(&'a self) -> Result<ArenaToken<'a>, ArenaError> {
if self.locked.get() {
Err(ArenaError::AlreadyLocked)
} else {
self.locked.set(true);
Ok(ArenaToken { inner: self })
}
}
}
impl Drop for Arena {
fn drop(&mut self) {
match self.backing {
ArenaBacking::MemoryMap => {
common::destroy_mapping(self.head, self.cap);
}
ArenaBacking::SystemAllocation => {
common::destroy_mapping_alloc(self.head, self.cap);
}
}
}
}
impl<'a> ArenaToken<'a> {
pub fn weak(&'a self) -> ArenaHandle<'a> {
ArenaHandle(self)
}
}
impl<'a> AllocHandle for ArenaToken<'a> {
fn allocate<T>(&self, count: usize) -> NonNull<T> {
common::allocate_inner(self.inner.head, &self.inner.pos, self.inner.cap, count)
}
fn allocate_or_extend<T>(&self, ptr: NonNull<T>, old_count: usize, count: usize) -> NonNull<T> {
common::allocate_or_extend_inner(
self.inner.head,
&self.inner.pos,
self.inner.cap,
ptr,
old_count,
count)
}
}
impl<'a> AllocHandle for ArenaHandle<'a> {
fn allocate<T>(&self, count: usize) -> NonNull<T> {
self.0.allocate(count)
}
fn allocate_or_extend<T>(&self, ptr: NonNull<T>, old_count: usize, count: usize) -> NonNull<T> {
self.0.allocate_or_extend(ptr, old_count, count)
}
}
impl<'a> Drop for ArenaToken<'a> {
fn drop(&mut self) {
self.inner.pos.set(0);
self.inner.locked.set(false);
}
}