Skip to main content

vec_of_enum/
lib.rs

1//! A helper struct to manage a `Vec` of `enum` values. Reduces boilerplate, implements useful traits.
2//!
3//! ```rust
4//! # use derive_more::{Constructor, From};
5//! # use serde::{Deserialize, Serialize};
6//! #
7//! # // Define some sample validation error structs
8//! # #[derive(Constructor, Serialize, Deserialize)]
9//! # pub struct PasswordMinLengthError {
10//! #     min_length: usize,
11//! # }
12//! #
13//! # #[derive(Constructor, Serialize, Deserialize)]
14//! # pub struct InvalidEmailError {
15//! #     email: String,
16//! #     reason: String,
17//! # }
18//! #
19//! # // Define an enum that can contain any validation error
20//! # #[derive(From, Serialize, Deserialize)]
21//! # pub enum ValidationError {
22//! #     PasswordMinLength(PasswordMinLengthError),
23//! #     InvalidEmail(InvalidEmailError),
24//! # }
25//! #
26//! # // Convenience conversion
27//! # impl From<(&str, &str)> for ValidationError {
28//! #     fn from((email, reason): (&str, &str)) -> Self {
29//! #         Self::InvalidEmail(InvalidEmailError::new(email.into(), reason.into()))
30//! #     }
31//! # }
32//! #
33//! # // Define a typed vector wrapper for ValidationErrors
34//! # vec_of_enum::define!(
35//! #     #[derive(Serialize, Deserialize)]
36//! #     pub struct ValidationErrors(Vec<ValidationError>);
37//! # );
38//! #
39//! # // Define a typed vector wrapper that also automatically converts from variant types
40//! # vec_of_enum::define!(
41//! #     #[derive(Serialize, Deserialize)]
42//! #     pub struct ValidationErrorsWithVariants(Vec<ValidationError>);
43//! #     variants = [PasswordMinLengthError, InvalidEmailError];
44//! # );
45//! #
46//! let mut errors = ValidationErrors::default();
47//!
48//! // ❌ Without `vec-of-enum`: too verbose
49//! errors.push(ValidationError::InvalidEmail(InvalidEmailError::new("user@example.com".into(), "domain is blocked".into())));
50//!
51//! // ✅ With `vec-of-enum`: very concise
52//! errors.push(("user@example.com", "domain is blocked"));
53//! ```
54//!
55//! # Full example
56//!
57//! ```rust
58//! use derive_more::{Constructor, From};
59//! use serde::{Deserialize, Serialize};
60//!
61//! // Define some sample validation error structs
62//! #[derive(Constructor, Serialize, Deserialize)]
63//! pub struct PasswordMinLengthError {
64//!     min_length: usize,
65//! }
66//!
67//! #[derive(Constructor, Serialize, Deserialize)]
68//! pub struct InvalidEmailError {
69//!     email: String,
70//!     reason: String,
71//! }
72//!
73//! // Define an enum that can contain any validation error
74//! #[derive(From, Serialize, Deserialize)]
75//! pub enum ValidationError {
76//!     PasswordMinLength(PasswordMinLengthError),
77//!     InvalidEmail(InvalidEmailError),
78//! }
79//!
80//! // Convenience conversion
81//! impl From<(&str, &str)> for ValidationError {
82//!     fn from((email, reason): (&str, &str)) -> Self {
83//!         Self::InvalidEmail(InvalidEmailError::new(email.into(), reason.into()))
84//!     }
85//! }
86//!
87//! // Define a typed vector wrapper for ValidationErrors
88//! vec_of_enum::define!(
89//!     #[derive(Serialize, Deserialize)]
90//!     pub struct ValidationErrors(Vec<ValidationError>);
91//! );
92//!
93//! // Define a typed vector wrapper that also automatically converts from variant types
94//! vec_of_enum::define!(
95//!     #[derive(Serialize, Deserialize)]
96//!     pub struct ValidationErrorsWithVariants(Vec<ValidationError>);
97//!     variants = [PasswordMinLengthError, InvalidEmailError];
98//! );
99//!
100//! let mut errors = ValidationErrors::default();
101//!
102//! // ❌ Without `vec-of-enum`: too verbose
103//! errors.push(ValidationError::InvalidEmail(InvalidEmailError::new("user@example.com".into(), "domain is blocked".into())));
104//!
105//! // ✅ With `vec-of-enum`: very concise
106//! errors.push(("user@example.com", "domain is blocked"));
107//! ```
108//!
109//! # Features
110//!
111//! The wrapper struct created using the `define!` macro:
112//!
113//! - Is `#[repr(transparent)]` for zero-cost abstraction
114//! - Implements `Deref` and `DerefMut` to `Vec<T>` for access to all Vec methods
115//! - Provides `new()`, `push()`, and `extend_from()` methods
116//! - Implements `Default`, `Extend`, `IntoIterator`, `From<Vec<T>>`, and `Into<Vec<T>>`
117//! - Supports automatic conversions from variant types when using the `variants = [...]` option
118//!
119//! # Custom Derives
120//!
121//! You can add any derive macros to your struct definition, and they will be applied to
122//! the generated struct. For example:
123//!
124//! ```rust
125//! use serde::{Deserialize, Serialize};
126//!
127//! #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
128//! pub enum MyEnum {}
129//!
130//! vec_of_enum::define!(
131//!     #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
132//!     pub struct MyVec(Vec<MyEnum>);
133//! );
134//! ```
135//!
136//! This allows you to add any necessary derives that your application requires.
137
138#![cfg_attr(not(test), deny(unused_crate_dependencies))]
139
140#[macro_export]
141macro_rules! define {
142    (
143        $(#[$meta:meta])*
144        $vis:vis struct $name:ident(Vec<$inner:ty>)
145        $(where [$($where_clause:tt)*])?;
146        $(variants = [$($variant:ty),+];)?
147    ) => {
148        $crate::define_struct!(
149            $(#[$meta])*
150            $vis struct $name(Vec<$inner>)
151            $(where [$($where_clause)*])?;
152        );
153        $crate::impl_self!($name, $inner);
154        $crate::impl_default!($name);
155        $crate::impl_extend!($name, $inner);
156        $crate::impl_into_iter_own!($name, $inner);
157        $crate::impl_into_iter_ref!($name, $inner);
158        $crate::impl_deref!($name, $inner);
159        $crate::impl_deref_mut!($name, $inner);
160        $crate::impl_from_vec!($name, $inner);
161        $crate::impl_into_vec!($name, $inner);
162        $($crate::impl_from_value!($name, [$($variant),+]);)?
163    };
164}
165
166#[macro_export]
167macro_rules! define_struct {
168    (
169        $(#[$meta:meta])*
170        $vis:vis struct $name:ident(Vec<$inner:ty>)
171        $(where [$($where_clause:tt)*])?;
172    ) => {
173        #[repr(transparent)]
174        $(#[$meta])*
175        $vis struct $name(Vec<$inner>)
176        $(where $($where_clause)*)?;
177    };
178}
179
180#[macro_export]
181macro_rules! impl_self {
182    ($name:ident, $inner:ty) => {
183        impl $name {
184            pub fn new(inner: impl Into<Vec<$inner>>) -> Self {
185                Self(inner.into())
186            }
187
188            pub fn push(&mut self, value: impl Into<$inner>) {
189                self.0.push(value.into())
190            }
191
192            pub fn extend_from<T: Into<$inner>>(&mut self, iter: impl IntoIterator<Item = T>) {
193                self.extend(iter.into_iter().map(T::into))
194            }
195        }
196    };
197}
198
199#[macro_export]
200macro_rules! impl_default {
201    ($name:ident) => {
202        impl Default for $name {
203            fn default() -> Self {
204                Self(Default::default())
205            }
206        }
207    };
208}
209
210#[macro_export]
211macro_rules! impl_extend {
212    ($name:ident, $inner:ty) => {
213        impl Extend<$inner> for $name {
214            fn extend<I: IntoIterator<Item = $inner>>(&mut self, iter: I) {
215                self.0.extend(iter);
216            }
217        }
218    };
219}
220
221#[macro_export]
222macro_rules! impl_into_iter_own {
223    ($name:ident, $inner:ty) => {
224        impl IntoIterator for $name {
225            type Item = $inner;
226            type IntoIter = std::vec::IntoIter<Self::Item>;
227
228            fn into_iter(self) -> Self::IntoIter {
229                self.0.into_iter()
230            }
231        }
232    };
233}
234
235#[macro_export]
236macro_rules! impl_into_iter_ref {
237    ($name:ident, $inner:ty) => {
238        impl<'a> IntoIterator for &'a $name {
239            type Item = &'a $inner;
240            type IntoIter = std::slice::Iter<'a, $inner>;
241
242            fn into_iter(self) -> Self::IntoIter {
243                self.0.iter()
244            }
245        }
246    };
247}
248
249#[macro_export]
250macro_rules! impl_deref {
251    ($name:ident, $inner:ty) => {
252        impl std::ops::Deref for $name {
253            type Target = Vec<$inner>;
254
255            fn deref(&self) -> &Self::Target {
256                &self.0
257            }
258        }
259    };
260}
261
262#[macro_export]
263macro_rules! impl_deref_mut {
264    ($name:ident, $inner:ty) => {
265        impl std::ops::DerefMut for $name {
266            fn deref_mut(&mut self) -> &mut Self::Target {
267                &mut self.0
268            }
269        }
270    };
271}
272
273#[macro_export]
274macro_rules! impl_from_vec {
275    ($name:ident, $inner:ty) => {
276        impl From<Vec<$inner>> for $name {
277            fn from(vec: Vec<$inner>) -> Self {
278                Self(vec)
279            }
280        }
281    };
282}
283
284#[macro_export]
285macro_rules! impl_from_value {
286    ($name:ident, [$($value_source:ty),+]) => {
287        $(
288            $crate::impl_from_value!($name, $value_source);
289        )+
290    };
291    ($name:ident, $value_source:ty) => {
292        impl From<$value_source> for $name {
293            fn from(source: $value_source) -> Self {
294                Self(vec![source.into()])
295            }
296        }
297    };
298}
299
300#[macro_export]
301macro_rules! impl_into_vec {
302    ($name:ident, $inner:ty) => {
303        impl From<$name> for Vec<$inner> {
304            fn from(value: $name) -> Self {
305                value.0
306            }
307        }
308    };
309}