use std::fmt::Debug;
use std::hash::Hash;
use std::hash::Hasher;
use std::marker::PhantomData;
use std::num::NonZeroU32;
use std::ops::Index;
use std::ops::IndexMut;
pub struct Handle<T> {
index: NonZeroU32,
_phantom: PhantomData<T>,
}
impl<T> Handle<T> {
fn new(index: NonZeroU32) -> Handle<T> {
Handle {
index,
_phantom: PhantomData,
}
}
#[inline(always)]
fn as_usize(self) -> usize {
self.index.get() as usize
}
}
impl<T> Clone for Handle<T> {
fn clone(&self) -> Handle<T> {
Handle::new(self.index)
}
}
impl<T> Copy for Handle<T> {}
impl<T> Debug for Handle<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("Handle")
.field("index", &self.index)
.finish()
}
}
impl<T> Eq for Handle<T> {}
impl<T> Hash for Handle<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.index.hash(state);
}
}
impl<T> Ord for Handle<T> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.index.cmp(&other.index)
}
}
impl<T> PartialEq for Handle<T> {
fn eq(&self, other: &Self) -> bool {
self.index == other.index
}
}
impl<T> PartialOrd for Handle<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.index.partial_cmp(&other.index)
}
}
pub struct Arena<T> {
items: Vec<T>,
}
impl<T> Arena<T> {
pub fn new() -> Arena<T> {
Arena { items: Vec::new() }
}
pub fn add(&mut self, item: T) -> Handle<T> {
let index = self.items.len() as u32;
self.items.push(item);
Handle::new(unsafe { NonZeroU32::new_unchecked(index + 1) })
}
pub fn get(&self, handle: Handle<T>) -> &T {
&self.items[handle.as_usize() - 1]
}
pub fn get_mut(&mut self, handle: Handle<T>) -> &mut T {
&mut self.items[handle.as_usize() - 1]
}
pub fn iter_handles(&self) -> impl Iterator<Item = Handle<T>> {
(1..=self.items.len())
.into_iter()
.map(|index| Handle::new(unsafe { NonZeroU32::new_unchecked(index as u32) }))
}
}
pub struct SupplementalArena<H, T> {
items: Vec<T>,
_phantom: PhantomData<H>,
}
impl<H, T> SupplementalArena<H, T> {
pub fn new() -> SupplementalArena<H, T> {
SupplementalArena {
items: Vec::new(),
_phantom: PhantomData,
}
}
pub fn with_capacity(arena: &Arena<H>) -> SupplementalArena<H, T> {
SupplementalArena {
items: Vec::with_capacity(arena.items.len()),
_phantom: PhantomData,
}
}
pub fn get(&self, handle: Handle<H>) -> Option<&T> {
self.items.get(handle.as_usize() - 1)
}
pub fn get_mut(&mut self, handle: Handle<H>) -> Option<&mut T> {
self.items.get_mut(handle.as_usize() - 1)
}
}
impl<H, T> SupplementalArena<H, T>
where
T: Default,
{
pub fn get_mut_or_default(&mut self, handle: Handle<H>) -> &mut T {
let index = handle.as_usize();
if self.items.len() < index {
self.items.resize_with(index, || T::default());
}
unsafe { self.items.get_unchecked_mut(index - 1) }
}
}
impl<H, T> Default for SupplementalArena<H, T> {
fn default() -> SupplementalArena<H, T> {
SupplementalArena::new()
}
}
impl<H, T> Index<Handle<H>> for SupplementalArena<H, T> {
type Output = T;
fn index(&self, handle: Handle<H>) -> &T {
&self.items[handle.as_usize() - 1]
}
}
impl<H, T> IndexMut<Handle<H>> for SupplementalArena<H, T>
where
T: Default,
{
fn index_mut(&mut self, handle: Handle<H>) -> &mut T {
self.get_mut_or_default(handle)
}
}