181 lines
5 KiB
Rust
181 lines
5 KiB
Rust
//! 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<usize>;
|
|
}
|
|
|
|
#[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<usize> {
|
|
if self.is_valid() {
|
|
Some(self.0 as usize)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
fn invalid() -> Self {
|
|
Self(u32::MAX)
|
|
}
|
|
}
|
|
|
|
impl std::convert::From<u32> for $name {
|
|
fn from(val: u32) -> Self {
|
|
<Self as $crate::entity::EntityRef>::new(val as usize)
|
|
}
|
|
}
|
|
|
|
impl std::default::Default for $name {
|
|
fn default() -> Self {
|
|
<Self as $crate::entity::EntityRef>::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<Idx: EntityRef, T: Clone + Debug>(Vec<T>, PhantomData<Idx>);
|
|
|
|
impl<Idx: EntityRef, T: Clone + Debug> std::default::Default for EntityVec<Idx, T> {
|
|
fn default() -> Self {
|
|
Self(vec![], PhantomData)
|
|
}
|
|
}
|
|
|
|
impl<Idx: EntityRef, T: Clone + Debug> From<Vec<T>> for EntityVec<Idx, T> {
|
|
fn from(vec: Vec<T>) -> Self {
|
|
Self(vec, PhantomData)
|
|
}
|
|
}
|
|
|
|
impl<Idx: EntityRef, T: Clone + Debug> EntityVec<Idx, T> {
|
|
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<Item = Idx> {
|
|
(0..self.0.len()).map(|index| Idx::new(index))
|
|
}
|
|
|
|
pub fn values(&self) -> impl DoubleEndedIterator<Item = &T> {
|
|
self.0.iter()
|
|
}
|
|
|
|
pub fn values_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut T> {
|
|
self.0.iter_mut()
|
|
}
|
|
|
|
pub fn entries(&self) -> impl DoubleEndedIterator<Item = (Idx, &T)> {
|
|
self.0
|
|
.iter()
|
|
.enumerate()
|
|
.map(|(index, t)| (Idx::new(index), t))
|
|
}
|
|
|
|
pub fn entries_mut(&mut self) -> impl Iterator<Item = (Idx, &mut T)> {
|
|
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<T> {
|
|
self.0
|
|
}
|
|
}
|
|
|
|
impl<Idx: EntityRef, T: Clone + Debug> Index<Idx> for EntityVec<Idx, T> {
|
|
type Output = T;
|
|
fn index(&self, idx: Idx) -> &T {
|
|
&self.0[idx.index()]
|
|
}
|
|
}
|
|
|
|
impl<Idx: EntityRef, T: Clone + Debug> IndexMut<Idx> for EntityVec<Idx, T> {
|
|
fn index_mut(&mut self, idx: Idx) -> &mut T {
|
|
&mut self.0[idx.index()]
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, Default)]
|
|
pub struct PerEntity<Idx: EntityRef, T: Clone + Debug + Default>(Vec<T>, PhantomData<Idx>, T);
|
|
|
|
impl<Idx: EntityRef, T: Clone + Debug + Default> Index<Idx> for PerEntity<Idx, T> {
|
|
type Output = T;
|
|
fn index(&self, idx: Idx) -> &T {
|
|
debug_assert!(idx.is_valid());
|
|
self.0.get(idx.index()).unwrap_or(&self.2)
|
|
}
|
|
}
|
|
|
|
impl<Idx: EntityRef, T: Clone + Debug + Default> IndexMut<Idx> for PerEntity<Idx, T> {
|
|
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<Idx: EntityRef, T: Clone + Debug + Default + PartialEq> PartialEq for PerEntity<Idx, T> {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.0 == other.0
|
|
}
|
|
}
|
|
impl<Idx: EntityRef, T: Clone + Debug + Default + PartialEq + Eq> Eq for PerEntity<Idx, T> {}
|