enum_table/impls/
std.rs

1use core::ops::{Index, IndexMut};
2
3use crate::{EnumTable, Enumable};
4
5impl<K: Enumable + core::fmt::Debug, V: core::fmt::Debug, const N: usize> core::fmt::Debug
6    for EnumTable<K, V, N>
7{
8    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
9        f.debug_map().entries(self.iter()).finish()
10    }
11}
12
13impl<K: Enumable, V: Clone, const N: usize> Clone for EnumTable<K, V, N> {
14    fn clone(&self) -> Self {
15        Self {
16            table: self.table.clone(),
17        }
18    }
19}
20
21impl<K: Enumable, V: Copy, const N: usize> Copy for EnumTable<K, V, N> {}
22
23impl<K: Enumable, V: PartialEq, const N: usize> PartialEq for EnumTable<K, V, N> {
24    fn eq(&self, other: &Self) -> bool {
25        // Manually implement `PartialEq` to avoid adding a `K: PartialEq` bound,
26        // which would be a breaking change. We can compare the enum discriminants
27        // directly using intrinsics.
28        let mut i = 0;
29        while i < N {
30            if crate::intrinsics::const_enum_eq(&self.table[i].0, &other.table[i].0)
31                && self.table[i].1 == other.table[i].1
32            {
33                i += 1;
34            } else {
35                return false;
36            }
37        }
38        true
39    }
40}
41
42impl<K: Enumable, V: Eq, const N: usize> Eq for EnumTable<K, V, N> {}
43
44impl<K: Enumable, V: core::hash::Hash, const N: usize> core::hash::Hash for EnumTable<K, V, N> {
45    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
46        for (discriminant, value) in self.table.iter() {
47            crate::intrinsics::hash(discriminant, state);
48            value.hash(state);
49        }
50    }
51}
52
53impl<K: Enumable, V: Default, const N: usize> Default for EnumTable<K, V, N> {
54    fn default() -> Self {
55        EnumTable::new_with_fn(|_| Default::default())
56    }
57}
58
59impl<K: Enumable, V, const N: usize> Index<K> for EnumTable<K, V, N> {
60    type Output = V;
61
62    fn index(&self, index: K) -> &Self::Output {
63        self.get(&index)
64    }
65}
66
67impl<K: Enumable, V, const N: usize> IndexMut<K> for EnumTable<K, V, N> {
68    fn index_mut(&mut self, index: K) -> &mut Self::Output {
69        self.get_mut(&index)
70    }
71}
72
73impl<K: Enumable, V, const N: usize> IntoIterator for EnumTable<K, V, N> {
74    type Item = (K, V);
75    type IntoIter = core::array::IntoIter<(K, V), N>;
76
77    fn into_iter(self) -> Self::IntoIter {
78        self.table.into_iter()
79    }
80}
81
82impl<'a, K: Enumable, V, const N: usize> IntoIterator for &'a EnumTable<K, V, N> {
83    type Item = (&'a K, &'a V);
84    type IntoIter =
85        core::iter::Map<core::slice::Iter<'a, (K, V)>, fn(&'a (K, V)) -> (&'a K, &'a V)>;
86
87    fn into_iter(self) -> Self::IntoIter {
88        self.table
89            .iter()
90            .map(|(discriminant, value)| (discriminant, value))
91    }
92}
93
94impl<'a, K: Enumable, V, const N: usize> IntoIterator for &'a mut EnumTable<K, V, N> {
95    type Item = (&'a K, &'a mut V);
96    type IntoIter =
97        core::iter::Map<core::slice::IterMut<'a, (K, V)>, fn(&'a mut (K, V)) -> (&'a K, &'a mut V)>;
98
99    fn into_iter(self) -> Self::IntoIter {
100        self.table
101            .iter_mut()
102            .map(|(discriminant, value)| (discriminant, value))
103    }
104}
105
106#[cfg(test)]
107mod tests {
108    use core::hash::{Hash, Hasher};
109
110    use super::*;
111
112    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Enumable)]
113    enum Color {
114        Red,
115        Green,
116        Blue,
117    }
118
119    const TABLES: EnumTable<Color, &'static str, { Color::COUNT }> =
120        crate::et!(Color, &'static str, |color| match color {
121            Color::Red => "Red",
122            Color::Green => "Green",
123            Color::Blue => "Blue",
124        });
125
126    const ANOTHER_TABLES: EnumTable<Color, &'static str, { Color::COUNT }> =
127        crate::et!(Color, &'static str, |color| match color {
128            Color::Red => "Red",
129            Color::Green => "Green",
130            Color::Blue => "Blue",
131        });
132
133    #[test]
134    fn debug_impl() {
135        assert_eq!(
136            format!("{TABLES:?}"),
137            r#"{Red: "Red", Green: "Green", Blue: "Blue"}"#
138        );
139    }
140
141    #[test]
142    fn eq_impl() {
143        assert!(TABLES == ANOTHER_TABLES);
144        assert!(TABLES != EnumTable::new_with_fn(|_| "Unknown"));
145    }
146
147    #[test]
148    fn hash_impl() {
149        let mut hasher = std::collections::hash_map::DefaultHasher::new();
150        TABLES.hash(&mut hasher);
151        let hash1 = hasher.finish();
152
153        let mut hasher2 = std::collections::hash_map::DefaultHasher::new();
154        ANOTHER_TABLES.hash(&mut hasher2);
155        let hash2 = hasher2.finish();
156
157        assert_eq!(hash1, hash2);
158    }
159
160    #[test]
161    fn default_impl() {
162        let default_table: EnumTable<Color, &'static str, { Color::COUNT }> = EnumTable::default();
163        assert_eq!(default_table.get(&Color::Red), &"");
164        assert_eq!(default_table.get(&Color::Green), &"");
165        assert_eq!(default_table.get(&Color::Blue), &"");
166    }
167
168    #[test]
169    fn index_impl() {
170        assert_eq!(TABLES[Color::Red], "Red");
171        assert_eq!(TABLES[Color::Green], "Green");
172        assert_eq!(TABLES[Color::Blue], "Blue");
173
174        let mut mutable_table = TABLES;
175        mutable_table[Color::Red] = "Changed Red";
176        assert_eq!(mutable_table[Color::Red], "Changed Red");
177    }
178
179    #[test]
180    fn into_iter_impl() {
181        let mut iter = TABLES.into_iter();
182        assert_eq!(iter.next(), Some((Color::Red, "Red")));
183        assert_eq!(iter.next(), Some((Color::Green, "Green")));
184        assert_eq!(iter.next(), Some((Color::Blue, "Blue")));
185        assert_eq!(iter.next(), None);
186    }
187
188    #[test]
189    fn into_iter_ref_impl() {
190        let mut iter = (&TABLES).into_iter();
191        assert_eq!(iter.next(), Some((&Color::Red, &"Red")));
192        assert_eq!(iter.next(), Some((&Color::Green, &"Green")));
193        assert_eq!(iter.next(), Some((&Color::Blue, &"Blue")));
194        assert_eq!(iter.next(), None);
195    }
196
197    #[test]
198    fn into_iter_mut_impl() {
199        let mut mutable_table = TABLES;
200        let mut iter = (&mut mutable_table).into_iter();
201        assert_eq!(iter.next(), Some((&Color::Red, &mut "Red")));
202        assert_eq!(iter.next(), Some((&Color::Green, &mut "Green")));
203        let blue = iter.next().unwrap();
204        assert_eq!(blue, (&Color::Blue, &mut "Blue"));
205        assert_eq!(iter.next(), None);
206
207        // Modify the value through the mutable reference
208        *blue.1 = "Modified Blue";
209        assert_eq!(mutable_table[Color::Blue], "Modified Blue");
210    }
211}