use std::fmt;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::ops::{Index, IndexMut};
pub struct Idx<T> {
raw: u32,
_ty: PhantomData<fn() -> T>,
}
impl<T> Idx<T> {
#[inline]
pub(crate) fn from_raw(raw: u32) -> Self {
Self {
raw,
_ty: PhantomData,
}
}
#[inline]
fn from_index(index: usize) -> Self {
let raw = u32::try_from(index).expect("ctree arena exceeded u32 nodes");
Self::from_raw(raw)
}
#[inline]
pub fn index(self) -> usize {
self.raw as usize
}
}
impl<T> Clone for Idx<T> {
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for Idx<T> {}
impl<T> PartialEq for Idx<T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.raw == other.raw
}
}
impl<T> Eq for Idx<T> {}
impl<T> Hash for Idx<T> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.raw.hash(state);
}
}
impl<T> fmt::Debug for Idx<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Idx").field(&self.raw).finish()
}
}
#[derive(Debug)]
pub struct Arena<T> {
data: Vec<T>,
}
impl<T> Arena<T> {
#[inline]
pub fn new() -> Self {
Self { data: Vec::new() }
}
#[inline]
pub fn alloc(&mut self, value: T) -> Idx<T> {
let idx = Idx::from_index(self.data.len());
self.data.push(value);
idx
}
#[inline]
pub fn len(&self) -> usize {
self.data.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn iter(&self) -> impl ExactSizeIterator<Item = (Idx<T>, &T)> {
self.data
.iter()
.enumerate()
.map(|(i, v)| (Idx::from_index(i), v))
}
}
impl<T> Default for Arena<T> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<T> Index<Idx<T>> for Arena<T> {
type Output = T;
#[inline]
fn index(&self, idx: Idx<T>) -> &T {
&self.data[idx.index()]
}
}
impl<T> IndexMut<Idx<T>> for Arena<T> {
#[inline]
fn index_mut(&mut self, idx: Idx<T>) -> &mut T {
&mut self.data[idx.index()]
}
}
#[cfg(test)]
mod tests {
use assert2::assert;
use super::*;
#[test]
fn alloc_returns_stable_handles() {
let mut arena = Arena::new();
let a = arena.alloc("a");
let b = arena.alloc("b");
let c = arena.alloc("c");
assert!(arena[a] == "a");
assert!(arena[b] == "b");
assert!(arena[c] == "c");
assert!(a != b);
assert!(b != c);
assert!(arena.len() == 3);
}
#[test]
fn iter_yields_all_in_order() {
let mut arena = Arena::new();
let ids: Vec<_> = [10, 20, 30].into_iter().map(|v| arena.alloc(v)).collect();
let seen: Vec<_> = arena.iter().collect();
assert!(seen.len() == 3);
for (expected_id, (got_id, &got_val)) in ids.iter().zip(seen) {
assert!(*expected_id == got_id);
assert!(arena[got_id] == got_val);
}
}
#[test]
fn handle_is_send_and_sync_even_when_payload_is_not() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<Idx<*const ()>>();
}
}