//! A simple id-based arena, similar to https://github.com/fitzgen/id-arena. //! We use our own version for more compact id's and to allow inherent impls //! on Ids. use std::{ fmt, ops::{Index, IndexMut}, hash::{Hash, Hasher}, marker::PhantomData, }; pub(crate) struct Id { idx: u32, _ty: PhantomData T>, } impl fmt::Debug for Id { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("Id").field(&self.idx).finish() } } impl Copy for Id {} impl Clone for Id { fn clone(&self) -> Id { *self } } impl PartialEq for Id { fn eq(&self, other: &Id) -> bool { self.idx == other.idx } } impl Eq for Id {} impl Hash for Id { fn hash(&self, h: &mut H) { self.idx.hash(h); } } #[derive(Debug, PartialEq, Eq)] pub(crate) struct Arena { data: Vec, } impl Default for Arena { fn default() -> Arena { Arena { data: Vec::new() } } } impl Arena { pub(crate) fn push(&mut self, value: T) -> Id { let id = self.data.len() as u32; self.data.push(value); Id { idx: id as u32, _ty: PhantomData, } } pub(crate) fn keys<'a>(&'a self) -> impl Iterator> + 'a { (0..(self.data.len() as u32)).into_iter().map(|idx| Id { idx, _ty: PhantomData, }) } pub(crate) fn items<'a>(&'a self) -> impl Iterator, &T)> + 'a { self.data.iter().enumerate().map(|(idx, item)| { let idx = idx as u32; ( Id { idx, _ty: PhantomData, }, item, ) }) } } impl Index> for Arena { type Output = T; fn index(&self, id: Id) -> &T { &self.data[id.idx as usize] } } impl IndexMut> for Arena { fn index_mut(&mut self, id: Id) -> &mut T { &mut self.data[id.idx as usize] } }