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 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
// 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 {
/// 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<V>: Enum {
/// Representation of an enum map for type `V`.
type Array: Array<V>;
}
/// 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<V> {
// 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<V> 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<T> EnumArray<T> 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<T> EnumArray<T> 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<T> EnumArray<T> 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<T> EnumArray<T> 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<T> EnumArray<T> for Ordering {
type Array = [T; Self::LENGTH];
}