From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- third_party/rust/enum-map/src/arbitrary.rs | 28 ++ third_party/rust/enum-map/src/enum_map_impls.rs | 115 ++++++ third_party/rust/enum-map/src/internal.rs | 159 ++++++++ third_party/rust/enum-map/src/iter.rs | 415 +++++++++++++++++++ third_party/rust/enum-map/src/lib.rs | 509 ++++++++++++++++++++++++ third_party/rust/enum-map/src/serde.rs | 98 +++++ 6 files changed, 1324 insertions(+) create mode 100644 third_party/rust/enum-map/src/arbitrary.rs create mode 100644 third_party/rust/enum-map/src/enum_map_impls.rs create mode 100644 third_party/rust/enum-map/src/internal.rs create mode 100644 third_party/rust/enum-map/src/iter.rs create mode 100644 third_party/rust/enum-map/src/lib.rs create mode 100644 third_party/rust/enum-map/src/serde.rs (limited to 'third_party/rust/enum-map/src') diff --git a/third_party/rust/enum-map/src/arbitrary.rs b/third_party/rust/enum-map/src/arbitrary.rs new file mode 100644 index 0000000000..e8c988d292 --- /dev/null +++ b/third_party/rust/enum-map/src/arbitrary.rs @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: 2021 Bruno Corrêa Zimmermann +// SPDX-FileCopyrightText: 2021 Kamila Borowska +// +// SPDX-License-Identifier: MIT OR Apache-2.0 + +use crate::{enum_map, EnumArray, EnumMap}; +use arbitrary::{Arbitrary, Result, Unstructured}; + +/// Requires crate feature `"arbitrary"` +impl<'a, K: EnumArray, V: Arbitrary<'a>> Arbitrary<'a> for EnumMap { + fn arbitrary(u: &mut Unstructured<'a>) -> Result> { + Ok(enum_map! { + _ => Arbitrary::arbitrary(u)?, + }) + } + + fn size_hint(depth: usize) -> (usize, Option) { + if K::LENGTH == 0 { + (0, Some(0)) + } else { + let (lo, hi) = V::size_hint(depth); + ( + lo.saturating_mul(K::LENGTH), + hi.and_then(|hi| hi.checked_mul(K::LENGTH)), + ) + } + } +} diff --git a/third_party/rust/enum-map/src/enum_map_impls.rs b/third_party/rust/enum-map/src/enum_map_impls.rs new file mode 100644 index 0000000000..545ff33ddc --- /dev/null +++ b/third_party/rust/enum-map/src/enum_map_impls.rs @@ -0,0 +1,115 @@ +// SPDX-FileCopyrightText: 2017 - 2021 Kamila Borowska +// SPDX-FileCopyrightText: 2021 Bruno Corrêa Zimmermann +// SPDX-FileCopyrightText: 2021 micycle +// SPDX-FileCopyrightText: 2023 Nicolas Carranza +// +// SPDX-License-Identifier: MIT OR Apache-2.0 + +use crate::{enum_map, EnumArray, EnumMap}; +use core::fmt::{self, Debug, Formatter}; +use core::hash::{Hash, Hasher}; +use core::iter::{Extend, FromIterator}; +use core::ops::{Index, IndexMut}; + +impl + Debug, V: Debug> Debug for EnumMap { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.debug_map().entries(self).finish() + } +} + +impl, V> Extend<(K, V)> for EnumMap { + fn extend>(&mut self, iter: I) { + for (key, value) in iter { + self[key] = value; + } + } +} + +impl<'a, K, V> Extend<(&'a K, &'a V)> for EnumMap +where + K: EnumArray + Copy, + V: Copy, +{ + fn extend>(&mut self, iter: I) { + self.extend(iter.into_iter().map(|(&key, &value)| (key, value))); + } +} + +impl FromIterator<(K, V)> for EnumMap +where + Self: Default, + K: EnumArray, +{ + fn from_iter>(iter: I) -> Self { + let mut map = EnumMap::default(); + map.extend(iter); + map + } +} + +impl, V> Index for EnumMap { + type Output = V; + + #[inline] + fn index(&self, key: K) -> &V { + &self.as_slice()[key.into_usize()] + } +} + +impl, V> IndexMut for EnumMap { + #[inline] + fn index_mut(&mut self, key: K) -> &mut V { + &mut self.as_mut_slice()[key.into_usize()] + } +} + +// Implementations provided by derive attribute are too specific, and put requirements on K. +// This is caused by rust-lang/rust#26925. +impl, V> Clone for EnumMap +where + K::Array: Clone, +{ + #[inline] + fn clone(&self) -> Self { + EnumMap { + array: self.array.clone(), + } + } +} + +impl, V> Copy for EnumMap where K::Array: Copy {} + +impl, V: PartialEq> PartialEq for EnumMap { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.as_slice() == other.as_slice() + } +} + +impl, V: Eq> Eq for EnumMap {} + +impl, V: Hash> Hash for EnumMap { + #[inline] + fn hash(&self, state: &mut H) { + self.as_slice().hash(state); + } +} + +impl, V: Default> Default for EnumMap { + #[inline] + fn default() -> Self { + enum_map! { _ => V::default() } + } +} + +impl, V: PartialOrd> PartialOrd for EnumMap { + fn partial_cmp(&self, other: &Self) -> Option { + self.as_slice().partial_cmp(other.as_slice()) + } +} + +impl, V: Ord> Ord for EnumMap { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + self.as_slice().cmp(other.as_slice()) + } +} diff --git a/third_party/rust/enum-map/src/internal.rs b/third_party/rust/enum-map/src/internal.rs new file mode 100644 index 0000000000..2a6235d09d --- /dev/null +++ b/third_party/rust/enum-map/src/internal.rs @@ -0,0 +1,159 @@ +// SPDX-FileCopyrightText: 2017 - 2023 Kamila Borowska +// SPDX-FileCopyrightText: 2021 Bruno Corrêa Zimmermann +// SPDX-FileCopyrightText: 2022 philipp +// +// SPDX-License-Identifier: MIT OR Apache-2.0 + +use core::cmp::Ordering; +use core::convert::Infallible; + +/// Enum mapping type. +/// +/// This trait is implemented by `#[derive(Enum)]`. +/// +/// This trait is also implemented by `bool` and `u8`. While `u8` is +/// strictly speaking not an actual enum, there are good reasons to consider +/// it like one, as array of `u8` keys is a relatively common pattern. +pub trait Enum: Sized { + /// Length of the enum. + const LENGTH: usize; + + /// Takes an usize, and returns an element matching `into_usize` function. + fn from_usize(value: usize) -> Self; + /// Returns an unique identifier for a value within range of `0..Array::LENGTH`. + fn into_usize(self) -> usize; +} + +/// Trait associating enum with an array. +/// +/// This exists due to limitations of Rust compiler that prevent arrays from using +/// associated constants in structures. The array length must match `LENGTH` of an +/// `Enum`. +pub trait EnumArray: Enum { + /// Representation of an enum map for type `V`. + type Array: Array; +} + +/// Array for enum-map storage. +/// +/// This trait is inteded for primitive array types (with fixed length). +/// +/// # Safety +/// +/// The array length needs to match actual storage. +pub unsafe trait Array { + // This is necessary duplication because the length in Enum trait can be + // provided by user and may not be trustworthy for unsafe code. + const LENGTH: usize; +} + +unsafe impl Array for [V; N] { + const LENGTH: usize = N; +} + +#[doc(hidden)] +#[inline] +pub fn out_of_bounds() -> ! { + panic!("index out of range for Enum::from_usize"); +} + +impl Enum for bool { + const LENGTH: usize = 2; + + #[inline] + fn from_usize(value: usize) -> Self { + match value { + 0 => false, + 1 => true, + _ => out_of_bounds(), + } + } + #[inline] + fn into_usize(self) -> usize { + usize::from(self) + } +} + +impl EnumArray for bool { + type Array = [T; Self::LENGTH]; +} + +impl Enum for () { + const LENGTH: usize = 1; + + #[inline] + fn from_usize(value: usize) -> Self { + match value { + 0 => (), + _ => out_of_bounds(), + } + } + #[inline] + fn into_usize(self) -> usize { + 0 + } +} + +impl EnumArray for () { + type Array = [T; Self::LENGTH]; +} + +impl Enum for u8 { + const LENGTH: usize = 256; + + #[inline] + fn from_usize(value: usize) -> Self { + value.try_into().unwrap_or_else(|_| out_of_bounds()) + } + #[inline] + fn into_usize(self) -> usize { + usize::from(self) + } +} + +impl EnumArray for u8 { + type Array = [T; Self::LENGTH]; +} + +impl Enum for Infallible { + const LENGTH: usize = 0; + + #[inline] + fn from_usize(_: usize) -> Self { + out_of_bounds(); + } + #[inline] + fn into_usize(self) -> usize { + match self {} + } +} + +impl EnumArray for Infallible { + type Array = [T; Self::LENGTH]; +} + +impl Enum for Ordering { + const LENGTH: usize = 3; + + #[inline] + fn from_usize(value: usize) -> Self { + match value { + 0 => Ordering::Less, + 1 => Ordering::Equal, + 2 => Ordering::Greater, + _ => out_of_bounds(), + } + } + #[inline] + fn into_usize(self) -> usize { + match self { + Ordering::Less => 0, + Ordering::Equal => 1, + Ordering::Greater => 2, + } + } +} + +impl EnumArray for Ordering { + type Array = [T; Self::LENGTH]; +} diff --git a/third_party/rust/enum-map/src/iter.rs b/third_party/rust/enum-map/src/iter.rs new file mode 100644 index 0000000000..393d8d1027 --- /dev/null +++ b/third_party/rust/enum-map/src/iter.rs @@ -0,0 +1,415 @@ +#![allow(clippy::module_name_repetitions)] + +// SPDX-FileCopyrightText: 2017 - 2022 Kamila Borowska +// SPDX-FileCopyrightText: 2020 Amanieu d'Antras +// SPDX-FileCopyrightText: 2021 Bruno Corrêa Zimmermann +// +// SPDX-License-Identifier: MIT OR Apache-2.0 + +use crate::{EnumArray, EnumMap}; +use core::iter::{Enumerate, FusedIterator}; +use core::marker::PhantomData; +use core::mem::ManuallyDrop; +use core::ops::Range; +use core::ptr; +use core::slice; + +/// Immutable enum map iterator +/// +/// This struct is created by `iter` method or `into_iter` on a reference +/// to `EnumMap`. +/// +/// # Examples +/// +/// ``` +/// use enum_map::{enum_map, Enum}; +/// +/// #[derive(Enum)] +/// enum Example { +/// A, +/// B, +/// C, +/// } +/// +/// let mut map = enum_map! { Example::A => 3, _ => 0 }; +/// assert_eq!(map[Example::A], 3); +/// for (key, &value) in &map { +/// assert_eq!(value, match key { +/// Example::A => 3, +/// _ => 0, +/// }); +/// } +/// ``` +#[derive(Debug)] +pub struct Iter<'a, K, V: 'a> { + _phantom: PhantomData K>, + iterator: Enumerate>, +} + +impl<'a, K: EnumArray, V> Clone for Iter<'a, K, V> { + fn clone(&self) -> Self { + Iter { + _phantom: PhantomData, + iterator: self.iterator.clone(), + } + } +} + +impl<'a, K: EnumArray, V> Iterator for Iter<'a, K, V> { + type Item = (K, &'a V); + #[inline] + fn next(&mut self) -> Option { + self.iterator + .next() + .map(|(index, item)| (K::from_usize(index), item)) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iterator.size_hint() + } + + fn fold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.iterator + .map(|(index, item)| (K::from_usize(index), item)) + .fold(init, f) + } +} + +impl<'a, K: EnumArray, V> DoubleEndedIterator for Iter<'a, K, V> { + #[inline] + fn next_back(&mut self) -> Option { + self.iterator + .next_back() + .map(|(index, item)| (K::from_usize(index), item)) + } +} + +impl<'a, K: EnumArray, V> ExactSizeIterator for Iter<'a, K, V> {} + +impl<'a, K: EnumArray, V> FusedIterator for Iter<'a, K, V> {} + +impl<'a, K: EnumArray, V> IntoIterator for &'a EnumMap { + type Item = (K, &'a V); + type IntoIter = Iter<'a, K, V>; + #[inline] + fn into_iter(self) -> Self::IntoIter { + Iter { + _phantom: PhantomData, + iterator: self.as_slice().iter().enumerate(), + } + } +} + +/// Mutable map iterator +/// +/// This struct is created by `iter_mut` method or `into_iter` on a mutable +/// reference to `EnumMap`. +/// +/// # Examples +/// +/// ``` +/// use enum_map::{enum_map, Enum}; +/// +/// #[derive(Debug, Enum)] +/// enum Example { +/// A, +/// B, +/// C, +/// } +/// +/// let mut map = enum_map! { Example::A => 3, _ => 0 }; +/// for (_, value) in &mut map { +/// *value += 1; +/// } +/// assert_eq!(map, enum_map! { Example::A => 4, _ => 1 }); +/// ``` +#[derive(Debug)] +pub struct IterMut<'a, K, V: 'a> { + _phantom: PhantomData K>, + iterator: Enumerate>, +} + +impl<'a, K: EnumArray, V> Iterator for IterMut<'a, K, V> { + type Item = (K, &'a mut V); + #[inline] + fn next(&mut self) -> Option { + self.iterator + .next() + .map(|(index, item)| (K::from_usize(index), item)) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iterator.size_hint() + } + + fn fold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.iterator + .map(|(index, item)| (K::from_usize(index), item)) + .fold(init, f) + } +} + +impl<'a, K: EnumArray, V> DoubleEndedIterator for IterMut<'a, K, V> { + #[inline] + fn next_back(&mut self) -> Option { + self.iterator + .next_back() + .map(|(index, item)| (K::from_usize(index), item)) + } +} + +impl<'a, K: EnumArray, V> ExactSizeIterator for IterMut<'a, K, V> {} + +impl<'a, K: EnumArray, V> FusedIterator for IterMut<'a, K, V> {} + +impl<'a, K: EnumArray, V> IntoIterator for &'a mut EnumMap { + type Item = (K, &'a mut V); + type IntoIter = IterMut<'a, K, V>; + #[inline] + fn into_iter(self) -> Self::IntoIter { + IterMut { + _phantom: PhantomData, + iterator: self.as_mut_slice().iter_mut().enumerate(), + } + } +} + +/// A map iterator that moves out of map. +/// +/// This struct is created by `into_iter` on `EnumMap`. +/// +/// # Examples +/// +/// ``` +/// use enum_map::{enum_map, Enum}; +/// +/// #[derive(Debug, Enum)] +/// enum Example { +/// A, +/// B, +/// } +/// +/// let map = enum_map! { Example::A | Example::B => String::from("123") }; +/// for (_, value) in map { +/// assert_eq!(value + "4", "1234"); +/// } +/// ``` +pub struct IntoIter, V> { + map: ManuallyDrop>, + alive: Range, +} + +impl, V> Iterator for IntoIter { + type Item = (K, V); + fn next(&mut self) -> Option<(K, V)> { + let position = self.alive.next()?; + Some((K::from_usize(position), unsafe { + ptr::read(&self.map.as_slice()[position]) + })) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.alive.size_hint() + } +} + +impl, V> DoubleEndedIterator for IntoIter { + fn next_back(&mut self) -> Option<(K, V)> { + let position = self.alive.next_back()?; + Some((K::from_usize(position), unsafe { + ptr::read(&self.map.as_slice()[position]) + })) + } +} + +impl, V> ExactSizeIterator for IntoIter {} + +impl, V> FusedIterator for IntoIter {} + +impl, V> Drop for IntoIter { + #[inline] + fn drop(&mut self) { + unsafe { + ptr::drop_in_place(&mut self.map.as_mut_slice()[self.alive.clone()]); + } + } +} + +impl, V> IntoIterator for EnumMap { + type Item = (K, V); + type IntoIter = IntoIter; + #[inline] + fn into_iter(self) -> Self::IntoIter { + let len = self.len(); + IntoIter { + map: ManuallyDrop::new(self), + alive: 0..len, + } + } +} + +impl, V> EnumMap { + /// An iterator visiting all values. The iterator type is `&V`. + /// + /// # Examples + /// + /// ``` + /// use enum_map::enum_map; + /// + /// let map = enum_map! { false => 3, true => 4 }; + /// let mut values = map.values(); + /// assert_eq!(values.next(), Some(&3)); + /// assert_eq!(values.next(), Some(&4)); + /// assert_eq!(values.next(), None); + /// ``` + #[inline] + pub fn values(&self) -> Values { + Values(self.as_slice().iter()) + } + + /// An iterator visiting all values mutably. The iterator type is `&mut V`. + /// + /// # Examples + /// + /// ``` + /// use enum_map::enum_map; + /// + /// let mut map = enum_map! { _ => 2 }; + /// for value in map.values_mut() { + /// *value += 2; + /// } + /// assert_eq!(map[false], 4); + /// assert_eq!(map[true], 4); + /// ``` + #[inline] + pub fn values_mut(&mut self) -> ValuesMut { + ValuesMut(self.as_mut_slice().iter_mut()) + } + + /// Creates a consuming iterator visiting all the values. The map + /// cannot be used after calling this. The iterator element type + /// is `V`. + /// + /// # Examples + /// + /// ``` + /// use enum_map::enum_map; + /// + /// let mut map = enum_map! { false => "hello", true => "goodbye" }; + /// assert_eq!(map.into_values().collect::>(), ["hello", "goodbye"]); + /// ``` + #[inline] + pub fn into_values(self) -> IntoValues { + IntoValues { + inner: self.into_iter(), + } + } +} + +/// An iterator over the values of `EnumMap`. +/// +/// This `struct` is created by the `values` method of `EnumMap`. +/// See its documentation for more. +pub struct Values<'a, V: 'a>(slice::Iter<'a, V>); + +impl<'a, V> Clone for Values<'a, V> { + fn clone(&self) -> Self { + Values(self.0.clone()) + } +} + +impl<'a, V: 'a> Iterator for Values<'a, V> { + type Item = &'a V; + #[inline] + fn next(&mut self) -> Option<&'a V> { + self.0.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } +} + +impl<'a, V: 'a> DoubleEndedIterator for Values<'a, V> { + #[inline] + fn next_back(&mut self) -> Option<&'a V> { + self.0.next_back() + } +} + +impl<'a, V: 'a> ExactSizeIterator for Values<'a, V> {} + +impl<'a, V: 'a> FusedIterator for Values<'a, V> {} + +/// A mutable iterator over the values of `EnumMap`. +/// +/// This `struct` is created by the `values_mut` method of `EnumMap`. +/// See its documentation for more. +pub struct ValuesMut<'a, V: 'a>(slice::IterMut<'a, V>); + +impl<'a, V: 'a> Iterator for ValuesMut<'a, V> { + type Item = &'a mut V; + #[inline] + fn next(&mut self) -> Option<&'a mut V> { + self.0.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } +} + +impl<'a, V: 'a> DoubleEndedIterator for ValuesMut<'a, V> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut V> { + self.0.next_back() + } +} + +impl<'a, V: 'a> ExactSizeIterator for ValuesMut<'a, V> {} + +impl<'a, V: 'a> FusedIterator for ValuesMut<'a, V> {} + +/// An owning iterator over the values of an `EnumMap`. +/// +/// This `struct` is created by the `into_values` method of `EnumMap`. +/// See its documentation for more. +pub struct IntoValues, V> { + inner: IntoIter, +} + +impl Iterator for IntoValues +where + K: EnumArray, +{ + type Item = V; + + fn next(&mut self) -> Option { + Some(self.inner.next()?.1) + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +impl, V> DoubleEndedIterator for IntoValues { + fn next_back(&mut self) -> Option { + Some(self.inner.next_back()?.1) + } +} + +impl ExactSizeIterator for IntoValues where K: EnumArray {} + +impl FusedIterator for IntoValues where K: EnumArray {} diff --git a/third_party/rust/enum-map/src/lib.rs b/third_party/rust/enum-map/src/lib.rs new file mode 100644 index 0000000000..cb933a3a5c --- /dev/null +++ b/third_party/rust/enum-map/src/lib.rs @@ -0,0 +1,509 @@ +// SPDX-FileCopyrightText: 2017 - 2023 Kamila Borowska +// SPDX-FileCopyrightText: 2019 Riey +// SPDX-FileCopyrightText: 2021 Alex Sayers +// SPDX-FileCopyrightText: 2021 Bruno Corrêa Zimmermann +// SPDX-FileCopyrightText: 2022 Cass Fridkin +// SPDX-FileCopyrightText: 2022 Mateusz Kowalczyk +// +// SPDX-License-Identifier: MIT OR Apache-2.0 + +//! An enum mapping type. +//! +//! It is implemented using an array type, so using it is as fast as using Rust +//! arrays. +//! +//! # Examples +//! +//! ``` +//! use enum_map::{enum_map, Enum, EnumMap}; +//! +//! #[derive(Debug, Enum)] +//! enum Example { +//! A(bool), +//! B, +//! C, +//! } +//! +//! let mut map = enum_map! { +//! Example::A(false) => 0, +//! Example::A(true) => 1, +//! Example::B => 2, +//! Example::C => 3, +//! }; +//! map[Example::C] = 4; +//! +//! assert_eq!(map[Example::A(true)], 1); +//! +//! for (key, &value) in &map { +//! println!("{:?} has {} as value.", key, value); +//! } +//! ``` + +#![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::primitive::usize; +use core::slice; +#[doc(hidden)] +// unreachable needs to be exported for compatibility with older versions of enum-map-derive +pub use core::{panic, ptr, unreachable}; +pub use enum_map_derive::Enum; +#[doc(hidden)] +pub use internal::out_of_bounds; +use internal::Array; +pub use internal::{Enum, EnumArray}; +pub use iter::{IntoIter, IntoValues, Iter, IterMut, Values, ValuesMut}; + +// SAFETY: initialized needs to represent number of initialized elements +#[doc(hidden)] +pub struct Guard<'a, K, V> +where + K: EnumArray, +{ + array_mut: &'a mut MaybeUninit, + initialized: usize, +} + +impl Drop for Guard<'_, K, V> +where + K: EnumArray, +{ + fn drop(&mut self) { + // This is safe as arr[..len] is initialized due to + // Guard's type invariant. + 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, +{ + #[doc(hidden)] + pub fn as_mut_ptr(&mut self) -> *mut V { + self.array_mut.as_mut_ptr().cast::() + } + + #[doc(hidden)] + #[must_use] + pub fn new(array_mut: &'a mut MaybeUninit) -> Self { + Self { + array_mut, + initialized: 0, + } + } + + #[doc(hidden)] + #[must_use] + #[allow(clippy::unused_self)] + pub fn storage_length(&self) -> usize { + // SAFETY: We need to use LENGTH from K::Array, as K::LENGTH is + // untrustworthy. + K::Array::LENGTH + } + + #[doc(hidden)] + #[must_use] + pub fn get_key(&self) -> K { + K::from_usize(self.initialized) + } + + #[doc(hidden)] + // Unsafe as it can write out of bounds. + 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, +{ + pub enum_map: [EnumMap; 0], + pub guard: Guard<'a, K, V>, +} + +/// Enum map constructor. +/// +/// This macro allows to create a new enum map in a type safe way. It takes +/// a list of `,` separated pairs separated by `=>`. Left side is `|` +/// separated list of enum keys, or `_` to match all unmatched enum keys, +/// while right side is a value. +/// +/// The iteration order when using this macro is not guaranteed to be +/// consistent. Future releases of this crate may change it, and this is not +/// considered to be a breaking change. +/// +/// # Examples +/// +/// ``` +/// use enum_map::{enum_map, Enum}; +/// +/// #[derive(Enum)] +/// enum Example { +/// A, +/// B, +/// C, +/// D, +/// } +/// +/// let enum_map = enum_map! { +/// Example::A | Example::B => 1, +/// Example::C => 2, +/// _ => 3, +/// }; +/// assert_eq!(enum_map[Example::A], 1); +/// assert_eq!(enum_map[Example::B], 1); +/// assert_eq!(enum_map[Example::C], 2); +/// assert_eq!(enum_map[Example::D], 3); +/// ``` +#[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 { + // Safe because this code is unreachable + 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); + // Safe because the array was fully initialized. + $crate::EnumMap::from_array(unsafe { uninit.assume_init() }) + } + }}; +} + +/// An enum mapping. +/// +/// This internally uses an array which stores a value for each possible +/// enum value. To work, it requires implementation of internal (private, +/// although public due to macro limitations) trait which allows extracting +/// information about an enum, which can be automatically generated using +/// `#[derive(Enum)]` macro. +/// +/// Additionally, `bool` and `u8` automatically derives from `Enum`. While +/// `u8` is not technically an enum, it's convenient to consider it like one. +/// In particular, [reverse-complement in benchmark game] could be using `u8` +/// as an enum. +/// +/// # Examples +/// +/// ``` +/// use enum_map::{enum_map, Enum, EnumMap}; +/// +/// #[derive(Enum)] +/// enum Example { +/// A, +/// B, +/// C, +/// } +/// +/// let mut map = EnumMap::default(); +/// // new initializes map with default values +/// assert_eq!(map[Example::A], 0); +/// map[Example::A] = 3; +/// assert_eq!(map[Example::A], 3); +/// ``` +/// +/// [reverse-complement in benchmark game]: +/// http://benchmarksgame.alioth.debian.org/u64q/program.php?test=revcomp&lang=rust&id=2 +pub struct EnumMap, V> { + array: K::Array, +} + +impl, V: Default> EnumMap { + /// Clear enum map with default values. + /// + /// # Examples + /// + /// ``` + /// use enum_map::{Enum, EnumMap}; + /// + /// #[derive(Enum)] + /// enum Example { + /// A, + /// B, + /// } + /// + /// let mut enum_map = EnumMap::<_, String>::default(); + /// enum_map[Example::B] = "foo".into(); + /// enum_map.clear(); + /// assert_eq!(enum_map[Example::A], ""); + /// assert_eq!(enum_map[Example::B], ""); + /// ``` + #[inline] + pub fn clear(&mut self) { + for v in self.as_mut_slice() { + *v = V::default(); + } + } +} + +#[allow(clippy::len_without_is_empty)] +impl, V> EnumMap { + /// Creates an enum map from array. + #[inline] + pub const fn from_array(array: K::Array) -> EnumMap { + EnumMap { array } + } + + /// Create an enum map, where each value is the returned value from `cb` + /// using provided enum key. + /// + /// ``` + /// # use enum_map_derive::*; + /// use enum_map::{enum_map, Enum, EnumMap}; + /// + /// #[derive(Enum, PartialEq, Debug)] + /// enum Example { + /// A, + /// B, + /// } + /// + /// let map = EnumMap::from_fn(|k| k == Example::A); + /// assert_eq!(map, enum_map! { Example::A => true, Example::B => false }) + /// ``` + pub fn from_fn(mut cb: F) -> Self + where + F: FnMut(K) -> V, + { + enum_map! { k => cb(k) } + } + + /// Returns an iterator over enum map. + /// + /// The iteration order is deterministic, and when using [macro@Enum] derive + /// it will be the order in which enum variants are declared. + /// + /// # Examples + /// + /// ``` + /// use enum_map::{enum_map, Enum}; + /// + /// #[derive(Enum, PartialEq)] + /// enum E { + /// A, + /// B, + /// C, + /// } + /// + /// let map = enum_map! { E::A => 1, E::B => 2, E::C => 3}; + /// assert!(map.iter().eq([(E::A, &1), (E::B, &2), (E::C, &3)])); + /// ``` + #[inline] + pub fn iter(&self) -> Iter { + self.into_iter() + } + + /// Returns a mutable iterator over enum map. + #[inline] + pub fn iter_mut(&mut self) -> IterMut { + self.into_iter() + } + + /// Returns number of elements in enum map. + #[inline] + #[allow(clippy::unused_self)] + pub const fn len(&self) -> usize { + K::Array::LENGTH + } + + /// Swaps two indexes. + /// + /// # Examples + /// + /// ``` + /// use enum_map::enum_map; + /// + /// let mut map = enum_map! { false => 0, true => 1 }; + /// map.swap(false, true); + /// assert_eq!(map[false], 1); + /// assert_eq!(map[true], 0); + /// ``` + #[inline] + pub fn swap(&mut self, a: K, b: K) { + self.as_mut_slice().swap(a.into_usize(), b.into_usize()); + } + + /// Consumes an enum map and returns the underlying array. + /// + /// The order of elements is deterministic, and when using [macro@Enum] + /// derive it will be the order in which enum variants are declared. + /// + /// # Examples + /// + /// ``` + /// use enum_map::{enum_map, Enum}; + /// + /// #[derive(Enum, PartialEq)] + /// enum E { + /// A, + /// B, + /// C, + /// } + /// + /// let map = enum_map! { E::A => 1, E::B => 2, E::C => 3}; + /// assert_eq!(map.into_array(), [1, 2, 3]); + /// ``` + pub fn into_array(self) -> K::Array { + self.array + } + + /// Returns a reference to the underlying array. + /// + /// The order of elements is deterministic, and when using [macro@Enum] + /// derive it will be the order in which enum variants are declared. + /// + /// # Examples + /// + /// ``` + /// use enum_map::{enum_map, Enum}; + /// + /// #[derive(Enum, PartialEq)] + /// enum E { + /// A, + /// B, + /// C, + /// } + /// + /// let map = enum_map! { E::A => 1, E::B => 2, E::C => 3}; + /// assert_eq!(map.as_array(), &[1, 2, 3]); + /// ``` + pub const fn as_array(&self) -> &K::Array { + &self.array + } + + /// Returns a mutable reference to the underlying array. + /// + /// The order of elements is deterministic, and when using [macro@Enum] + /// derive it will be the order in which enum variants are declared. + /// + /// # Examples + /// + /// ``` + /// use enum_map::{enum_map, Enum}; + /// + /// #[derive(Enum, PartialEq)] + /// enum E { + /// A, + /// B, + /// C, + /// } + /// + /// let mut map = enum_map! { E::A => 1, E::B => 2, E::C => 3}; + /// map.as_mut_array()[1] = 42; + /// assert_eq!(map.as_array(), &[1, 42, 3]); + /// ``` + pub fn as_mut_array(&mut self) -> &mut K::Array { + &mut self.array + } + + /// Converts an enum map to a slice representing values. + /// + /// The order of elements is deterministic, and when using [macro@Enum] + /// derive it will be the order in which enum variants are declared. + /// + /// # Examples + /// + /// ``` + /// use enum_map::{enum_map, Enum}; + /// + /// #[derive(Enum, PartialEq)] + /// enum E { + /// A, + /// B, + /// C, + /// } + /// + /// let map = enum_map! { E::A => 1, E::B => 2, E::C => 3}; + /// assert_eq!(map.as_slice(), &[1, 2, 3]); + /// ``` + #[inline] + pub fn as_slice(&self) -> &[V] { + unsafe { slice::from_raw_parts(ptr::addr_of!(self.array).cast(), K::Array::LENGTH) } + } + + /// Converts a mutable enum map to a mutable slice representing values. + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [V] { + unsafe { slice::from_raw_parts_mut(ptr::addr_of_mut!(self.array).cast(), K::Array::LENGTH) } + } + + /// Returns an enum map with function `f` applied to each element in order. + /// + /// # Examples + /// + /// ``` + /// use enum_map::enum_map; + /// + /// let a = enum_map! { false => 0, true => 1 }; + /// let b = a.map(|_, x| f64::from(x) + 0.5); + /// assert_eq!(b, enum_map! { false => 0.5, true => 1.5 }); + /// ``` + pub fn map(self, mut f: F) -> EnumMap + where + F: FnMut(K, V) -> T, + K: EnumArray, + { + struct DropOnPanic + where + K: EnumArray, + { + position: usize, + map: ManuallyDrop>, + } + impl Drop for DropOnPanic + where + K: EnumArray, + { + 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) + } + } + } +} diff --git a/third_party/rust/enum-map/src/serde.rs b/third_party/rust/enum-map/src/serde.rs new file mode 100644 index 0000000000..9ac434d5d0 --- /dev/null +++ b/third_party/rust/enum-map/src/serde.rs @@ -0,0 +1,98 @@ +// SPDX-FileCopyrightText: 2017 - 2023 Kamila Borowska +// SPDX-FileCopyrightText: 2021 Bruno Corrêa Zimmermann +// +// SPDX-License-Identifier: MIT OR Apache-2.0 + +use crate::{enum_map, EnumArray, EnumMap}; +use core::fmt; +use core::marker::PhantomData; +use serde::de::{self, Deserialize, Deserializer, Error, MapAccess, SeqAccess}; +use serde::ser::{Serialize, SerializeTuple, Serializer}; + +/// Requires crate feature `"serde"` +impl + Serialize, V: Serialize> Serialize for EnumMap { + fn serialize(&self, serializer: S) -> Result { + if serializer.is_human_readable() { + serializer.collect_map(self) + } else { + let mut tup = serializer.serialize_tuple(self.len())?; + for value in self.values() { + tup.serialize_element(value)?; + } + tup.end() + } + } +} + +/// Requires crate feature `"serde"` +impl<'de, K, V> Deserialize<'de> for EnumMap +where + K: EnumArray + EnumArray> + Deserialize<'de>, + V: Deserialize<'de>, +{ + fn deserialize>(deserializer: D) -> Result { + if deserializer.is_human_readable() { + deserializer.deserialize_map(HumanReadableVisitor(PhantomData)) + } else { + deserializer.deserialize_tuple(K::LENGTH, CompactVisitor(PhantomData)) + } + } +} + +struct HumanReadableVisitor(PhantomData<(K, V)>); + +impl<'de, K, V> de::Visitor<'de> for HumanReadableVisitor +where + K: EnumArray + EnumArray> + Deserialize<'de>, + V: Deserialize<'de>, +{ + type Value = EnumMap; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "a map") + } + + fn visit_map>(self, mut access: M) -> Result { + let mut entries = EnumMap::default(); + while let Some((key, value)) = access.next_entry()? { + entries[key] = Some(value); + } + for value in entries.values() { + value + .as_ref() + .ok_or_else(|| M::Error::custom("key not specified"))?; + } + Ok(enum_map! { key => entries[key].take().unwrap() }) + } +} + +struct CompactVisitor(PhantomData<(K, V)>); + +impl<'de, K, V> de::Visitor<'de> for CompactVisitor +where + K: EnumArray + EnumArray> + Deserialize<'de>, + V: Deserialize<'de>, +{ + type Value = EnumMap; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "a sequence") + } + + fn visit_seq>(self, mut access: M) -> Result { + let mut entries = EnumMap::default(); + let len = entries.len(); + { + let mut iter = entries.values_mut(); + while let Some(place) = iter.next() { + *place = Some(access.next_element()?.ok_or_else(|| { + M::Error::invalid_length( + len - iter.len() - 1, + &"a sequence with as many elements as there are variants", + ) + })?); + } + } + Ok(enum_map! { key => entries[key].take().unwrap() }) + } +} -- cgit v1.2.3