enum_table/impls/
vec.rs

1use crate::{EnumTable, Enumable, builder::EnumTableBuilder};
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.table.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(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        // Check that all variants are present and move values out
101        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            // Missing Blue
168        ];
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"), // Duplicate instead of Blue
186        ];
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}