Skip to main content

enum_map/
lib.rs

1// SPDX-FileCopyrightText: 2017 - 2023 Luna Borowska <luna@borowska.pw>
2// SPDX-FileCopyrightText: 2019 Riey <creeper844@gmail.com>
3// SPDX-FileCopyrightText: 2021 Alex Sayers <alex@asayers.com>
4// SPDX-FileCopyrightText: 2021 Bruno CorrĂȘa Zimmermann <brunoczim@gmail.com>
5// SPDX-FileCopyrightText: 2022 Cass Fridkin <cass@cloudflare.com>
6// SPDX-FileCopyrightText: 2022 Mateusz Kowalczyk <fuuzetsu@fuuzetsu.co.uk>
7//
8// SPDX-License-Identifier: MIT OR Apache-2.0
9
10//! An enum mapping type.
11//!
12//! It is implemented using an array type, so using it is as fast as using Rust
13//! arrays.
14//!
15//! # Examples
16//!
17//! ```
18//! # use enum_map_derive::*;
19//! use enum_map::{enum_map, Enum, EnumMap};
20//!
21//! #[derive(Debug, Enum)]
22//! enum Example {
23//!     A(bool),
24//!     B,
25//!     C,
26//! }
27//!
28//! let mut map = enum_map! {
29//!     Example::A(false) => 0,
30//!     Example::A(true) => 1,
31//!     Example::B => 2,
32//!     Example::C => 3,
33//! };
34//! map[Example::C] = 4;
35//!
36//! assert_eq!(map[Example::A(true)], 1);
37//!
38//! for (key, &value) in &map {
39//!     println!("{:?} has {} as value.", key, value);
40//! }
41//! ```
42
43#![no_std]
44#![deny(missing_docs)]
45#![warn(clippy::pedantic)]
46
47#[cfg(feature = "arbitrary")]
48mod arbitrary;
49#[cfg(feature = "bytemuck")]
50mod bytemuck;
51mod enum_map_impls;
52mod internal;
53mod iter;
54#[cfg(feature = "serde")]
55mod serde;
56
57#[doc(hidden)]
58pub use core::mem::{self, ManuallyDrop, MaybeUninit};
59#[doc(hidden)]
60pub use core::primitive::usize;
61use core::{convert::Infallible, slice};
62#[doc(hidden)]
63// unreachable needs to be exported for compatibility with older versions of enum-map-derive
64pub use core::{panic, ptr, unreachable};
65
66#[cfg(feature = "derive")]
67pub use enum_map_derive::Enum;
68use internal::Array;
69pub use internal::Enum;
70#[doc(hidden)]
71pub use internal::out_of_bounds;
72pub use iter::{IntoIter, IntoValues, Iter, IterMut, Values, ValuesMut};
73
74// SAFETY: initialized needs to represent number of initialized elements
75#[doc(hidden)]
76pub struct Guard<'a, K, V>
77where
78    K: Enum,
79{
80    array_mut: &'a mut MaybeUninit<K::Array<V>>,
81    initialized: usize,
82}
83
84impl<K, V> Drop for Guard<'_, K, V>
85where
86    K: Enum,
87{
88    fn drop(&mut self) {
89        // This is safe as arr[..len] is initialized due to
90        // Guard's type invariant.
91        unsafe {
92            ptr::slice_from_raw_parts_mut(self.as_mut_ptr(), self.initialized).drop_in_place();
93        }
94    }
95}
96
97impl<'a, K, V> Guard<'a, K, V>
98where
99    K: Enum,
100{
101    #[doc(hidden)]
102    pub fn as_mut_ptr(&mut self) -> *mut V {
103        self.array_mut.as_mut_ptr().cast::<V>()
104    }
105
106    #[doc(hidden)]
107    #[must_use]
108    pub fn new(array_mut: &'a mut MaybeUninit<K::Array<V>>) -> Self {
109        Self {
110            array_mut,
111            initialized: 0,
112        }
113    }
114
115    #[doc(hidden)]
116    #[must_use]
117    #[allow(clippy::unused_self)]
118    pub fn storage_length(&self) -> usize {
119        // SAFETY: We need to use LENGTH from K::Array, as K::LENGTH is
120        // untrustworthy.
121        K::Array::<V>::LENGTH
122    }
123
124    #[doc(hidden)]
125    #[must_use]
126    pub fn get_key(&self) -> K {
127        K::from_usize(self.initialized)
128    }
129
130    #[doc(hidden)]
131    // Unsafe as it can write out of bounds.
132    pub unsafe fn push(&mut self, value: V) {
133        unsafe {
134            self.as_mut_ptr().add(self.initialized).write(value);
135        }
136        self.initialized += 1;
137    }
138}
139
140#[doc(hidden)]
141pub struct TypeEqualizer<'a, K, V>
142where
143    K: Enum,
144{
145    pub enum_map: [EnumMap<K, V>; 0],
146    pub guard: Guard<'a, K, V>,
147}
148
149/// Enum map constructor.
150///
151/// This macro allows to create a new enum map in a type safe way. It takes
152/// a list of `,` separated pairs separated by `=>`. Left side is `|`
153/// separated list of enum keys, or `_` to match all unmatched enum keys,
154/// while right side is a value.
155///
156/// The iteration order when using this macro is not guaranteed to be
157/// consistent. Future releases of this crate may change it, and this is not
158/// considered to be a breaking change.
159///
160/// # Examples
161///
162/// ```
163/// # use enum_map_derive::*;
164/// use enum_map::{enum_map, Enum};
165///
166/// #[derive(Enum)]
167/// enum Example {
168///     A,
169///     B,
170///     C,
171///     D,
172/// }
173///
174/// let enum_map = enum_map! {
175///     Example::A | Example::B => 1,
176///     Example::C => 2,
177///     _ => 3,
178/// };
179/// assert_eq!(enum_map[Example::A], 1);
180/// assert_eq!(enum_map[Example::B], 1);
181/// assert_eq!(enum_map[Example::C], 2);
182/// assert_eq!(enum_map[Example::D], 3);
183/// ```
184#[macro_export]
185macro_rules! enum_map {
186    {$($t:tt)*} => {{
187        let mut uninit = $crate::MaybeUninit::uninit();
188        let mut eq = $crate::TypeEqualizer {
189            enum_map: [],
190            guard: $crate::Guard::new(&mut uninit),
191        };
192        if false {
193            // Safe because this code is unreachable
194            unsafe { (&mut eq.enum_map).as_mut_ptr().read() }
195        } else {
196            for _ in 0..(&eq.guard).storage_length() {
197                struct __PleaseDoNotUseBreakWithoutLabel;
198                let _please_do_not_use_continue_without_label;
199                let value;
200                #[allow(unreachable_code)]
201                loop {
202                    _please_do_not_use_continue_without_label = ();
203                    value = match (&eq.guard).get_key() { $($t)* };
204                    break __PleaseDoNotUseBreakWithoutLabel;
205                };
206
207                unsafe { (&mut eq.guard).push(value); }
208            }
209            #[allow(clippy::mem_forget, reason = "avoid Drop impl on Guard on success")]
210            $crate::mem::forget(eq);
211            // Safe because the array was fully initialized.
212            $crate::EnumMap::from_array(unsafe { uninit.assume_init() })
213        }
214    }};
215}
216
217/// An enum mapping.
218///
219/// This internally uses an array which stores a value for each possible
220/// enum value. To work, it requires implementation of internal (private,
221/// although public due to macro limitations) trait which allows extracting
222/// information about an enum, which can be automatically generated using
223/// `#[derive(Enum)]` macro.
224///
225/// Additionally, `bool` and `u8` automatically derives from `Enum`. While
226/// `u8` is not technically an enum, it's convenient to consider it like one.
227/// In particular, [reverse-complement in benchmark game] could be using `u8`
228/// as an enum.
229///
230/// # Examples
231///
232/// ```
233/// # use enum_map_derive::*;
234/// use enum_map::{enum_map, Enum, EnumMap};
235///
236/// #[derive(Enum)]
237/// enum Example {
238///     A,
239///     B,
240///     C,
241/// }
242///
243/// let mut map = EnumMap::default();
244/// // new initializes map with default values
245/// assert_eq!(map[Example::A], 0);
246/// map[Example::A] = 3;
247/// assert_eq!(map[Example::A], 3);
248/// ```
249///
250/// [reverse-complement in benchmark game]:
251///     http://benchmarksgame.alioth.debian.org/u64q/program.php?test=revcomp&lang=rust&id=2
252#[repr(transparent)]
253pub struct EnumMap<K: Enum, V> {
254    array: K::Array<V>,
255}
256
257impl<K: Enum, V: Default> EnumMap<K, V> {
258    /// Clear enum map with default values.
259    ///
260    /// # Examples
261    ///
262    /// ```
263    /// # use enum_map_derive::*;
264    /// use enum_map::{Enum, EnumMap};
265    ///
266    /// #[derive(Enum)]
267    /// enum Example {
268    ///     A,
269    ///     B,
270    /// }
271    ///
272    /// let mut enum_map = EnumMap::<_, String>::default();
273    /// enum_map[Example::B] = "foo".into();
274    /// enum_map.clear();
275    /// assert_eq!(enum_map[Example::A], "");
276    /// assert_eq!(enum_map[Example::B], "");
277    /// ```
278    #[inline]
279    pub fn clear(&mut self) {
280        for v in self.as_mut_slice() {
281            *v = V::default();
282        }
283    }
284}
285
286#[allow(clippy::len_without_is_empty)]
287impl<K: Enum, V> EnumMap<K, V> {
288    /// Creates an enum map from array.
289    #[inline]
290    pub const fn from_array(array: K::Array<V>) -> EnumMap<K, V> {
291        EnumMap { array }
292    }
293
294    /// Create an enum map, where each value is the returned value from `cb`
295    /// using provided enum key.
296    ///
297    /// ```
298    /// # use enum_map_derive::*;
299    /// use enum_map::{enum_map, Enum, EnumMap};
300    ///
301    /// #[derive(Enum, PartialEq, Debug)]
302    /// enum Example {
303    ///     A,
304    ///     B,
305    /// }
306    ///
307    /// let map = EnumMap::from_fn(|k| k == Example::A);
308    /// assert_eq!(map, enum_map! { Example::A => true, Example::B => false })
309    /// ```
310    pub fn from_fn<F>(mut cb: F) -> Self
311    where
312        F: FnMut(K) -> V,
313    {
314        enum_map! { k => cb(k) }
315    }
316
317    /// Create an enum map, where each value is the returned value of
318    /// fallible function `cb`, using provided enum key.
319    ///
320    /// ```
321    /// # use enum_map_derive::*;
322    /// use enum_map::{enum_map, Enum, EnumMap};
323    ///
324    /// #[derive(Enum, PartialEq, Debug)]
325    /// enum Example {
326    ///     A,
327    ///     B,
328    /// }
329    ///
330    /// let map = EnumMap::try_from_fn(|k: Example| {
331    ///     if k == Example::A {
332    ///         Ok(4)
333    ///     } else {
334    ///         Err("error")
335    ///     }
336    /// });
337    /// assert_eq!(map, Err("error"))
338    /// ```
339    ///
340    /// # Errors
341    ///
342    /// This returns any errors that `cb` generates.
343    pub fn try_from_fn<F, E>(mut cb: F) -> Result<Self, E>
344    where
345        F: FnMut(K) -> Result<V, E>,
346    {
347        Ok(enum_map! { k => cb(k)? })
348    }
349
350    /// Returns an iterator over enum map.
351    ///
352    /// The iteration order is deterministic, and when using [macro@Enum] derive
353    /// it will be the order in which enum variants are declared.
354    ///
355    /// # Examples
356    ///
357    /// ```
358    /// # use enum_map_derive::*;
359    /// use enum_map::{enum_map, Enum};
360    ///
361    /// #[derive(Enum, PartialEq)]
362    /// enum E {
363    ///     A,
364    ///     B,
365    ///     C,
366    /// }
367    ///
368    /// let map = enum_map! { E::A => 1, E::B => 2, E::C => 3};
369    /// assert!(map.iter().eq([(E::A, &1), (E::B, &2), (E::C, &3)]));
370    /// ```
371    #[inline]
372    pub fn iter(&self) -> Iter<'_, K, V> {
373        self.into_iter()
374    }
375
376    /// Returns a mutable iterator over enum map.
377    #[inline]
378    pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
379        self.into_iter()
380    }
381
382    /// Returns number of elements in enum map.
383    #[inline]
384    #[allow(clippy::unused_self)]
385    pub const fn len(&self) -> usize {
386        K::Array::<V>::LENGTH
387    }
388
389    /// Swaps two indexes.
390    ///
391    /// # Examples
392    ///
393    /// ```
394    /// use enum_map::enum_map;
395    ///
396    /// let mut map = enum_map! { false => 0, true => 1 };
397    /// map.swap(false, true);
398    /// assert_eq!(map[false], 1);
399    /// assert_eq!(map[true], 0);
400    /// ```
401    #[inline]
402    pub fn swap(&mut self, a: K, b: K) {
403        self.as_mut_slice().swap(a.into_usize(), b.into_usize());
404    }
405
406    /// Consumes an enum map and returns the underlying array.
407    ///
408    /// The order of elements is deterministic, and when using [macro@Enum]
409    /// derive it will be the order in which enum variants are declared.
410    ///
411    /// # Examples
412    ///
413    /// ```
414    /// # use enum_map_derive::*;
415    /// use enum_map::{enum_map, Enum};
416    ///
417    /// #[derive(Enum, PartialEq)]
418    /// enum E {
419    ///     A,
420    ///     B,
421    ///     C,
422    /// }
423    ///
424    /// let map = enum_map! { E::A => 1, E::B => 2, E::C => 3};
425    /// assert_eq!(map.into_array(), [1, 2, 3]);
426    /// ```
427    pub fn into_array(self) -> K::Array<V> {
428        self.array
429    }
430
431    /// Returns a reference to the underlying array.
432    ///
433    /// The order of elements is deterministic, and when using [macro@Enum]
434    /// derive it will be the order in which enum variants are declared.
435    ///
436    /// # Examples
437    ///
438    /// ```
439    /// # use enum_map_derive::*;
440    /// use enum_map::{enum_map, Enum};
441    ///
442    /// #[derive(Enum, PartialEq)]
443    /// enum E {
444    ///     A,
445    ///     B,
446    ///     C,
447    /// }
448    ///
449    /// let map = enum_map! { E::A => 1, E::B => 2, E::C => 3};
450    /// assert_eq!(map.as_array(), &[1, 2, 3]);
451    /// ```
452    pub const fn as_array(&self) -> &K::Array<V> {
453        &self.array
454    }
455
456    /// Returns a mutable reference to the underlying array.
457    ///
458    /// The order of elements is deterministic, and when using [macro@Enum]
459    /// derive it will be the order in which enum variants are declared.
460    ///
461    /// # Examples
462    ///
463    /// ```
464    /// # use enum_map_derive::*;
465    /// use enum_map::{enum_map, Enum};
466    ///
467    /// #[derive(Enum, PartialEq)]
468    /// enum E {
469    ///     A,
470    ///     B,
471    ///     C,
472    /// }
473    ///
474    /// let mut map = enum_map! { E::A => 1, E::B => 2, E::C => 3};
475    /// map.as_mut_array()[1] = 42;
476    /// assert_eq!(map.as_array(), &[1, 42, 3]);
477    /// ```
478    pub fn as_mut_array(&mut self) -> &mut K::Array<V> {
479        &mut self.array
480    }
481
482    /// Converts an enum map to a slice representing values.
483    ///
484    /// The order of elements is deterministic, and when using [macro@Enum]
485    /// derive it will be the order in which enum variants are declared.
486    ///
487    /// # Examples
488    ///
489    /// ```
490    /// # use enum_map_derive::*;
491    /// use enum_map::{enum_map, Enum};
492    ///
493    /// #[derive(Enum, PartialEq)]
494    /// enum E {
495    ///     A,
496    ///     B,
497    ///     C,
498    /// }
499    ///
500    /// let map = enum_map! { E::A => 1, E::B => 2, E::C => 3};
501    /// assert_eq!(map.as_slice(), &[1, 2, 3]);
502    /// ```
503    #[inline]
504    pub fn as_slice(&self) -> &[V] {
505        unsafe { slice::from_raw_parts(ptr::addr_of!(self.array).cast(), K::Array::<V>::LENGTH) }
506    }
507
508    /// Converts a mutable enum map to a mutable slice representing values.
509    #[inline]
510    pub fn as_mut_slice(&mut self) -> &mut [V] {
511        unsafe {
512            slice::from_raw_parts_mut(ptr::addr_of_mut!(self.array).cast(), K::Array::<V>::LENGTH)
513        }
514    }
515
516    /// Returns an enum map with function `f` applied to each element in order.
517    ///
518    /// # Examples
519    ///
520    /// ```
521    /// use enum_map::enum_map;
522    ///
523    /// let a = enum_map! { false => 0, true => 1 };
524    /// let b = a.map(|_, x| f64::from(x) + 0.5);
525    /// assert_eq!(b, enum_map! { false => 0.5, true => 1.5 });
526    /// ```
527    #[expect(clippy::missing_panics_doc, reason = "This uses an infallible closure")]
528    pub fn map<F, T>(self, mut f: F) -> EnumMap<K, T>
529    where
530        F: FnMut(K, V) -> T,
531        K: Enum,
532    {
533        self.try_map(|k, v| Ok::<_, Infallible>(f(k, v))).unwrap()
534    }
535
536    /// Applies fallible function `f` to each element of enum map returning
537    /// an enum map of the same key type as `self` or the first error
538    /// encountered.
539    ///
540    /// # Examples
541    ///
542    /// ```
543    /// use enum_map::enum_map;
544    ///
545    /// let a = enum_map! { false => 0, true => 400 };
546    /// let b = a.try_map(|_, x| u8::try_from(x));
547    /// assert!(b.is_err());
548    /// ```
549    ///
550    /// # Errors
551    ///
552    /// This returns any errors that `f` generates.
553    pub fn try_map<F, T, E>(self, mut f: F) -> Result<EnumMap<K, T>, E>
554    where
555        F: FnMut(K, V) -> Result<T, E>,
556        K: Enum,
557    {
558        struct DropOnPanic<K, V>
559        where
560            K: Enum,
561        {
562            position: usize,
563            map: ManuallyDrop<EnumMap<K, V>>,
564        }
565        impl<K, V> Drop for DropOnPanic<K, V>
566        where
567            K: Enum,
568        {
569            fn drop(&mut self) {
570                unsafe {
571                    ptr::drop_in_place(&raw mut self.map.as_mut_slice()[self.position..]);
572                }
573            }
574        }
575        let mut drop_protect = DropOnPanic {
576            position: 0,
577            map: ManuallyDrop::new(self),
578        };
579        Ok(enum_map! {
580            k => {
581                let value = unsafe { ptr::read(&raw const drop_protect.map.as_slice()[drop_protect.position]) };
582                drop_protect.position += 1;
583                f(k, value)?
584            }
585        })
586    }
587}
588
589#[doc(hidden)]
590#[must_use]
591pub const fn enum_len<E: Enum>() -> usize {
592    E::Array::<()>::LENGTH
593}