#![no_std]
#![deny(missing_docs)]
#![warn(clippy::pedantic)]
#[cfg(feature = "arbitrary")]
mod arbitrary;
mod enum_map_impls;
mod internal;
mod iter;
#[cfg(feature = "serde")]
mod serde;
#[doc(hidden)]
pub use core::mem::{self, ManuallyDrop, MaybeUninit};
#[doc(hidden)]
pub use core::ptr;
pub use enum_map_derive::Enum;
use internal::Array;
pub use internal::{Enum, EnumArray};
pub use iter::{IntoIter, Iter, IterMut, Values, ValuesMut};
#[doc(hidden)]
pub struct Guard<'a, K, V>
where
K: EnumArray<V>,
{
array_mut: &'a mut MaybeUninit<K::Array>,
initialized: usize,
}
impl<K, V> Drop for Guard<'_, K, V>
where
K: EnumArray<V>,
{
fn drop(&mut self) {
unsafe {
ptr::slice_from_raw_parts_mut(self.as_mut_ptr(), self.initialized).drop_in_place();
}
}
}
impl<'a, K, V> Guard<'a, K, V>
where
K: EnumArray<V>,
{
#[doc(hidden)]
pub fn as_mut_ptr(&mut self) -> *mut V {
self.array_mut.as_mut_ptr().cast::<V>()
}
#[doc(hidden)]
#[must_use]
pub fn new(array_mut: &'a mut MaybeUninit<K::Array>) -> Self {
Self {
array_mut,
initialized: 0,
}
}
#[doc(hidden)]
#[must_use]
#[allow(clippy::unused_self)]
pub fn storage_length(&self) -> usize {
K::Array::LENGTH
}
#[doc(hidden)]
#[must_use]
pub fn get_key(&self) -> K {
K::from_usize(self.initialized)
}
#[doc(hidden)]
pub unsafe fn push(&mut self, value: V) {
self.as_mut_ptr().add(self.initialized).write(value);
self.initialized += 1;
}
}
#[doc(hidden)]
pub struct TypeEqualizer<'a, K, V>
where
K: EnumArray<V>,
{
pub enum_map: [EnumMap<K, V>; 0],
pub guard: Guard<'a, K, V>,
}
#[macro_export]
macro_rules! enum_map {
{$($t:tt)*} => {{
let mut uninit = $crate::MaybeUninit::uninit();
let mut eq = $crate::TypeEqualizer {
enum_map: [],
guard: $crate::Guard::new(&mut uninit),
};
if false {
unsafe { (&mut eq.enum_map).as_mut_ptr().read() }
} else {
for _ in 0..(&eq.guard).storage_length() {
struct __PleaseDoNotUseBreakWithoutLabel;
let _please_do_not_use_continue_without_label;
let value;
#[allow(unreachable_code)]
loop {
_please_do_not_use_continue_without_label = ();
value = match (&eq.guard).get_key() { $($t)* };
break __PleaseDoNotUseBreakWithoutLabel;
};
unsafe { (&mut eq.guard).push(value); }
}
$crate::mem::forget(eq);
$crate::EnumMap::from_array(unsafe { uninit.assume_init() })
}
}};
}
pub struct EnumMap<K: EnumArray<V>, V> {
array: K::Array,
}
impl<K: EnumArray<V>, V: Default> EnumMap<K, V> {
#[inline]
pub fn clear(&mut self) {
for v in self.as_mut_slice() {
*v = V::default();
}
}
}
#[allow(clippy::len_without_is_empty)]
impl<K: EnumArray<V>, V> EnumMap<K, V> {
#[inline]
pub fn from_array(array: K::Array) -> EnumMap<K, V> {
EnumMap { array }
}
#[inline]
pub fn iter(&self) -> Iter<K, V> {
self.into_iter()
}
#[inline]
pub fn iter_mut(&mut self) -> IterMut<K, V> {
self.into_iter()
}
#[inline]
pub fn len(&self) -> usize {
self.as_slice().len()
}
#[inline]
pub fn swap(&mut self, a: K, b: K) {
self.as_mut_slice().swap(a.into_usize(), b.into_usize());
}
#[inline]
pub fn as_slice(&self) -> &[V] {
self.array.slice()
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [V] {
self.array.slice_mut()
}
pub fn map<F, T>(self, mut f: F) -> EnumMap<K, T>
where
F: FnMut(K, V) -> T,
K: EnumArray<T>,
{
struct DropOnPanic<K, V>
where
K: EnumArray<V>,
{
position: usize,
map: ManuallyDrop<EnumMap<K, V>>,
}
impl<K, V> Drop for DropOnPanic<K, V>
where
K: EnumArray<V>,
{
fn drop(&mut self) {
unsafe {
ptr::drop_in_place(&mut self.map.as_mut_slice()[self.position..]);
}
}
}
let mut drop_protect = DropOnPanic {
position: 0,
map: ManuallyDrop::new(self),
};
enum_map! {
k => {
let value = unsafe { ptr::read(&drop_protect.map.as_slice()[drop_protect.position]) };
drop_protect.position += 1;
f(k, value)
}
}
}
}