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