use std::fmt::{Debug, Formatter}; use core::hash::Hash; use core::marker::PhantomData; pub struct Id { // Not actually a signed index into the heap. But the index is set to -1 if // we don't know an ID yet. This is checked during debug mode. pub(crate) index: i32, _phantom: PhantomData, } impl Id { #[inline] pub(crate) fn new_invalid() -> Self { Self{ index: -1, _phantom: Default::default() } } #[inline] pub(crate) fn new(index: i32) -> Self { Self{ index, _phantom: Default::default() } } #[inline] pub(crate) fn is_invalid(&self) -> bool { self.index < 0 } } #[derive(Debug)] pub(crate) struct Arena { store: Vec, } ////////////////////////////////// impl Debug for Id { fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { f.debug_struct("Id").field("index", &self.index).finish() } } impl Clone for Id { fn clone(&self) -> Self { *self } } impl Copy for Id {} impl PartialEq for Id { fn eq(&self, other: &Self) -> bool { self.index.eq(&other.index) } } impl Eq for Id {} impl Hash for Id { fn hash(&self, h: &mut H) { self.index.hash(h); } } impl Arena { pub fn new() -> Self { Self { store: vec![] } } pub fn alloc_with_id(&mut self, f: impl FnOnce(Id) -> T) -> Id { // Lets keep this a runtime assert. assert!(self.store.len() < i32::max_value() as usize, "Arena out of capacity"); let id = Id::new(self.store.len() as i32); self.store.push(f(id)); id } // Compiler-internal direct retrieval pub(crate) fn get_id(&self, idx: usize) -> Id { debug_assert!(idx < self.store.len()); return Id::new(idx as i32); } pub fn iter(&self) -> impl Iterator { self.store.iter() } pub fn len(&self) -> usize { self.store.len() } } impl core::ops::Index> for Arena { type Output = T; fn index(&self, id: Id) -> &Self::Output { debug_assert!(!id.is_invalid(), "attempted to index into Arena with an invalid id (index < 0)"); self.store.index(id.index as usize) } } impl core::ops::IndexMut> for Arena { fn index_mut(&mut self, id: Id) -> &mut Self::Output { debug_assert!(!id.is_invalid(), "attempted to index_mut into Arena with an invalid id (index < 0)"); self.store.index_mut(id.index as usize) } }