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}