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