use alloc::vec::{IntoIter, Vec};
use core::{
iter::Enumerate,
marker::PhantomData,
ops::{Index, IndexMut},
};
pub trait EntityRef: Copy + Eq {
fn new(index: usize) -> Self;
fn index(self) -> usize;
}
macro_rules! entity_ref {
($name:ident) => {
impl $name {
#[inline]
#[allow(dead_code)]
pub const fn new(index: usize) -> Self {
Self(index)
}
#[inline]
#[allow(dead_code)]
pub const fn index(self) -> usize {
self.0
}
}
impl $crate::entity::EntityRef for $name {
#[inline]
fn new(index: usize) -> Self {
Self(index)
}
#[inline]
fn index(self) -> usize {
self.0
}
}
};
}
pub(crate) use entity_ref;
#[derive(Debug, Clone)]
pub struct PrimaryMap<K, V> {
values: Vec<V>,
marker: PhantomData<fn() -> K>,
}
pub struct PrimaryMapIntoIter<K, V> {
values: Enumerate<IntoIter<V>>,
marker: PhantomData<fn() -> K>,
}
impl<K, V> Default for PrimaryMap<K, V> {
#[inline]
fn default() -> Self {
Self {
values: Vec::new(),
marker: PhantomData,
}
}
}
impl<K, V> PrimaryMap<K, V>
where
K: EntityRef,
{
#[inline]
#[allow(dead_code)]
pub fn new() -> Self {
Self::default()
}
#[inline]
pub fn push(&mut self, value: V) -> K {
let key = K::new(self.values.len());
self.values.push(value);
key
}
#[inline]
pub(crate) fn map_values<U>(self, mut f: impl FnMut(K, V) -> U) -> PrimaryMap<K, U> {
PrimaryMap {
values: self
.values
.into_iter()
.enumerate()
.map(|(index, value)| f(K::new(index), value))
.collect(),
marker: PhantomData,
}
}
#[inline]
pub fn get(&self, key: K) -> Option<&V> {
self.values.get(key.index())
}
#[inline]
pub fn get_mut(&mut self, key: K) -> Option<&mut V> {
self.values.get_mut(key.index())
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = (K, &V)> {
self.values
.iter()
.enumerate()
.map(|(index, value)| (K::new(index), value))
}
}
impl<K, V> Iterator for PrimaryMapIntoIter<K, V>
where
K: EntityRef,
{
type Item = (K, V);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.values
.next()
.map(|(index, value)| (K::new(index), value))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.values.size_hint()
}
}
impl<K, V> ExactSizeIterator for PrimaryMapIntoIter<K, V> where K: EntityRef {}
impl<K, V> IntoIterator for PrimaryMap<K, V>
where
K: EntityRef,
{
type Item = (K, V);
type IntoIter = PrimaryMapIntoIter<K, V>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
PrimaryMapIntoIter {
values: self.values.into_iter().enumerate(),
marker: PhantomData,
}
}
}
impl<K, V> Index<K> for PrimaryMap<K, V>
where
K: EntityRef,
{
type Output = V;
#[inline]
fn index(&self, index: K) -> &Self::Output {
self.get(index)
.expect("primary map indexed with an out-of-bounds entity id")
}
}
impl<K, V> IndexMut<K> for PrimaryMap<K, V>
where
K: EntityRef,
{
#[inline]
fn index_mut(&mut self, index: K) -> &mut Self::Output {
self.get_mut(index)
.expect("primary map indexed with an out-of-bounds entity id")
}
}
#[derive(Debug, Clone)]
pub struct SecondaryMap<K, V> {
values: Vec<Option<V>>,
marker: PhantomData<fn() -> K>,
}
impl<K, V> Default for SecondaryMap<K, V> {
#[inline]
fn default() -> Self {
Self {
values: Vec::new(),
marker: PhantomData,
}
}
}
impl<K, V> SecondaryMap<K, V>
where
K: EntityRef,
{
#[inline]
#[allow(dead_code)]
pub fn new() -> Self {
Self::default()
}
pub fn insert(&mut self, key: K, value: V) -> Option<V> {
let index = key.index();
if self.values.len() <= index {
self.values.resize_with(index + 1, || None);
}
self.values[index].replace(value)
}
#[inline]
pub fn remove(&mut self, key: K) -> Option<V> {
self.values.get_mut(key.index()).and_then(Option::take)
}
#[inline]
pub fn get(&self, key: K) -> Option<&V> {
self.values.get(key.index()).and_then(Option::as_ref)
}
#[inline]
pub fn get_mut(&mut self, key: K) -> Option<&mut V> {
self.values.get_mut(key.index()).and_then(Option::as_mut)
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = (K, &V)> {
self.values
.iter()
.enumerate()
.filter_map(|(index, value)| value.as_ref().map(|value| (K::new(index), value)))
}
}
impl<K, V> Index<K> for SecondaryMap<K, V>
where
K: EntityRef,
{
type Output = V;
#[inline]
fn index(&self, index: K) -> &Self::Output {
self.get(index)
.expect("secondary map indexed with a missing entity id")
}
}
impl<K, V> IndexMut<K> for SecondaryMap<K, V>
where
K: EntityRef,
{
#[inline]
fn index_mut(&mut self, index: K) -> &mut Self::Output {
self.get_mut(index)
.expect("secondary map indexed with a missing entity id")
}
}
#[cfg(test)]
mod tests {
use super::{PrimaryMap, SecondaryMap};
use alloc::vec::Vec;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct TestId(usize);
super::entity_ref!(TestId);
#[test]
fn primary_map_returns_dense_index_ids() {
let mut arena = PrimaryMap::<TestId, u32>::new();
let first = arena.push(7);
let second = arena.push(11);
assert_eq!(first, TestId(0));
assert_eq!(second, TestId(1));
assert_eq!(arena.get(second), Some(&11));
}
#[test]
fn primary_map_supports_index_syntax() {
let mut arena = PrimaryMap::<TestId, u32>::new();
let first = arena.push(7);
assert_eq!(arena[first], 7);
arena[first] = 13;
assert_eq!(arena[first], 13);
}
#[test]
fn primary_map_consuming_iterator_yields_keys_and_values() {
let mut arena = PrimaryMap::<TestId, u32>::new();
let first = arena.push(7);
let second = arena.push(11);
assert_eq!(
arena.into_iter().collect::<Vec<_>>(),
[(first, 7), (second, 11)]
);
}
#[test]
fn secondary_map_tracks_sparse_side_data() {
let mut map = SecondaryMap::<TestId, &'static str>::new();
let first = TestId::new(0);
let third = TestId::new(2);
assert_eq!(map.insert(third, "three"), None);
assert_eq!(map.insert(third, "trois"), Some("three"));
assert_eq!(map.get(first), None);
assert_eq!(map[third], "trois");
assert_eq!(map.iter().collect::<Vec<_>>(), [(third, &"trois")]);
}
}