Skip to main content

enum_map/
internal.rs

1// SPDX-FileCopyrightText: 2017 - 2023 Luna Borowska <luna@borowska.pw>
2// SPDX-FileCopyrightText: 2021 Bruno CorrĂȘa Zimmermann <brunoczim@gmail.com>
3// SPDX-FileCopyrightText: 2022 philipp <descpl@yahoo.de>
4//
5// SPDX-License-Identifier: MIT OR Apache-2.0
6
7use core::cmp::Ordering;
8use core::convert::Infallible;
9
10/// Enum mapping type.
11///
12/// This trait is implemented by `#[derive(Enum)]`.
13///
14/// This trait is also implemented by `bool` and `u8`. While `u8` is
15/// strictly speaking not an actual enum, there are good reasons to consider
16/// it like one, as array of `u8` keys is a relatively common pattern.
17pub trait Enum: Sized {
18    /// Representation of an enum.
19    ///
20    /// For an enum with four elements it looks like this.
21    ///
22    /// ```
23    /// type Array<V> = [V; 4];
24    /// ```
25    type Array<V>: Array<Value = V>;
26
27    /// Takes an usize, and returns an element matching `into_usize` function.
28    fn from_usize(value: usize) -> Self;
29    /// Returns an unique identifier for a value within range of `0..Array::LENGTH`.
30    fn into_usize(self) -> usize;
31}
32
33/// Representation of an enum, which can only be an array.
34// SAFETY: Can only be an array, however it's not marked as `unsafe`
35// for documentation, as it's sealed anyways.
36pub trait Array: Sealed {
37    /// Number of elements in an enum.
38    const LENGTH: usize;
39
40    /// Type of elements stored in an array representation of an enum.
41    type Value;
42}
43
44impl<V, const N: usize> Array for [V; N] {
45    const LENGTH: usize = N;
46    type Value = V;
47}
48
49pub trait Sealed {}
50impl<V, const N: usize> Sealed for [V; N] {}
51
52#[doc(hidden)]
53#[inline]
54pub fn out_of_bounds() -> ! {
55    panic!("index out of range for Enum::from_usize");
56}
57
58impl Enum for bool {
59    type Array<V> = [V; 2];
60
61    #[inline]
62    fn from_usize(value: usize) -> Self {
63        match value {
64            0 => false,
65            1 => true,
66            _ => out_of_bounds(),
67        }
68    }
69    #[inline]
70    fn into_usize(self) -> usize {
71        usize::from(self)
72    }
73}
74
75impl Enum for () {
76    type Array<V> = [V; 1];
77
78    #[inline]
79    fn from_usize(value: usize) -> Self {
80        match value {
81            0 => (),
82            _ => out_of_bounds(),
83        }
84    }
85    #[inline]
86    fn into_usize(self) -> usize {
87        0
88    }
89}
90
91impl Enum for u8 {
92    type Array<V> = [V; 256];
93
94    #[inline]
95    fn from_usize(value: usize) -> Self {
96        value.try_into().unwrap_or_else(|_| out_of_bounds())
97    }
98    #[inline]
99    fn into_usize(self) -> usize {
100        usize::from(self)
101    }
102}
103
104impl Enum for Infallible {
105    type Array<V> = [V; 0];
106
107    #[inline]
108    fn from_usize(_: usize) -> Self {
109        out_of_bounds();
110    }
111    #[inline]
112    fn into_usize(self) -> usize {
113        match self {}
114    }
115}
116
117impl Enum for Ordering {
118    type Array<V> = [V; 3];
119
120    #[inline]
121    fn from_usize(value: usize) -> Self {
122        match value {
123            0 => Ordering::Less,
124            1 => Ordering::Equal,
125            2 => Ordering::Greater,
126            _ => out_of_bounds(),
127        }
128    }
129    #[inline]
130    fn into_usize(self) -> usize {
131        match self {
132            Ordering::Less => 0,
133            Ordering::Equal => 1,
134            Ordering::Greater => 2,
135        }
136    }
137}