Skip to main content

enum_table/impls/
vec.rs

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