use crate::Indexable;
use core::marker::PhantomData;
use core::mem::MaybeUninit;
#[must_use]
pub struct ArrayMap<K, V, const N: usize> {
pub(crate) array: [V; N],
pub(crate) phantom: PhantomData<*const K>,
}
#[allow(unsafe_code)]
unsafe impl<K, V: Send, const N: usize> Send for ArrayMap<K, V, N> {}
#[allow(unsafe_code)]
unsafe impl<K, V: Sync, const N: usize> Sync for ArrayMap<K, V, N> {}
impl<K, V: Unpin, const N: usize> Unpin for ArrayMap<K, V, N> {}
#[cfg(feature = "std")]
impl<K, V: std::panic::UnwindSafe, const N: usize> std::panic::UnwindSafe for ArrayMap<K, V, N> {}
impl<K, V, const N: usize> ArrayMap<K, V, N> {
pub const fn new(array: [V; N]) -> Self {
Self {
array,
phantom: PhantomData,
}
}
}
impl<K: Indexable, V: Clone, const N: usize> ArrayMap<K, V, N> {
#[inline(always)]
pub fn from_value(v: V) -> Self {
Self::from_closure(|_| v.clone())
}
}
impl<K, V: Clone, const N: usize> Clone for ArrayMap<K, V, N> {
#[inline(always)]
fn clone(&self) -> Self {
Self {
array: self.array.clone(),
phantom: PhantomData,
}
}
}
impl<K, V: Copy, const N: usize> Copy for ArrayMap<K, V, N> {}
impl<K, V: PartialEq, const N: usize> PartialEq for ArrayMap<K, V, N> {
fn eq(&self, other: &Self) -> bool {
self.array.eq(&other.array)
}
}
impl<K, V: Eq, const N: usize> Eq for ArrayMap<K, V, N> {}
impl<K: core::fmt::Debug + Indexable, V: core::fmt::Debug, const N: usize> core::fmt::Debug for ArrayMap<K, V, N> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
assert_eq!(N, K::SIZE);
f.debug_map().entries(self.iter()).finish()
}
}
impl<K: Indexable, V, const N: usize> ArrayMap<K, V, N> {
pub fn from_closure<F: FnMut(&K) -> V>(mut f: F) -> Self {
let mut array = PanicSafeInit::new();
for k in K::iter() {
let v = f(&k);
array.write(k, v);
}
array.into_map().unwrap()
}
pub fn try_from_closure<E, F: FnMut(&K) -> Result<V, E>>(mut f: F) -> Result<Self, E> {
let mut array = PanicSafeInit::new();
for k in K::iter() {
match f(&k) {
Ok(v) => {
array.write(k, v);
}
Err(e) => {
return Err(e);
}
}
}
Ok(array.into_map().unwrap())
}
pub fn from_results<E, I: IntoIterator<Item = (K, Result<V, E>)>>(iter: I) -> Result<Self, E> {
let mut array = PanicSafeInit::new();
for (k, r) in iter {
match r {
Ok(v) => {
array.write(k, v);
}
Err(e) => {
return Err(e);
}
}
}
Ok(array.into_map().unwrap_or_else(|| {
panic!(
"Not all indexes have been set. Indexable::index() for {} probably isn't unique",
core::any::type_name::<K>()
)
}))
}
pub fn from_options<E, I: IntoIterator<Item = (K, Option<V>)>>(iter: I) -> Option<Self> {
let mut array = PanicSafeInit::new();
for (k, r) in iter {
#[allow(clippy::single_match_else)]
match r {
Some(v) => array.write(k, v),
None => {
if !array.filled[k.index()] {
return None;
}
}
}
}
array.into_map()
}
#[allow(clippy::should_implement_trait)]
pub fn from_iter<E, I: IntoIterator<Item = (K, V)>>(iter: I) -> Option<Self> {
let mut array = PanicSafeInit::new();
for (k, v) in iter {
array.write(k, v);
}
array.into_map()
}
#[inline(always)]
pub fn iter(&self) -> impl Iterator<Item = (K, &V)> + '_ {
assert_eq!(N, K::SIZE);
crate::assert_indexable_safe::<K>();
K::iter().zip(self.array.iter())
}
#[inline(always)]
pub fn iter_mut(&mut self) -> impl Iterator<Item = (K, &mut V)> + '_ {
assert_eq!(N, K::SIZE);
crate::assert_indexable_safe::<K>();
K::iter().zip(self.array.iter_mut())
}
#[inline(always)]
#[allow(clippy::unused_self)]
pub fn keys(&self) -> impl Iterator<Item = K> + '_ {
K::iter()
}
pub fn each_mut(&mut self) -> ArrayMap<K, &mut V, N> {
let mut array = PanicSafeInit::new();
for (k, v) in self.iter_mut() {
array.write(k, v);
}
array.into_map().unwrap()
}
pub fn each_ref(&self) -> ArrayMap<K, &V, N> {
let mut array = PanicSafeInit::new();
for (k, v) in self.iter() {
array.write(k, v);
}
array.into_map().unwrap()
}
pub fn map<U, F: FnMut(&K, V) -> U>(self, mut f: F) -> ArrayMap<K, U, N> {
let mut array = PanicSafeInit::new();
for (k, v) in self {
let u = f(&k, v);
array.write(k, u);
}
array.into_map().unwrap()
}
}
impl<K, V, const N: usize> ArrayMap<K, V, N> {
#[inline]
pub fn values(&self) -> impl Iterator<Item = &V> + '_ {
self.array.iter()
}
#[inline]
pub fn values_mut(&mut self) -> impl Iterator<Item = &mut V> + '_ {
self.array.iter_mut()
}
}
impl<K: Indexable, V, const N: usize> core::iter::IntoIterator for ArrayMap<K, V, N> {
type Item = (K, V);
type IntoIter = core::iter::Zip<K::Iter, core::array::IntoIter<V, N>>;
fn into_iter(self) -> Self::IntoIter {
assert_eq!(N, K::SIZE);
crate::assert_indexable_safe::<K>();
K::iter().zip(self.array.into_iter())
}
}
impl<K: Indexable, V, const N: usize> core::iter::FromIterator<(K, V)> for ArrayMap<K, V, N> {
fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
let mut array = PanicSafeInit::new();
for (k, v) in iter {
array.write(k, v);
}
array.into_map().unwrap()
}
}
impl<K: Indexable, V, const N: usize> core::iter::FromIterator<(K, V)> for ArrayMap<K, Option<V>, N> {
fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
let mut this = Self::from_closure(|_| None);
for (t, u) in iter {
this.array[t.index()] = Some(u);
}
this
}
}
impl<K: Indexable, V: Default, const N: usize> Default for ArrayMap<K, V, N> {
#[inline(always)]
fn default() -> Self {
Self::from_closure(|_| V::default())
}
}
impl<K, V, const N: usize> AsRef<[V; N]> for ArrayMap<K, V, N> {
#[inline(always)]
fn as_ref(&self) -> &[V; N] {
&self.array
}
}
impl<K, V, const N: usize> AsMut<[V; N]> for ArrayMap<K, V, N> {
#[inline(always)]
fn as_mut(&mut self) -> &mut [V; N] {
&mut self.array
}
}
impl<K, V, const N: usize> AsRef<[V]> for ArrayMap<K, V, N> {
#[inline(always)]
fn as_ref(&self) -> &[V] {
&self.array
}
}
impl<K, V, const N: usize> AsMut<[V]> for ArrayMap<K, V, N> {
#[inline(always)]
fn as_mut(&mut self) -> &mut [V] {
&mut self.array
}
}
impl<K: Indexable, V, const N: usize> core::ops::Index<K> for ArrayMap<K, V, N> {
type Output = V;
#[inline(always)]
fn index(&self, index: K) -> &Self::Output {
assert_eq!(N, K::SIZE);
&self.array[index.index()]
}
}
impl<K: Indexable, V, const N: usize> core::ops::IndexMut<K> for ArrayMap<K, V, N> {
#[inline(always)]
fn index_mut(&mut self, index: K) -> &mut Self::Output {
assert_eq!(N, K::SIZE);
&mut self.array[index.index()]
}
}
impl<K: Indexable, V, const N: usize> core::ops::Index<usize> for ArrayMap<K, V, N> {
type Output = V;
#[inline(always)]
fn index(&self, index: usize) -> &Self::Output {
assert_eq!(N, K::SIZE);
&self.array[index]
}
}
impl<K: Indexable, V, const N: usize> core::ops::IndexMut<usize> for ArrayMap<K, V, N> {
#[inline(always)]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
assert_eq!(N, K::SIZE);
&mut self.array[index]
}
}
struct PanicSafeInit<K: Indexable, V, const N: usize> {
filled: [bool; N],
array: MaybeUninit<[V; N]>,
_phantom: PhantomData<*const K>,
}
impl<K: Indexable, V, const N: usize> PanicSafeInit<K, V, N> {
pub fn new() -> Self {
assert_eq!(K::SIZE, N);
crate::assert_indexable_safe::<K>();
Self {
filled: [false; N],
array: MaybeUninit::uninit(),
_phantom: PhantomData,
}
}
pub fn write(&mut self, k: K, v: V) {
let index = k.index();
#[allow(unsafe_code)]
unsafe {
self.array.as_mut_ptr().cast::<V>().add(index).write(v);
self.filled[index] = true;
}
}
pub fn into_map(self) -> Option<ArrayMap<K, V, N>> {
self.filled.iter().all(|x| *x).then(|| {
let no_drop = core::mem::ManuallyDrop::new(self);
#[allow(unsafe_code)]
let array = unsafe { core::ptr::read(&no_drop.array).assume_init() };
ArrayMap::new(array)
})
}
}
impl<K: Indexable, V, const N: usize> Drop for PanicSafeInit<K, V, N> {
fn drop(&mut self) {
if core::mem::needs_drop::<V>() {
for k in K::iter() {
let index = k.index();
if self.filled[index] {
#[allow(unsafe_code)]
unsafe {
core::ptr::drop_in_place(self.array.as_mut_ptr().cast::<V>().add(index));
}
}
}
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::test::*;
use crate::IndexU8;
fn send_sync_traits<
K: Indexable,
V,
T: Send
+ Sync
+ Unpin
+ Default
+ Clone
+ Copy
+ PartialEq
+ Eq
+ core::fmt::Debug
+ AsRef<[V; N]>
+ AsMut<[V; N]>
+ core::ops::Index<K>
+ core::ops::IndexMut<K>,
const N: usize,
>() {
}
fn test_traits<
I: Indexable + Copy + PartialEq + core::fmt::Debug,
V: Send + Sync + Unpin + Default + Clone + Copy + PartialEq + Eq + core::fmt::Debug,
F: FnMut(I) -> V,
const N: usize,
>(
mut f: F,
) {
send_sync_traits::<I, V, ArrayMap<I, V, N>, N>();
let mut whole_map = ArrayMap::<I, V, N>::default();
for i in I::iter() {
assert_eq!(whole_map[i], V::default());
let new_value = f(i);
whole_map[i] = new_value;
assert_eq!(whole_map[i], new_value);
assert!(whole_map.iter().any(|(k, v)| k == i && v == &new_value));
}
assert_eq!(whole_map.keys().count(), I::SIZE);
assert_eq!(whole_map.iter().count(), I::SIZE);
assert_eq!(whole_map.iter_mut().count(), I::SIZE);
}
#[test]
fn test_impls() {
test_traits::<bool, Option<(u8, u8)>, _, { bool::SIZE }>(|b| Some((b as u8 + 1, b as u8)));
test_traits::<u8, u32, _, { u8::SIZE }>(|u| u as u32 + 1);
test_traits::<Lowercase, &'static str, _, { Lowercase::SIZE }>(|_| "abc");
}
#[test]
fn test_map() {
let mut m1 = ArrayMap::<IndexU8<5>, u8, 5>::new([0_u8, 1, 2, 3, 4]);
let r = m1.each_mut();
for (k, v) in r.into_iter() {
assert_eq!(k.get(), *v);
*v += 1;
}
let r = m1.each_ref();
for (k, v) in r.into_iter() {
assert_eq!(k.get() + 1, *v);
}
}
}