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