use crate::array::Array;
use crate::*;
use core::ops::{Index, IndexMut};
pub struct ArrayMap<K: ArrayFinite<V>, V>(K::Array);
#[doc(hidden)]
#[allow(clippy::missing_safety_doc)] pub unsafe trait ArrayFinite<V>: Finite {
#[allow(missing_docs)]
type Array: Array<V>;
}
impl<K: ArrayFinite<V>, V> ArrayMap<K, V> {
pub fn new(mut f: impl FnMut(K) -> V) -> Self {
ArrayMap(K::Array::new(|k| {
f(unsafe { K::nth(k).unwrap_unchecked() })
}))
}
pub fn from(array: K::Array) -> Self {
Self(array)
}
pub fn map_with_key<N>(&self, mut f: impl FnMut(K, &V) -> N) -> ArrayMap<K, N>
where
K: ArrayFinite<N>,
{
ArrayMap(<K as ArrayFinite<N>>::Array::new(|k| unsafe {
f(
K::nth(k).unwrap_unchecked(),
self.0.as_slice().get_unchecked(k),
)
}))
}
pub fn map<N>(&self, mut f: impl FnMut(&V) -> N) -> ArrayMap<K, N>
where
K: ArrayFinite<N>,
{
self.map_with_key(|_, v| f(v))
}
}
impl<K: ArrayFinite<V>, V: Default> Default for ArrayMap<K, V> {
fn default() -> Self {
ArrayMap(K::Array::new(|_| Default::default()))
}
}
impl<K: ArrayFinite<V>, V> Index<K> for ArrayMap<K, V> {
type Output = V;
fn index(&self, index: K) -> &Self::Output {
let index = K::index_of(index);
unsafe { self.0.as_slice().get_unchecked(index) }
}
}
impl<K: ArrayFinite<V>, V> IndexMut<K> for ArrayMap<K, V> {
fn index_mut(&mut self, index: K) -> &mut Self::Output {
let index = K::index_of(index);
unsafe { self.0.as_slice_mut().get_unchecked_mut(index) }
}
}
impl<K: CompressFinite + ArrayFinite<V>, V> Index<Compress<K>> for ArrayMap<K, V> {
type Output = V;
fn index(&self, index: Compress<K>) -> &Self::Output {
let index = Compress::index_of(index);
unsafe { self.0.as_slice().get_unchecked(index) }
}
}
impl<K: CompressFinite + ArrayFinite<V>, V> IndexMut<Compress<K>> for ArrayMap<K, V> {
fn index_mut(&mut self, index: Compress<K>) -> &mut Self::Output {
let index = Compress::index_of(index);
unsafe { self.0.as_slice_mut().get_unchecked_mut(index) }
}
}
impl<K: ArrayFinite<V>, V> Clone for ArrayMap<K, V>
where
K::Array: Clone,
{
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<K: ArrayFinite<V>, V> Copy for ArrayMap<K, V> where K::Array: Copy {}
impl<K: ArrayFinite<V>, V> PartialEq for ArrayMap<K, V>
where
K::Array: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<K: ArrayFinite<V>, V> Eq for ArrayMap<K, V> where K::Array: Eq {}
impl<K: ArrayFinite<V>, V> PartialOrd for ArrayMap<K, V>
where
K::Array: PartialOrd,
{
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
self.0.partial_cmp(&other.0)
}
}
impl<K: ArrayFinite<V>, V> Ord for ArrayMap<K, V>
where
K::Array: Ord,
{
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.0.cmp(&other.0)
}
}
#[test]
fn test_map_with_key() {
let map = ArrayMap::new(|x| if x { 1 } else { 0 });
let map = map.map_with_key(|k, v| if k { *v * 2 } else { *v + 5 });
assert_eq!(map[false], 5);
assert_eq!(map[true], 2);
}