1#![no_std]
2#![allow(private_bounds)]
3
4mod utils;
33
34use crate::utils::{
35 assume_init_array, into_usize, transmute_safe, ConstIntoUSize, ConstUSize, Is, IsConstUSize,
36 TransmuteSafe,
37};
38use core::marker::PhantomData;
39use core::mem::MaybeUninit;
40use core::ops::{Index, IndexMut};
41use derive_where::derive_where;
42
43pub use const_default::ConstDefault;
45
46pub use const_assoc_derive::PrimitiveEnum;
48
49#[macro_export]
70macro_rules! assoc {
71 ($($key:expr => $value:expr),* $(,)?) => {
72 {
73 let phantom_values = $crate::assoc_macro_private::PhantomArray::new(&[$($value),*]);
74
75 if $crate::assoc_macro_private::has_duplicate_keys(&[$($key),*], phantom_values) {
76 panic!("A `ConstArrayMap` cannot have two values with identical keys.");
77 }
78
79 let mut map = $crate::Assoc::<_, _>::new_uninit();
80
81 $(
82 *map.const_get_mut($key) = ::core::mem::MaybeUninit::new($value);
83 )*
84
85 unsafe { map.assume_init() }
96 }
97 };
98}
99
100#[doc(hidden)]
101pub mod assoc_macro_private {
102 use crate::{key_to_index, Key, KeyImpl};
103 use core::marker::PhantomData;
104
105 pub const fn has_duplicate_keys<K: Key, V, const N: usize>(
106 keys: &[K; N],
107 _values: PhantomArray<V, N>,
108 ) -> bool
109 where
110 K::Impl: KeyImpl<Storage<V> = [V; N]>,
111 {
112 let mut i = 0;
113
114 while i < N {
115 let mut j = i + 1;
116
117 while j < N {
118 if key_to_index(keys[i]) == key_to_index(keys[j]) {
119 return true;
120 }
121
122 j += 1;
123 }
124
125 i += 1;
126 }
127
128 false
129 }
130
131 pub struct PhantomArray<T, const N: usize>(PhantomData<[T; N]>);
132
133 impl<T, const N: usize> PhantomArray<T, N> {
134 #[inline(always)]
135 pub const fn new(_array: &[T; N]) -> Self {
136 PhantomArray(PhantomData)
137 }
138 }
139}
140
141#[repr(transparent)]
143pub struct Assoc<K: Key, V> {
144 storage: <K::Impl as KeyImpl>::Storage<V>,
145}
146
147impl<K: Key, V: ConstDefault> ConstDefault for Assoc<K, V>
148where
149 <K::Impl as KeyImpl>::Storage<V>: ConstDefault,
150{
151 const DEFAULT: Self = Self {
152 storage: <<K::Impl as KeyImpl>::Storage<V>>::DEFAULT,
153 };
154}
155
156impl<K: Key, V: ConstDefault> Default for Assoc<K, V>
157where
158 <K::Impl as KeyImpl>::Storage<V>: Default,
159{
160 fn default() -> Self {
161 Self {
162 storage: <<K::Impl as KeyImpl>::Storage<V> as Default>::default(),
163 }
164 }
165}
166
167impl<K: Key, V, const N: usize> Assoc<K, V>
168where
169 K::Impl: KeyImpl<Storage<V> = [V; N]>,
170{
171 pub const LEN: usize = N;
172
173 pub const fn from_values(values: [V; N]) -> Self {
174 Self { storage: values }
175 }
176
177 #[inline(always)]
178 pub const fn len(&self) -> usize {
179 Self::LEN
180 }
181
182 #[inline(always)]
183 pub const fn is_empty(&self) -> bool {
184 self.len() == 0
185 }
186
187 #[inline(always)]
189 pub fn get(&self, key: K) -> &V {
190 let idx = key_to_index(key);
191 unsafe { self.storage.get_unchecked(idx) }
194 }
195
196 #[inline(always)]
201 pub const fn const_get(&self, key: K) -> &V {
202 let idx = key_to_index(key);
203 &self.storage[idx]
204 }
205
206 #[inline(always)]
208 pub fn get_mut(&mut self, key: K) -> &mut V {
209 let idx = key_to_index(key);
210 unsafe { self.storage.get_unchecked_mut(idx) }
213 }
214
215 #[inline(always)]
220 pub const fn const_get_mut(&mut self, key: K) -> &mut V {
221 let idx = key_to_index(key);
222 &mut self.storage[idx]
223 }
224
225 pub fn into_values(self) -> impl Iterator<Item = V> {
228 self.storage.into_iter()
229 }
230
231 pub fn values(&self) -> impl Iterator<Item = &V> {
234 self.storage.iter()
235 }
236
237 pub fn values_mut(&mut self) -> impl Iterator<Item = &mut V> {
240 self.storage.iter_mut()
241 }
242}
243
244impl<K: Key, V, const N: usize> Index<K> for Assoc<K, V>
245where
246 K::Impl: KeyImpl<Storage<V> = [V; N]>,
247{
248 type Output = V;
249
250 #[inline(always)]
251 fn index(&self, index: K) -> &Self::Output {
252 self.get(index)
253 }
254}
255
256impl<K: Key, V, const N: usize> IndexMut<K> for Assoc<K, V>
257where
258 K::Impl: KeyImpl<Storage<V> = [V; N]>,
259{
260 #[inline(always)]
261 fn index_mut(&mut self, index: K) -> &mut Self::Output {
262 self.get_mut(index)
263 }
264}
265
266impl<K: Key, V, const N: usize> Assoc<K, MaybeUninit<V>>
267where
268 K::Impl: KeyImpl<Storage<V> = [V; N]>,
269 K::Impl: KeyImpl<Storage<MaybeUninit<V>> = [MaybeUninit<V>; N]>,
270{
271 pub const fn new_uninit() -> Self {
272 let storage: [MaybeUninit<V>; N] = unsafe { MaybeUninit::uninit().assume_init() };
275 Self { storage }
276 }
277
278 pub const unsafe fn assume_init(self) -> Assoc<K, V> {
287 Assoc {
288 storage: unsafe { assume_init_array(self.storage) },
291 }
292 }
293}
294
295unsafe trait KeyImpl: Copy + TransmuteSafe<Self::Repr> {
301 type Storage<V>;
302 type Repr: Copy + ConstIntoUSize;
303}
304
305#[doc(hidden)]
306#[inline(always)]
307pub const fn key_to_index<K: Key>(key: K) -> usize {
308 let key_impl = transmute_safe(key);
309 key_impl_to_index(key_impl)
310}
311
312#[inline(always)]
313const fn key_impl_to_index<K: KeyImpl>(key: K) -> usize {
314 let repr: K::Repr = transmute_safe(key);
315 into_usize(repr)
316}
317
318trait Key: TransmuteSafe<Self::Impl> {
320 type Impl: KeyImpl;
321}
322
323#[repr(transparent)]
324#[derive_where(Copy, Clone)]
325struct EnumKeyImpl<T: PrimitiveEnum, _U>(T, PhantomData<_U>);
326
327unsafe impl<T: PrimitiveEnum, _U> TransmuteSafe<EnumKeyImpl<T, _U>> for T {}
329
330unsafe impl<T: PrimitiveEnum, _U>
334 TransmuteSafe<<T::Layout as PrimitiveEnumLayoutTrait>::Discriminant> for EnumKeyImpl<T, _U>
335{
336}
337
338impl<T: PrimitiveEnum> Key for T
339where
340 EnumKeyImpl<T, <<T as PrimitiveEnum>::Layout as PrimitiveEnumLayoutTrait>::MaxVariants>:
341 KeyImpl,
342{
343 type Impl = EnumKeyImpl<T, <T::Layout as PrimitiveEnumLayoutTrait>::MaxVariants>;
344}
345
346pub unsafe trait PrimitiveEnum: Copy {
352 type Layout: PrimitiveEnumLayoutTrait;
354}
355
356unsafe impl<T: PrimitiveEnum, const MAX_VARIANTS: usize> KeyImpl
360 for EnumKeyImpl<T, ConstUSize<MAX_VARIANTS>>
361where
362 <<T as PrimitiveEnum>::Layout as PrimitiveEnumLayoutTrait>::MaxVariants:
363 Is<ConstUSize<MAX_VARIANTS>>,
364 EnumKeyImpl<T, ConstUSize<MAX_VARIANTS>>:
365 TransmuteSafe<<<T as PrimitiveEnum>::Layout as PrimitiveEnumLayoutTrait>::Discriminant>,
366{
367 type Storage<V> = [V; MAX_VARIANTS];
368 type Repr = <<T as PrimitiveEnum>::Layout as PrimitiveEnumLayoutTrait>::Discriminant;
369}
370
371trait PrimitiveEnumLayoutTrait {
373 type Discriminant: Copy + ConstIntoUSize;
374 type MaxVariants: IsConstUSize;
375}
376
377pub struct PrimitiveEnumLayout<Discriminant, const MAX_MAX_VARIANTS: usize> {
384 _marker: PhantomData<Discriminant>,
385}
386
387impl<Discriminant, const MAX_VARIANTS: usize> PrimitiveEnumLayoutTrait
388 for PrimitiveEnumLayout<Discriminant, MAX_VARIANTS>
389where
390 Discriminant: Copy + ConstIntoUSize,
391{
392 type Discriminant = Discriminant;
393 type MaxVariants = ConstUSize<MAX_VARIANTS>;
394}