use std::{ cmp::{Eq, PartialEq}, fmt, hash, marker::PhantomData, ops::{Index, IndexMut}, }; // NOTE: We use u64 to make sure we are consistent across all machines. We // assume that usize fits into 8 bytes. pub struct Id(u64, PhantomData); impl Id { pub fn id(&self) -> u64 { self.0 } } impl Copy for Id {} impl Clone for Id { fn clone(&self) -> Self { Self(self.0, PhantomData) } } impl Eq for Id {} impl PartialEq for Id { fn eq(&self, other: &Self) -> bool { self.0 == other.0 } } impl fmt::Debug for Id { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Id<{}>({})", std::any::type_name::(), self.0) } } impl hash::Hash for Id { fn hash(&self, h: &mut H) { self.0.hash(h); } } pub struct Store { items: Vec, } impl Default for Store { fn default() -> Self { Self { items: Vec::new() } } } impl Store { pub fn get(&self, id: Id) -> &T { // NOTE: Safe conversion, because it came from usize. self.items.get(id.0 as usize).unwrap() } pub fn get_mut(&mut self, id: Id) -> &mut T { // NOTE: Safe conversion, because it came from usize. self.items.get_mut(id.0 as usize).unwrap() } pub fn ids(&self) -> impl Iterator> { // NOTE: Assumes usize fits into 8 bytes. (0..self.items.len() as u64).map(|i| Id(i, PhantomData)) } pub fn iter(&self) -> impl Iterator { self.items.iter() } pub fn iter_mut(&mut self) -> impl Iterator { self.items.iter_mut() } pub fn iter_ids(&self) -> impl Iterator, &T)> { self.items .iter() .enumerate() // NOTE: Assumes usize fits into 8 bytes. .map(|(i, item)| (Id(i as u64, PhantomData), item)) } pub fn insert(&mut self, item: T) -> Id { // NOTE: Assumes usize fits into 8 bytes. let id = Id(self.items.len() as u64, PhantomData); self.items.push(item); id } } impl Index> for Store { type Output = T; fn index(&self, id: Id) -> &Self::Output { self.get(id) } } impl IndexMut> for Store { fn index_mut(&mut self, id: Id) -> &mut Self::Output { self.get_mut(id) } }