checked_enum/
lib.rs

1use std::cmp::Ordering;
2use std::fmt;
3use std::hash::{Hash, Hasher};
4
5pub trait CheckedEnum: Sized + 'static {
6    type Storage: Copy + Clone + 'static;
7
8    fn try_from_storage(val: Self::Storage) -> Option<Self>;
9    fn to_storage(self) -> Self::Storage;
10}
11
12pub struct UncheckedEnum<T>
13where
14    T: CheckedEnum,
15{
16    pub value: T::Storage,
17}
18
19impl<T> Copy for UncheckedEnum<T> where T: CheckedEnum {}
20impl<T> Clone for UncheckedEnum<T>
21where
22    T: CheckedEnum,
23{
24    fn clone(&self) -> Self {
25        *self
26    }
27}
28
29impl<T> fmt::Debug for UncheckedEnum<T>
30where
31    T: CheckedEnum,
32    T: fmt::Debug,
33    T::Storage: fmt::Debug,
34{
35    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
36        fmt.debug_struct("UncheckedEnum")
37            .field("enum", &self.as_enum())
38            .field("value", &self.value)
39            .finish()
40    }
41}
42
43impl<T> PartialEq for UncheckedEnum<T>
44where
45    T: CheckedEnum,
46    T::Storage: PartialEq,
47{
48    fn eq(&self, other: &Self) -> bool {
49        self.value == other.value
50    }
51
52    fn ne(&self, other: &Self) -> bool {
53        self.value != other.value
54    }
55}
56
57impl<T> PartialEq<T> for UncheckedEnum<T>
58where
59    T: CheckedEnum,
60    T: PartialEq,
61{
62    fn eq(&self, other: &T) -> bool {
63        T::try_from_storage(self.value).as_ref() == Some(other)
64    }
65}
66
67impl<T> PartialEq<Option<T>> for UncheckedEnum<T>
68where
69    T: CheckedEnum,
70    T: PartialEq,
71{
72    fn eq(&self, other: &Option<T>) -> bool {
73        T::try_from_storage(self.value) == *other
74    }
75}
76
77impl<T> Eq for UncheckedEnum<T>
78where
79    T: CheckedEnum,
80    T::Storage: Eq,
81{
82}
83
84impl<T> PartialOrd for UncheckedEnum<T>
85where
86    T: CheckedEnum,
87    T::Storage: PartialOrd,
88{
89    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
90        self.value.partial_cmp(&other.value)
91    }
92}
93
94impl<T> Ord for UncheckedEnum<T>
95where
96    T: CheckedEnum,
97    T::Storage: Ord,
98{
99    fn cmp(&self, other: &Self) -> Ordering {
100        self.value.cmp(&other.value)
101    }
102}
103
104impl<T> Hash for UncheckedEnum<T>
105where
106    T: CheckedEnum,
107    T::Storage: Hash,
108{
109    fn hash<H>(&self, state: &mut H)
110    where
111        H: Hasher,
112    {
113        self.value.hash(state)
114    }
115}
116
117impl<T> UncheckedEnum<T>
118where
119    T: CheckedEnum,
120{
121    #[inline]
122    pub fn new(value: T::Storage) -> Self {
123        UncheckedEnum { value }
124    }
125
126    #[inline]
127    pub fn as_enum(self) -> Option<T> {
128        T::try_from_storage(self.value)
129    }
130
131    #[inline]
132    pub unsafe fn as_enum_unchecked(&self) -> T {
133        ::std::mem::transmute_copy(self)
134    }
135}
136
137impl<T> From<T> for UncheckedEnum<T>
138where
139    T: CheckedEnum,
140{
141    fn from(val: T) -> UncheckedEnum<T> {
142        UncheckedEnum::new(T::to_storage(val))
143    }
144}
145
146macro_rules! imp_from_prim {
147    ($prim:ident) => {
148        impl<T> From< $prim > for UncheckedEnum<T>
149        where
150            T: CheckedEnum<Storage = $prim>,
151        {
152            #[inline]
153            fn from(value: T::Storage) -> Self {
154                UncheckedEnum::new(value)
155            }
156        }
157    };
158    ($($prim:ident)*) => {
159        $(imp_from_prim!($prim);)*
160    }
161}
162
163imp_from_prim!(i8 u8 i16 u16 i32 u32 i64 u64 isize usize);
164
165#[macro_export]
166macro_rules! checked_enum {
167    ($ety:ident($repr:ty) => { $from:ident, $to:ident }) => {
168        impl $crate::CheckedEnum for $ety {
169            type Storage = $repr;
170
171            #[inline]
172            fn try_from_storage(val: Self::Storage) -> Option<Self> {
173                $ety::$from(val)
174            }
175
176            #[inline]
177            fn to_storage(self) -> Self::Storage {
178                $ety::$to(self)
179            }
180        }
181    };
182}