use crate::common::{self, AllocHandle, ArenaBacking, ArenaError};
use std::cell::Cell;
use std::ops::Deref;
use std::ptr::NonNull;
use std::rc::Rc;
#[derive(Debug)]
pub struct Arena(InnerRef, ArenaBacking);
#[derive(Clone, Debug)]
pub struct InnerRef {
inner: Rc<Inner>,
}
#[derive(Debug)]
struct Inner {
head: NonNull<u8>,
pos: Cell<usize>,
cap: usize,
}
pub type Slice<T> = common::Slice<T, InnerRef>;
pub type SliceVec<T> = common::SliceVec<T, InnerRef>;
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);
Ok(Arena(
InnerRef {
inner: Rc::new(Inner { head, pos, cap }),
},
backing,
))
}
pub fn inner(&self) -> InnerRef {
self.0.clone()
}
pub fn clear(&self) -> Result<(), ArenaError> {
if Rc::strong_count(&self.inner) == 1 {
self.inner.pos.set(0);
Ok(())
} else {
Err(ArenaError::CannotClear)
}
}
}
impl Deref for Arena {
type Target = InnerRef;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Drop for Arena {
fn drop(&mut self) {
match self.1 {
ArenaBacking::MemoryMap => {
common::destroy_mapping(self.inner.head, self.inner.cap);
}
ArenaBacking::SystemAllocation => {
common::destroy_mapping_alloc(self.inner.head, self.inner.cap);
}
}
}
}
impl AllocHandle for InnerRef {
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)
}
}