//! Yet another index-based arena. use std::{ fmt, iter::FromIterator, marker::PhantomData, ops::{Index, IndexMut}, }; pub mod map; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct RawId(u32); impl From for u32 { fn from(raw: RawId) -> u32 { raw.0 } } impl From for RawId { fn from(id: u32) -> RawId { RawId(id) } } impl fmt::Debug for RawId { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt(f) } } impl fmt::Display for RawId { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt(f) } } #[derive(Clone, PartialEq, Eq)] pub struct Arena { data: Vec, _ty: PhantomData, } impl fmt::Debug for Arena { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("Arena").field("len", &self.len()).field("data", &self.data).finish() } } #[macro_export] macro_rules! impl_arena_id { ($name:ident) => { impl $crate::ArenaId for $name { fn from_raw(raw: $crate::RawId) -> Self { $name(raw) } fn into_raw(self) -> $crate::RawId { self.0 } } }; } pub trait ArenaId { fn from_raw(raw: RawId) -> Self; fn into_raw(self) -> RawId; } impl Arena { pub const fn new() -> Arena { Arena { data: Vec::new(), _ty: PhantomData } } } impl Arena { pub fn len(&self) -> usize { self.data.len() } pub fn is_empty(&self) -> bool { self.data.is_empty() } pub fn alloc(&mut self, value: T) -> ID { let id = RawId(self.data.len() as u32); self.data.push(value); ID::from_raw(id) } pub fn iter(&self) -> impl Iterator + ExactSizeIterator { self.data.iter().enumerate().map(|(idx, value)| (ID::from_raw(RawId(idx as u32)), value)) } } impl Default for Arena { fn default() -> Arena { Arena { data: Vec::new(), _ty: PhantomData } } } impl Index for Arena { type Output = T; fn index(&self, idx: ID) -> &T { let idx = idx.into_raw().0 as usize; &self.data[idx] } } impl IndexMut for Arena { fn index_mut(&mut self, idx: ID) -> &mut T { let idx = idx.into_raw().0 as usize; &mut self.data[idx] } } impl FromIterator for Arena { fn from_iter(iter: I) -> Self where I: IntoIterator, { Arena { data: Vec::from_iter(iter), _ty: PhantomData } } }