1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
// SPDX-FileCopyrightText: 2017 - 2023 Kamila Borowska <kamila@borowska.pw>
// SPDX-FileCopyrightText: 2021 Bruno Corrêa Zimmermann <brunoczim@gmail.com>
// SPDX-FileCopyrightText: 2022 philipp <descpl@yahoo.de>
//
// 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 {
/// Representation of an enum.
///
/// For an enum with four elements it looks like this.
///
/// ```
/// type Array<V> = [V; 4];
/// ```
type Array<V>: Array;
/// 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;
}
/// 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<V, const N: usize> 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 {
type Array<V> = [V; 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 Enum for () {
type Array<V> = [V; 1];
#[inline]
fn from_usize(value: usize) -> Self {
match value {
0 => (),
_ => out_of_bounds(),
}
}
#[inline]
fn into_usize(self) -> usize {
0
}
}
impl Enum for u8 {
type Array<V> = [V; 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 Enum for Infallible {
type Array<V> = [V; 0];
#[inline]
fn from_usize(_: usize) -> Self {
out_of_bounds();
}
#[inline]
fn into_usize(self) -> usize {
match self {}
}
}
impl Enum for Ordering {
type Array<V> = [V; 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,
}
}
}