//! Type-safe indices and indexed containers. use std::default::Default; use std::fmt::Debug; use std::hash::Hash; use std::marker::PhantomData; use std::ops::{Index, IndexMut}; pub trait EntityRef: Clone + Copy + PartialEq + Eq + PartialOrd + Ord + Hash { fn new(value: usize) -> Self; fn index(self) -> usize; fn invalid() -> Self; fn is_valid(self) -> bool { self != Self::invalid() } fn is_invalid(self) -> bool { self == Self::invalid() } fn maybe_index(self) -> Option; } #[macro_export] macro_rules! declare_entity { ($name:tt, $prefix:tt) => { #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct $name(u32); impl $crate::entity::EntityRef for $name { fn new(value: usize) -> Self { use std::convert::TryFrom; let value = u32::try_from(value).unwrap(); debug_assert!(value != u32::MAX); Self(value) } fn index(self) -> usize { debug_assert!(self.is_valid()); self.0 as usize } fn maybe_index(self) -> Option { if self.is_valid() { Some(self.0 as usize) } else { None } } fn invalid() -> Self { Self(u32::MAX) } } impl std::convert::From for $name { fn from(val: u32) -> Self { ::new(val as usize) } } impl std::default::Default for $name { fn default() -> Self { ::invalid() } } impl std::fmt::Debug for $name { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}{}", $prefix, self.0) } } impl std::fmt::Display for $name { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}{}", $prefix, self.0) } } }; } #[derive(Clone, Debug)] pub struct EntityVec(Vec, PhantomData); impl std::default::Default for EntityVec { fn default() -> Self { Self(vec![], PhantomData) } } impl From> for EntityVec { fn from(vec: Vec) -> Self { Self(vec, PhantomData) } } impl EntityVec { pub fn push(&mut self, t: T) -> Idx { let idx = Idx::new(self.0.len()); self.0.push(t); idx } pub fn len(&self) -> usize { self.0.len() } pub fn iter(&self) -> impl DoubleEndedIterator { (0..self.0.len()).map(|index| Idx::new(index)) } pub fn values(&self) -> impl DoubleEndedIterator { self.0.iter() } pub fn values_mut(&mut self) -> impl DoubleEndedIterator { self.0.iter_mut() } pub fn entries(&self) -> impl DoubleEndedIterator { self.0 .iter() .enumerate() .map(|(index, t)| (Idx::new(index), t)) } pub fn entries_mut(&mut self) -> impl Iterator { self.0 .iter_mut() .enumerate() .map(|(index, t)| (Idx::new(index), t)) } pub fn get(&self, idx: Idx) -> Option<&T> { self.0.get(idx.index()) } pub fn get_mut(&mut self, idx: Idx) -> Option<&mut T> { self.0.get_mut(idx.index()) } pub fn into_vec(self) -> Vec { self.0 } } impl Index for EntityVec { type Output = T; fn index(&self, idx: Idx) -> &T { &self.0[idx.index()] } } impl IndexMut for EntityVec { fn index_mut(&mut self, idx: Idx) -> &mut T { &mut self.0[idx.index()] } } #[derive(Clone, Debug, Default)] pub struct PerEntity(Vec, PhantomData, T); impl Index for PerEntity { type Output = T; fn index(&self, idx: Idx) -> &T { debug_assert!(idx.is_valid()); self.0.get(idx.index()).unwrap_or(&self.2) } } impl IndexMut for PerEntity { fn index_mut(&mut self, idx: Idx) -> &mut T { debug_assert!(idx.is_valid()); if idx.index() >= self.0.len() { self.0.resize(idx.index() + 1, T::default()); } &mut self.0[idx.index()] } } impl PartialEq for PerEntity { fn eq(&self, other: &Self) -> bool { self.0 == other.0 } } impl Eq for PerEntity {}