Skip to main content

enum_table/impls/
vec.rs

1use crate::{EnumTable, Enumable};
2
3/// Error type for `EnumTable::try_from_vec`.
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub enum EnumTableFromVecError<K> {
6    /// The vector has an invalid size.
7    InvalidSize { expected: usize, found: usize },
8    /// A required enum variant is missing from the vector.
9    /// This error happened meaning that the vector duplicated some variant
10    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    /// Converts the `EnumTable` into a `Vec` of key-value pairs.
30    ///
31    /// # Examples
32    ///
33    /// ```rust
34    /// use enum_table::{EnumTable, Enumable};
35    ///
36    /// #[derive(Enumable, Debug, PartialEq, Copy, Clone)]
37    /// enum Color {
38    ///     Red,
39    ///     Green,
40    ///     Blue,
41    /// }
42    ///
43    /// let table = EnumTable::<Color, &str, { Color::COUNT }>::new_with_fn(|color| match color {
44    ///     Color::Red => "red",
45    ///     Color::Green => "green",
46    ///     Color::Blue => "blue",
47    /// });
48    ///
49    /// let vec = table.into_vec();
50    /// assert!(vec.contains(&(Color::Red, "red")));
51    /// assert!(vec.contains(&(Color::Green, "green")));
52    /// assert!(vec.contains(&(Color::Blue, "blue")));
53    /// assert_eq!(vec.len(), 3);
54    /// ```
55    pub fn into_vec(self) -> Vec<(K, V)> {
56        self.into_iter().collect()
57    }
58
59    /// Creates an `EnumTable` from a `Vec` of key-value pairs.
60    ///
61    /// Returns an error if the vector doesn't contain exactly one entry for each enum variant.
62    ///
63    /// # Arguments
64    ///
65    /// * `vec` - A vector containing key-value pairs for each enum variant.
66    ///
67    /// # Examples
68    ///
69    /// ```rust
70    /// use enum_table::{EnumTable, Enumable};
71    ///
72    /// #[derive(Enumable, Debug, PartialEq, Copy, Clone)]
73    /// enum Color {
74    ///     Red,
75    ///     Green,
76    ///     Blue,
77    /// }
78    ///
79    /// let vec = vec![
80    ///     (Color::Red, "red"),
81    ///     (Color::Green, "green"),
82    ///     (Color::Blue, "blue"),
83    /// ];
84    ///
85    /// let table = EnumTable::<Color, &str, { Color::COUNT }>::try_from_vec(vec).unwrap();
86    /// assert_eq!(table.get(&Color::Red), &"red");
87    /// assert_eq!(table.get(&Color::Green), &"green");
88    /// assert_eq!(table.get(&Color::Blue), &"blue");
89    /// ```
90    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            // Missing Blue
163        ];
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"), // Duplicate instead of Blue
181        ];
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}