1use crate::{EnumTable, Enumable};
2
3#[derive(Debug, Clone, PartialEq, Eq)]
5pub enum EnumTableFromVecError<K> {
6 InvalidSize { expected: usize, found: usize },
8 MissingVariant(K),
11}
12
13impl<K: core::fmt::Debug> core::fmt::Display for EnumTableFromVecError<K> {
14 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
15 match self {
16 EnumTableFromVecError::InvalidSize { expected, found } => {
17 write!(f, "Invalid vector size: expected {expected}, found {found}")
18 }
19 EnumTableFromVecError::MissingVariant(variant) => {
20 write!(f, "Missing enum variant: {variant:?}")
21 }
22 }
23 }
24}
25
26impl<K: core::fmt::Debug> core::error::Error for EnumTableFromVecError<K> {}
27
28impl<K: Enumable, V, const N: usize> EnumTable<K, V, N> {
29 pub fn into_vec(self) -> Vec<(K, V)> {
56 self.into_iter().collect()
57 }
58
59 pub fn try_from_vec(vec: Vec<(K, V)>) -> Result<Self, EnumTableFromVecError<K>> {
91 if vec.len() != N {
92 return Err(EnumTableFromVecError::InvalidSize {
93 expected: N,
94 found: vec.len(),
95 });
96 }
97
98 let mut slots: [Option<V>; N] = core::array::from_fn(|_| None);
99
100 for (key, value) in vec {
101 slots[key.variant_index()] = Some(value);
102 }
103
104 let table = crate::intrinsics::try_collect_array(|i| {
105 slots[i]
106 .take()
107 .ok_or(EnumTableFromVecError::MissingVariant(K::VARIANTS[i]))
108 })?;
109
110 Ok(Self::new(table))
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117
118 #[derive(Debug, Clone, Copy, PartialEq, Eq, Enumable)]
119 enum Color {
120 Red = 33,
121 Green = 11,
122 Blue = 222,
123 }
124
125 const TABLES: EnumTable<Color, &'static str, { Color::COUNT }> =
126 crate::et!(Color, &'static str, |color| match color {
127 Color::Red => "Red",
128 Color::Green => "Green",
129 Color::Blue => "Blue",
130 });
131
132 #[test]
133 fn into_vec() {
134 let table = TABLES;
135 let vec = table.into_vec();
136
137 assert_eq!(vec.len(), 3);
138 assert!(vec.contains(&(Color::Red, "Red")));
139 assert!(vec.contains(&(Color::Green, "Green")));
140 assert!(vec.contains(&(Color::Blue, "Blue")));
141 }
142
143 #[test]
144 fn try_from_vec() {
145 let vec = vec![
146 (Color::Red, "Red"),
147 (Color::Green, "Green"),
148 (Color::Blue, "Blue"),
149 ];
150
151 let table = EnumTable::<Color, &str, { Color::COUNT }>::try_from_vec(vec).unwrap();
152 assert_eq!(table.get(&Color::Red), &"Red");
153 assert_eq!(table.get(&Color::Green), &"Green");
154 assert_eq!(table.get(&Color::Blue), &"Blue");
155 }
156
157 #[test]
158 fn try_from_vec_invalid_size() {
159 let vec = vec![
160 (Color::Red, "Red"),
161 (Color::Green, "Green"),
162 ];
164
165 let result = EnumTable::<Color, &str, { Color::COUNT }>::try_from_vec(vec);
166 assert_eq!(
167 result,
168 Err(crate::EnumTableFromVecError::InvalidSize {
169 expected: 3,
170 found: 2
171 })
172 );
173 }
174
175 #[test]
176 fn try_from_vec_missing_variant() {
177 let vec = vec![
178 (Color::Red, "Red"),
179 (Color::Green, "Green"),
180 (Color::Red, "Duplicate Red"), ];
182
183 let result = EnumTable::<Color, &str, { Color::COUNT }>::try_from_vec(vec);
184 assert_eq!(
185 result,
186 Err(crate::EnumTableFromVecError::MissingVariant(Color::Blue))
187 );
188 }
189
190 #[test]
191 fn conversion_roundtrip() {
192 let original = TABLES;
193 let vec = original.into_vec();
194 let reconstructed = EnumTable::<Color, &str, { Color::COUNT }>::try_from_vec(vec).unwrap();
195
196 assert_eq!(reconstructed.get(&Color::Red), &"Red");
197 assert_eq!(reconstructed.get(&Color::Green), &"Green");
198 assert_eq!(reconstructed.get(&Color::Blue), &"Blue");
199 }
200}