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
macro_rules! impl_enum {
($ty:ty, $num:literal: $($name:ident => $idx:expr,)*) => {
// SAFETY: The tests below test all conditions.
unsafe impl crate::Linearize for $ty {
type Storage<T> = [T; Self::LENGTH];
type CopyStorage<T>
= [T; Self::LENGTH]
where
T: Copy;
const LENGTH: usize = $num;
#[inline]
fn linearize(&self) -> usize {
match self {
$(<$ty>::$name => $idx,)*
}
}
#[inline]
unsafe fn from_linear_unchecked(linear: usize) -> Self
where
Self: Sized,
{
match linear {
$($idx => <$ty>::$name,)*
_ => unsafe {
// SAFETY: It's a precondition that linear < Self::LENGTH,
cold_unreachable!();
},
}
}
}
impl_assert!($ty, $num);
#[test]
fn test() {
use crate::Linearize;
$(
assert_roundtrip!(<$ty>::$name, $idx);
)*
let variants = [$(<$ty>::$name),*];
assert_eq!(variants.len(), $num);
for (idx, variant) in variants.into_iter().enumerate() {
assert_eq!(variant.linearize(), idx);
}
}
};
}
mod core {
mod cmp {
mod ordering {
impl_enum! {
core::cmp::Ordering, 3:
Less => 0,
Equal => 1,
Greater => 2,
}
}
}
mod fmt {
mod alignment {
impl_enum! {
core::fmt::Alignment, 3:
Left => 0,
Right => 1,
Center => 2,
}
}
}
mod num {
mod fp_category {
impl_enum! {
core::num::FpCategory, 5:
Nan => 0,
Infinite => 1,
Zero => 2,
Subnormal => 3,
Normal => 4,
}
}
}
}
#[cfg(feature = "std")]
mod std {
mod net {
mod shutdown {
impl_enum! {
std::net::Shutdown, 3:
Read => 0,
Write => 1,
Both => 2,
}
}
}
}