use core::{
borrow::Borrow,
fmt::Debug,
hash::Hash,
marker::PhantomData,
mem::MaybeUninit,
ops::{Index, IndexMut},
};
use generic_array::{
ArrayLength, GenericArray, GenericArrayIter, functional::FunctionalSequence,
sequence::GenericSequence, typenum::Unsigned,
};
use crate::{
IterAll,
finite::{Finite, FiniteExt},
};
#[repr(transparent)]
pub struct ExhaustiveMap<K: Finite, V> {
array: GenericArray<V, K::INHABITANTS>,
_phantom: PhantomData<fn(&K) -> usize>,
}
impl<K: Finite, V> ExhaustiveMap<K, V> {
#[must_use]
pub fn from_fn(f: impl FnMut(K) -> V) -> Self {
Self {
array: K::iter_all().map(f).collect(),
_phantom: PhantomData,
}
}
pub fn try_from_fn<E>(f: impl FnMut(K) -> Result<V, E>) -> Result<Self, E> {
Ok(Self {
array: K::iter_all().map(f).collect::<Result<_, E>>()?,
_phantom: PhantomData,
})
}
#[must_use]
pub fn from_usize_fn(f: impl FnMut(usize) -> V) -> Self {
Self {
array: GenericArray::generate(f),
_phantom: PhantomData,
}
}
#[must_use]
pub const fn len(&self) -> usize {
K::INHABITANTS::USIZE
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn replace<Q: Borrow<K>>(&mut self, k: Q, v: V) -> V {
core::mem::replace(&mut self[k], v)
}
pub fn swap<Q1: Borrow<K>, Q2: Borrow<K>>(&mut self, k1: Q1, k2: Q2) {
self.array
.swap(k1.borrow().to_usize(), k2.borrow().to_usize());
}
pub fn take<Q: Borrow<K>>(&mut self, k: Q) -> V
where
V: Default,
{
core::mem::take(&mut self[k])
}
#[must_use]
pub fn map_values<U>(self, f: impl FnMut(V) -> U) -> ExhaustiveMap<K, U> {
ExhaustiveMap {
array: self.array.map(f),
_phantom: PhantomData,
}
}
pub fn keys() -> IterAll<K> {
K::iter_all()
}
pub fn values(&self) -> Values<'_, V> {
Values(self.array.iter())
}
pub fn values_mut(&mut self) -> ValuesMut<'_, V> {
ValuesMut(self.array.iter_mut())
}
pub fn into_values(self) -> IntoValues<V, K::INHABITANTS> {
IntoValues(self.array.into_iter())
}
pub fn iter(&self) -> Iter<'_, K, V> {
Iter(Self::keys().zip(self.values()))
}
pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
IterMut(Self::keys().zip(self.values_mut()))
}
#[must_use]
pub fn new_uninit() -> ExhaustiveMap<K, MaybeUninit<V>> {
ExhaustiveMap {
array: GenericArray::uninit(),
_phantom: PhantomData,
}
}
}
impl<K: Finite, V> ExhaustiveMap<K, Option<V>> {
pub fn try_unwrap_values(self) -> Result<ExhaustiveMap<K, V>, ExhaustiveMap<K, Option<V>>> {
if !self.array.iter().all(Option::is_some) {
return Err(self);
}
#[allow(clippy::missing_panics_doc)]
Ok(self.map_values(|v| v.unwrap()))
}
}
impl<K: Finite, V> ExhaustiveMap<K, MaybeUninit<V>> {
#[must_use]
pub unsafe fn assume_init(self) -> ExhaustiveMap<K, V> {
ExhaustiveMap {
array: unsafe { GenericArray::assume_init(self.array) },
_phantom: PhantomData,
}
}
}
#[cfg(feature = "alloc")]
mod alloc_impls {
use alloc::{boxed::Box, collections::BTreeMap, vec::Vec};
use core::marker::PhantomData;
use crate::{ExhaustiveMap, Finite, generic_array::GenericArray, typenum::Unsigned};
impl<K: Finite, V> TryFrom<Box<[V]>> for ExhaustiveMap<K, V> {
type Error = Box<[V]>;
fn try_from(value: Box<[V]>) -> Result<Self, Self::Error> {
if value.len() != K::INHABITANTS::USIZE {
return Err(value);
}
Ok(Self {
array: *GenericArray::try_from_boxed_slice(value).unwrap(),
_phantom: PhantomData,
})
}
}
impl<K: Finite, V> From<ExhaustiveMap<K, V>> for Box<[V]> {
fn from(value: ExhaustiveMap<K, V>) -> Self {
Box::new(value.array).into_boxed_slice()
}
}
impl<K: Finite, V> TryFrom<Vec<V>> for ExhaustiveMap<K, V> {
type Error = Vec<V>;
fn try_from(value: Vec<V>) -> Result<Self, Self::Error> {
if value.len() != K::INHABITANTS::USIZE {
return Err(value);
}
Ok(Self {
array: *GenericArray::try_from_vec(value).unwrap(),
_phantom: PhantomData,
})
}
}
impl<const N: usize, K: Finite, V> TryFrom<[V; N]> for ExhaustiveMap<K, V> {
type Error = [V; N];
fn try_from(value: [V; N]) -> Result<Self, Self::Error> {
if N != K::INHABITANTS::USIZE {
return Err(value);
}
Ok(Self {
array: GenericArray::try_from_iter(value).unwrap(),
_phantom: PhantomData,
})
}
}
impl<K: Finite + Ord, V> TryFrom<BTreeMap<K, V>> for ExhaustiveMap<K, V> {
type Error = K;
fn try_from(mut value: BTreeMap<K, V>) -> Result<Self, Self::Error> {
Self::try_from_fn(|k| value.remove(&k).ok_or(k))
}
}
impl<K: Finite + Ord, V> From<ExhaustiveMap<K, V>> for BTreeMap<K, V> {
fn from(value: ExhaustiveMap<K, V>) -> Self {
Self::from_iter(value)
}
}
}
#[cfg(feature = "std")]
mod std_impls {
use std::{
collections::HashMap,
hash::{BuildHasher, Hash},
};
use crate::{ExhaustiveMap, Finite};
impl<K: Finite + Eq + Hash, V> TryFrom<HashMap<K, V>> for ExhaustiveMap<K, V> {
type Error = K;
fn try_from(mut value: HashMap<K, V>) -> Result<Self, Self::Error> {
Self::try_from_fn(|k| value.remove(&k).ok_or(k))
}
}
impl<K: Finite + Eq + Hash, V, S: BuildHasher + Default> From<ExhaustiveMap<K, V>>
for HashMap<K, V, S>
{
fn from(value: ExhaustiveMap<K, V>) -> Self {
Self::from_iter(value)
}
}
}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct Values<'a, V>(core::slice::Iter<'a, V>);
impl<'a, V> Iterator for Values<'a, V> {
type Item = &'a V;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.0.len(), Some(self.0.len()))
}
}
impl<T> ExactSizeIterator for Values<'_, T> {
fn len(&self) -> usize {
self.0.len()
}
}
impl<T> DoubleEndedIterator for Values<'_, T> {
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct ValuesMut<'a, V>(core::slice::IterMut<'a, V>);
impl<'a, V> Iterator for ValuesMut<'a, V> {
type Item = &'a mut V;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.0.len(), Some(self.0.len()))
}
}
impl<T> ExactSizeIterator for ValuesMut<'_, T> {
fn len(&self) -> usize {
self.0.len()
}
}
impl<T> DoubleEndedIterator for ValuesMut<'_, T> {
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct IntoValues<V, N: ArrayLength>(GenericArrayIter<V, N>);
impl<V, N: ArrayLength> Iterator for IntoValues<V, N> {
type Item = V;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.0.len(), Some(self.0.len()))
}
}
impl<V, N: ArrayLength> ExactSizeIterator for IntoValues<V, N> {
fn len(&self) -> usize {
self.0.len()
}
}
impl<V, N: ArrayLength> DoubleEndedIterator for IntoValues<V, N> {
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
}
impl<K: Finite, V: Default> Default for ExhaustiveMap<K, V> {
fn default() -> Self {
Self {
array: GenericArray::default(),
_phantom: PhantomData,
}
}
}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct Iter<'a, K, V>(core::iter::Zip<IterAll<K>, Values<'a, V>>);
impl<'a, K, V> Iterator for Iter<'a, K, V> {
type Item = (K, &'a V);
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.0.len(), Some(self.0.len()))
}
}
impl<K, V> ExactSizeIterator for Iter<'_, K, V> {
fn len(&self) -> usize {
self.0.len()
}
}
impl<K, V> DoubleEndedIterator for Iter<'_, K, V> {
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct IterMut<'a, K, V>(core::iter::Zip<IterAll<K>, ValuesMut<'a, V>>);
impl<'a, K, V> Iterator for IterMut<'a, K, V> {
type Item = (K, &'a mut V);
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.0.len(), Some(self.0.len()))
}
}
impl<K, V> ExactSizeIterator for IterMut<'_, K, V> {
fn len(&self) -> usize {
self.0.len()
}
}
impl<K, V> DoubleEndedIterator for IterMut<'_, K, V> {
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct IntoIter<K: Finite, V>(core::iter::Zip<IterAll<K>, IntoValues<V, K::INHABITANTS>>);
impl<K: Finite, V> Iterator for IntoIter<K, V> {
type Item = (K, V);
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.0.len(), Some(self.0.len()))
}
}
impl<K: Finite, V> ExactSizeIterator for IntoIter<K, V> {
fn len(&self) -> usize {
self.0.len()
}
}
impl<K: Finite, V> DoubleEndedIterator for IntoIter<K, V> {
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
}
impl<K: Finite, V> IntoIterator for ExhaustiveMap<K, V> {
type Item = (K, V);
type IntoIter = IntoIter<K, V>;
fn into_iter(self) -> Self::IntoIter {
IntoIter(Self::keys().zip(self.into_values()))
}
}
impl<'a, K: Finite, V> IntoIterator for &'a ExhaustiveMap<K, V> {
type Item = (K, &'a V);
type IntoIter = Iter<'a, K, V>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, K: Finite, V> IntoIterator for &'a mut ExhaustiveMap<K, V> {
type Item = (K, &'a mut V);
type IntoIter = IterMut<'a, K, V>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
impl<K: Finite + Debug, V: Debug> Debug for ExhaustiveMap<K, V> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_map().entries(self).finish()
}
}
impl<K: Finite, V, Q: Borrow<K>> Index<Q> for ExhaustiveMap<K, V> {
type Output = V;
fn index(&self, index: Q) -> &Self::Output {
&self.array[K::to_usize(index.borrow())]
}
}
impl<K: Finite, V, Q: Borrow<K>> IndexMut<Q> for ExhaustiveMap<K, V> {
fn index_mut(&mut self, index: Q) -> &mut Self::Output {
&mut self.array[K::to_usize(index.borrow())]
}
}
impl<K: Finite, V: Clone> Clone for ExhaustiveMap<K, V> {
fn clone(&self) -> Self {
Self {
array: self.array.clone(),
_phantom: PhantomData,
}
}
}
impl<K: Finite, V: Copy> Copy for ExhaustiveMap<K, V> where GenericArray<V, K::INHABITANTS>: Copy {}
impl<K: Finite, V: PartialEq> PartialEq for ExhaustiveMap<K, V> {
fn eq(&self, other: &Self) -> bool {
self.array.eq(&other.array)
}
}
impl<K: Finite, V: Eq> Eq for ExhaustiveMap<K, V> {}
impl<K: Finite, V: PartialOrd> PartialOrd for ExhaustiveMap<K, V> {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
self.array.partial_cmp(&other.array)
}
}
impl<K: Finite, V: Ord> Ord for ExhaustiveMap<K, V> {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.array.cmp(&other.array)
}
}
impl<K: Finite, V: Hash> Hash for ExhaustiveMap<K, V> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.array.hash(state);
}
}
#[cfg(feature = "serde")]
mod serde_impl {
use alloc::format;
use core::{any::type_name, marker::PhantomData};
use generic_array::typenum::Unsigned;
use serde::{
Deserialize, Deserializer, Serialize, Serializer,
de::{Error, Visitor},
ser::SerializeMap,
};
use super::{ExhaustiveMap, Finite};
impl<K: Finite + Serialize, V: Serialize> Serialize for ExhaustiveMap<K, V> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut map = serializer.serialize_map(Some(K::INHABITANTS::USIZE))?;
for (k, v) in self {
map.serialize_entry(&k, v)?;
}
map.end()
}
}
struct MapVisitor<K: Finite, V>(PhantomData<fn() -> ExhaustiveMap<K, V>>);
impl<K: Finite, V> MapVisitor<K, V> {
fn new() -> Self {
Self(PhantomData)
}
}
impl<'de, K: Finite + Deserialize<'de>, V: Deserialize<'de>> Visitor<'de> for MapVisitor<K, V> {
type Value = ExhaustiveMap<K, V>;
fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(
formatter,
"an ExhaustiveMap<{}, {}>",
type_name::<K>(),
type_name::<V>()
)
}
fn visit_map<A>(self, mut access: A) -> Result<Self::Value, A::Error>
where
A: serde::de::MapAccess<'de>,
{
let mut map: ExhaustiveMap<K, Option<V>> = ExhaustiveMap::default();
while let Some((key, value)) = access.next_entry::<K, V>()? {
map[key] = Some(value);
}
let map = map.try_unwrap_values().map_err(|e| {
A::Error::custom(format!(
"ExhaustiveMap<{}, {}>: found entries for {} keys out of {} keys",
type_name::<K>(),
type_name::<V>(),
e.values().filter(|v| v.is_some()).count(),
K::INHABITANTS::USIZE,
))
})?;
Ok(map)
}
}
impl<'de, K: Finite + Deserialize<'de>, V: Deserialize<'de>> serde::Deserialize<'de>
for ExhaustiveMap<K, V>
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_map(MapVisitor::new())
}
}
#[cfg(test)]
mod test {
use alloc::string::ToString;
use super::*;
#[derive(Debug, Finite, Serialize, Deserialize)]
enum Color {
Red,
Green,
Blue,
}
#[test]
fn test_serialize_deserialize() {
let map = ExhaustiveMap::<Color, _>::from_usize_fn(|i| i);
let json = serde_json::to_string(&map).unwrap();
assert_eq!(json, r#"{"Red":0,"Green":1,"Blue":2}"#);
let deserialized: ExhaustiveMap<Color, usize> = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized, map);
}
#[test]
fn test_deserialize_missing_entry() {
let json = r#"{"Red":0,"Blue":2}"#;
let err = serde_json::from_str::<ExhaustiveMap<Color, usize>>(&json).unwrap_err();
assert!(
err.to_string()
.contains("found entries for 2 keys out of 3 key"),
"{err:?}"
);
}
}
}
#[cfg(all(test, feature = "std"))]
mod test {
use std::{prelude::rust_2024::*, println};
use super::*;
#[derive(Finite)]
struct Key(PhantomData<*mut u8>);
#[allow(unused)]
const fn assert_implements_traits<
T: Send + Sync + Default + Clone + Copy + PartialEq + Eq + PartialOrd + Ord + Hash,
>() {
}
const _: () = assert_implements_traits::<ExhaustiveMap<Key, bool>>();
#[test]
fn test_uninit() {
let mut m = ExhaustiveMap::<bool, u8>::new_uninit();
m[true].write(123);
m[false].write(45);
let m = unsafe { m.assume_init() };
println!("{m:?}");
}
#[test]
fn test_conversion() {
let m: ExhaustiveMap<bool, u8> = [2, 3].try_into().unwrap();
assert_eq!(m[false], 2);
assert_eq!(m[true], 3);
}
#[test]
fn test_try_unrwap_values() {
let m: ExhaustiveMap<bool, Option<u8>> = ExhaustiveMap::from_fn(|_| None);
let mut m = m.try_unwrap_values().unwrap_err();
m[false] = Some(2);
let mut m = m.try_unwrap_values().unwrap_err();
m[true] = Some(3);
let m = m.try_unwrap_values().unwrap();
let expected = ExhaustiveMap::from_fn(|v| if v { 3 } else { 2 });
assert_eq!(m, expected);
}
}