1use crate::{EnumTable, Enumable, builder::EnumTableBuilder};
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.table.into_iter().collect()
57 }
58
59 pub fn try_from_vec(mut 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 builder = EnumTableBuilder::<K, V, N>::new();
99
100 for variant in K::VARIANTS {
102 if let Some(pos) = vec
103 .iter()
104 .position(|(k, _)| crate::intrinsics::const_enum_eq(k, variant))
105 {
106 let (_, value) = vec.swap_remove(pos);
107 unsafe {
108 builder.push_unchecked(variant, value);
109 }
110 } else {
111 return Err(EnumTableFromVecError::MissingVariant(*variant));
112 }
113 }
114
115 Ok(unsafe { builder.build_to_unchecked() })
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 #[derive(Debug, Clone, Copy, PartialEq, Eq, Enumable)]
124 enum Color {
125 Red = 33,
126 Green = 11,
127 Blue = 222,
128 }
129
130 const TABLES: EnumTable<Color, &'static str, { Color::COUNT }> =
131 crate::et!(Color, &'static str, |color| match color {
132 Color::Red => "Red",
133 Color::Green => "Green",
134 Color::Blue => "Blue",
135 });
136
137 #[test]
138 fn into_vec() {
139 let table = TABLES;
140 let vec = table.into_vec();
141
142 assert_eq!(vec.len(), 3);
143 assert!(vec.contains(&(Color::Red, "Red")));
144 assert!(vec.contains(&(Color::Green, "Green")));
145 assert!(vec.contains(&(Color::Blue, "Blue")));
146 }
147
148 #[test]
149 fn try_from_vec() {
150 let vec = vec![
151 (Color::Red, "Red"),
152 (Color::Green, "Green"),
153 (Color::Blue, "Blue"),
154 ];
155
156 let table = EnumTable::<Color, &str, { Color::COUNT }>::try_from_vec(vec).unwrap();
157 assert_eq!(table.get(&Color::Red), &"Red");
158 assert_eq!(table.get(&Color::Green), &"Green");
159 assert_eq!(table.get(&Color::Blue), &"Blue");
160 }
161
162 #[test]
163 fn try_from_vec_invalid_size() {
164 let vec = vec![
165 (Color::Red, "Red"),
166 (Color::Green, "Green"),
167 ];
169
170 let result = EnumTable::<Color, &str, { Color::COUNT }>::try_from_vec(vec);
171 assert_eq!(
172 result,
173 Err(crate::EnumTableFromVecError::InvalidSize {
174 expected: 3,
175 found: 2
176 })
177 );
178 }
179
180 #[test]
181 fn try_from_vec_missing_variant() {
182 let vec = vec![
183 (Color::Red, "Red"),
184 (Color::Green, "Green"),
185 (Color::Red, "Duplicate Red"), ];
187
188 let result = EnumTable::<Color, &str, { Color::COUNT }>::try_from_vec(vec);
189 assert_eq!(
190 result,
191 Err(crate::EnumTableFromVecError::MissingVariant(Color::Blue))
192 );
193 }
194
195 #[test]
196 fn conversion_roundtrip() {
197 let original = TABLES;
198 let vec = original.into_vec();
199 let reconstructed = EnumTable::<Color, &str, { Color::COUNT }>::try_from_vec(vec).unwrap();
200
201 assert_eq!(reconstructed.get(&Color::Red), &"Red");
202 assert_eq!(reconstructed.get(&Color::Green), &"Green");
203 assert_eq!(reconstructed.get(&Color::Blue), &"Blue");
204 }
205}