use std::convert::Infallible;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::mem;
use std::ops::Index;
use std::ops::IndexMut;
use std::slice;
use crate::array_as_mut::array_as_mut;
use crate::array_builder::ArrayBuilder;
use crate::array_from_iter::array_from_iter;
use crate::map::total::IntoIterArray;
use crate::map::total::Iter;
use crate::map::total::IterMut;
use crate::Ordinal;
#[repr(C)]
pub struct OrdinalTotalArrayMap<K, V, const S: usize> {
map: [V; S],
_phantom: PhantomData<K>,
}
impl<K: Ordinal, V, const S: usize> OrdinalTotalArrayMap<K, V, S> {
const ASSERT: () = {
assert!(K::ORDINAL_SIZE == S, "K::ORDINAL_SIZE != S");
};
pub fn try_new<E>(mut init: impl FnMut(K) -> Result<V, E>) -> Result<Self, E> {
const { Self::ASSERT };
let mut a = ArrayBuilder::new();
for v in K::all_values() {
a.push(init(v)?);
}
Ok(OrdinalTotalArrayMap {
map: a.finish(),
_phantom: PhantomData,
})
}
pub fn new(mut init: impl FnMut(K) -> V) -> Self {
const { Self::ASSERT };
match Self::try_new(move |k| Ok::<_, Infallible>(init(k))) {
Ok(map) => map,
Err(infallible) => match infallible {},
}
}
pub fn from_array(array: [V; S]) -> Self {
OrdinalTotalArrayMap {
map: array,
_phantom: PhantomData,
}
}
pub const fn len(&self) -> usize {
S
}
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn get<'a>(&'a self, key: &K) -> &'a V {
&self.map[key.ordinal()]
}
pub fn get_mut<'a>(&'a mut self, key: &K) -> &'a mut V {
&mut self.map[key.ordinal()]
}
pub fn as_ref(&self) -> OrdinalTotalArrayMap<K, &V, S> {
OrdinalTotalArrayMap::new(|k| self.get(&k))
}
pub fn as_mut(&mut self) -> OrdinalTotalArrayMap<K, &mut V, S> {
OrdinalTotalArrayMap::from_array(array_as_mut(&mut self.map))
}
pub fn zip<W>(
self,
other: OrdinalTotalArrayMap<K, W, S>,
) -> OrdinalTotalArrayMap<K, (V, W), S> {
OrdinalTotalArrayMap {
map: array_from_iter(self.map.into_iter().zip(other.map)),
_phantom: PhantomData,
}
}
pub fn map<W>(self, mut f: impl FnMut(K, V) -> W) -> OrdinalTotalArrayMap<K, W, S> {
OrdinalTotalArrayMap {
map: array_from_iter(self.into_iter().map(|(k, v)| f(k, v))),
_phantom: PhantomData,
}
}
pub fn map_values<W>(self, mut f: impl FnMut(V) -> W) -> OrdinalTotalArrayMap<K, W, S> {
self.map(|_k, v| f(v))
}
pub fn iter<'a>(&'a self) -> Iter<'a, K, V> {
Iter::new(self.map.iter(), 0)
}
pub fn iter_mut<'a>(&'a mut self) -> IterMut<'a, K, V> {
IterMut::new(self.map.iter_mut())
}
pub fn keys(&self) -> crate::OrdinalValues<K> {
K::all_values()
}
pub fn into_keys(self) -> crate::OrdinalValues<K> {
self.keys()
}
pub fn values<'a>(&'a self) -> slice::Iter<'a, V> {
self.map.iter()
}
pub fn values_array(&self) -> &[V; S] {
&self.map
}
pub fn values_mut<'a>(&'a mut self) -> slice::IterMut<'a, V> {
self.map.iter_mut()
}
pub fn values_array_mut(&mut self) -> &mut [V; S] {
&mut self.map
}
pub fn into_values(self) -> [V; S] {
self.map
}
#[inline]
pub fn insert(&mut self, key: K, value: V) -> V {
mem::replace(&mut self.map[key.ordinal()], value)
}
}
impl<'a, K: Ordinal, V, const S: usize> Index<&'a K> for OrdinalTotalArrayMap<K, V, S> {
type Output = V;
fn index(&self, index: &'a K) -> &Self::Output {
&self.map[index.ordinal()]
}
}
impl<'a, K: Ordinal, V, const S: usize> IndexMut<&'a K> for OrdinalTotalArrayMap<K, V, S> {
fn index_mut(&mut self, index: &'a K) -> &mut Self::Output {
&mut self.map[index.ordinal()]
}
}
impl<K, V: Clone, const S: usize> Clone for OrdinalTotalArrayMap<K, V, S> {
fn clone(&self) -> Self {
OrdinalTotalArrayMap {
map: self.map.clone(),
_phantom: PhantomData,
}
}
}
impl<K: Ordinal, V: Default, const S: usize> Default for OrdinalTotalArrayMap<K, V, S> {
fn default() -> Self {
OrdinalTotalArrayMap::new(|_| V::default())
}
}
impl<K: Ordinal + Debug, V: Debug, const S: usize> Debug for OrdinalTotalArrayMap<K, V, S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_map().entries(self.iter()).finish()
}
}
impl<K: Ordinal, V, const S: usize> IntoIterator for OrdinalTotalArrayMap<K, V, S> {
type Item = (K, V);
type IntoIter = IntoIterArray<K, V, S>;
fn into_iter(self) -> Self::IntoIter {
IntoIterArray::new(self.map.into_iter())
}
}
impl<'a, K: Ordinal, V, const S: usize> IntoIterator for &'a OrdinalTotalArrayMap<K, V, S> {
type Item = (K, &'a V);
type IntoIter = Iter<'a, K, V>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[cfg(test)]
mod tests {
#[test]
fn test() {}
}