use core::{fmt, marker::PhantomData};
use crate::Enum;
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct EnumMap<const LENGTH: usize, E: Enum<LENGTH>, V> {
data: [Option<V>; LENGTH],
_enum: PhantomData<E>,
}
impl<const LENGTH: usize, E: Enum<LENGTH>, V> EnumMap<LENGTH, E, V> {
pub fn new() -> Self {
#[cfg(debug_assertions)]
assert_enum_impl::<LENGTH, E>();
Self {
data: [(); LENGTH].map(|_| None),
_enum: PhantomData,
}
}
pub fn as_slice(&self) -> &[Option<V>; LENGTH] {
&self.data
}
pub fn as_mut_slice(&mut self) -> &mut [Option<V>; LENGTH] {
&mut self.data
}
pub fn clear(&mut self) {
self.data = [(); LENGTH].map(|_| None);
}
pub fn contains_key(&self, key: E) -> bool {
self.get(key).is_some()
}
pub fn get(&self, key: E) -> Option<&V> {
self.data[E::to_index(key)].as_ref()
}
pub fn get_mut(&mut self, key: E) -> Option<&mut V> {
self.data[E::to_index(key)].as_mut()
}
pub fn insert(&mut self, key: E, value: V) -> Option<V> {
core::mem::replace(&mut self.data[E::to_index(key)], Some(value))
}
pub fn into_values(self) -> IntoValues<LENGTH, E, V> {
IntoValues {
inner: self.into_iter(),
}
}
pub fn is_empty(&self) -> bool {
self.data.iter().all(Option::is_none)
}
pub fn iter(&self) -> Iter<'_, LENGTH, E, V> {
Iter {
map: self,
index: 0,
}
}
pub fn iter_mut(&mut self) -> IterMut<'_, LENGTH, E, V> {
IterMut {
inner: self.data.iter_mut().enumerate(),
_enum: PhantomData,
}
}
pub fn keys(&self) -> Keys<'_, LENGTH, E, V> {
Keys { inner: self.iter() }
}
pub fn len(&self) -> usize {
self.data.iter().filter(|v| v.is_some()).count()
}
pub fn remove(&mut self, key: E) -> Option<V> {
core::mem::take(&mut self.data[E::to_index(key)])
}
pub fn values(&self) -> Values<'_, LENGTH, E, V> {
Values { inner: self.iter() }
}
pub fn values_mut(&mut self) -> ValuesMut<'_, LENGTH, E, V> {
ValuesMut {
inner: self.iter_mut(),
}
}
}
impl<const LENGTH: usize, E: Enum<LENGTH>, V> Default for EnumMap<LENGTH, E, V> {
fn default() -> Self {
Self::new()
}
}
impl<const LENGTH: usize, E: Enum<LENGTH>, V, const N: usize> From<[(E, V); N]>
for EnumMap<LENGTH, E, V>
{
fn from(value: [(E, V); N]) -> Self {
Self::from_iter(value)
}
}
impl<const LENGTH: usize, E: Enum<LENGTH>, V> From<[Option<V>; LENGTH]> for EnumMap<LENGTH, E, V> {
fn from(value: [Option<V>; LENGTH]) -> Self {
Self {
data: value,
_enum: PhantomData,
}
}
}
impl<const LENGTH: usize, E: Enum<LENGTH>, V> From<EnumMap<LENGTH, E, V>> for [Option<V>; LENGTH] {
fn from(value: EnumMap<LENGTH, E, V>) -> Self {
value.data
}
}
impl<const LENGTH: usize, E: Enum<LENGTH>, V> FromIterator<(E, V)> for EnumMap<LENGTH, E, V> {
fn from_iter<T: IntoIterator<Item = (E, V)>>(iter: T) -> Self {
let mut map = Self::new();
map.extend(iter);
map
}
}
impl<const LENGTH: usize, E: Enum<LENGTH>, V> Extend<(E, V)> for EnumMap<LENGTH, E, V> {
#[inline]
fn extend<T: IntoIterator<Item = (E, V)>>(&mut self, iter: T) {
for (k, v) in iter {
self.insert(k, v);
}
}
}
impl<const LENGTH: usize, E: Enum<LENGTH>, V> core::ops::Index<E> for EnumMap<LENGTH, E, V> {
type Output = V;
fn index(&self, index: E) -> &Self::Output {
self.get(index).expect("no entry found for key")
}
}
impl<const LENGTH: usize, E: Enum<LENGTH>, V> IntoIterator for EnumMap<LENGTH, E, V> {
type Item = (E, V);
type IntoIter = IntoIter<LENGTH, E, V>;
fn into_iter(self) -> Self::IntoIter {
IntoIter::<LENGTH, E, V>::new(self)
}
}
impl<'a, const LENGTH: usize, E: Enum<LENGTH>, V> IntoIterator for &'a EnumMap<LENGTH, E, V> {
type Item = (E, &'a V);
type IntoIter = Iter<'a, LENGTH, E, V>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<const LENGTH: usize, E: Enum<LENGTH>, V> fmt::Debug for EnumMap<LENGTH, E, V>
where
E: fmt::Debug,
V: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map().entries(self.iter()).finish()
}
}
pub struct Iter<'a, const LENGTH: usize, E: Enum<LENGTH>, V> {
index: usize,
map: &'a EnumMap<LENGTH, E, V>,
}
impl<'a, const LENGTH: usize, E: Enum<LENGTH>, V> Iterator for Iter<'a, LENGTH, E, V> {
type Item = (E, &'a V);
fn next(&mut self) -> Option<Self::Item> {
while self.index < self.map.data.len() {
let index = self.index;
self.index += 1;
if let Some(value) = &self.map.data[index] {
return Some((E::from_index(index)?, value));
}
}
None
}
}
pub struct Keys<'a, const LENGTH: usize, E: Enum<LENGTH>, V> {
inner: Iter<'a, LENGTH, E, V>,
}
impl<'a, const LENGTH: usize, E: Enum<LENGTH>, V> Iterator for Keys<'a, LENGTH, E, V> {
type Item = E;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|(k, _)| k)
}
}
pub struct Values<'a, const LENGTH: usize, E: Enum<LENGTH>, V> {
inner: Iter<'a, LENGTH, E, V>,
}
impl<'a, const LENGTH: usize, E: Enum<LENGTH>, V> Iterator for Values<'a, LENGTH, E, V> {
type Item = &'a V;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|(_, v)| v)
}
}
pub struct ValuesMut<'a, const LENGTH: usize, E: Enum<LENGTH>, V> {
inner: IterMut<'a, LENGTH, E, V>,
}
impl<'a, const LENGTH: usize, E: Enum<LENGTH>, V> Iterator for ValuesMut<'a, LENGTH, E, V> {
type Item = &'a mut V;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|(_, v)| v)
}
}
pub struct IntoValues<const LENGTH: usize, E: Enum<LENGTH>, V> {
inner: IntoIter<LENGTH, E, V>,
}
impl<const LENGTH: usize, E: Enum<LENGTH>, V> Iterator for IntoValues<LENGTH, E, V> {
type Item = V;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|(_, v)| v)
}
}
pub struct IterMut<'a, const LENGTH: usize, E: Enum<LENGTH>, V> {
inner: core::iter::Enumerate<core::slice::IterMut<'a, Option<V>>>,
_enum: PhantomData<E>,
}
impl<'a, const LENGTH: usize, E: Enum<LENGTH>, V> Iterator for IterMut<'a, LENGTH, E, V> {
type Item = (E, &'a mut V);
fn next(&mut self) -> Option<Self::Item> {
for (i, v) in self.inner.by_ref() {
if let Some(v) = v.as_mut() {
return Some((E::from_index(i)?, v));
}
}
None
}
}
pub struct IntoIter<const LENGTH: usize, E: Enum<LENGTH>, V> {
index: usize,
map: EnumMap<LENGTH, E, V>,
}
impl<const LENGTH: usize, E: Enum<LENGTH>, V> IntoIter<LENGTH, E, V> {
fn new(map: EnumMap<LENGTH, E, V>) -> Self {
Self { index: 0, map }
}
}
impl<const LENGTH: usize, E: Enum<LENGTH>, V> Iterator for IntoIter<LENGTH, E, V> {
type Item = (E, V);
fn next(&mut self) -> Option<Self::Item> {
while self.index < self.map.data.len() {
let index = self.index;
self.index += 1;
let value = core::mem::take(&mut self.map.data[index]);
if let Some(value) = value {
return Some((E::from_index(index)?, value));
}
}
None
}
}
#[cfg(debug_assertions)]
fn assert_enum_impl<const LENGTH: usize, E>()
where
E: Enum<LENGTH>,
{
let ty = core::any::type_name::<E>();
for i in 0..LENGTH + 1 {
let Some(v) = E::from_index(i) else {
assert_eq!(
i, LENGTH,
"No variant constructed from index {i} for enum {ty} with LENGTH {LENGTH}",
);
return;
};
assert_eq!(
i, E::to_index(v),
"`to_index` returned different index for variant constructed at index {i} with `from_index`",
);
}
panic!("Enum {ty} yielded more variants from `from_index` than LENGTH ({LENGTH})");
}