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#[macro_export]
139macro_rules! define {
140    (
141        $(#[$meta:meta])*
142        $vis:vis struct $name:ident(Vec<$inner:ty>)
143        $(where [$($where_clause:tt)*])?;
144        $(variants = [$($variant:ty),+];)?
145    ) => {
146        $crate::define_struct!(
147            $(#[$meta])*
148            $vis struct $name(Vec<$inner>)
149            $(where [$($where_clause)*])?;
150        );
151        $crate::impl_self!($name, $inner);
152        $crate::impl_default!($name);
153        $crate::impl_extend!($name, $inner);
154        $crate::impl_into_iter_own!($name, $inner);
155        $crate::impl_into_iter_ref!($name, $inner);
156        $crate::impl_deref!($name, $inner);
157        $crate::impl_deref_mut!($name, $inner);
158        $crate::impl_from_vec!($name, $inner);
159        $crate::impl_into_vec!($name, $inner);
160        $($crate::impl_from_value!($name, [$($variant),+]);)?
161    };
162}
163
164#[macro_export]
165macro_rules! define_struct {
166    (
167        $(#[$meta:meta])*
168        $vis:vis struct $name:ident(Vec<$inner:ty>)
169        $(where [$($where_clause:tt)*])?;
170    ) => {
171        #[repr(transparent)]
172        $(#[$meta])*
173        $vis struct $name(Vec<$inner>)
174        $(where $($where_clause)*)?;
175    };
176}
177
178#[macro_export]
179macro_rules! impl_self {
180    ($name:ident, $inner:ty) => {
181        impl $name {
182            pub fn new(inner: impl Into<Vec<$inner>>) -> Self {
183                Self(inner.into())
184            }
185
186            pub fn push(&mut self, value: impl Into<$inner>) {
187                self.0.push(value.into())
188            }
189
190            pub fn extend_from<T: Into<$inner>>(&mut self, iter: impl IntoIterator<Item = T>) {
191                self.extend(iter.into_iter().map(T::into))
192            }
193        }
194    };
195}
196
197#[macro_export]
198macro_rules! impl_default {
199    ($name:ident) => {
200        impl Default for $name {
201            fn default() -> Self {
202                Self(Default::default())
203            }
204        }
205    };
206}
207
208#[macro_export]
209macro_rules! impl_extend {
210    ($name:ident, $inner:ty) => {
211        impl Extend<$inner> for $name {
212            fn extend<I: IntoIterator<Item = $inner>>(&mut self, iter: I) {
213                self.0.extend(iter);
214            }
215        }
216    };
217}
218
219#[macro_export]
220macro_rules! impl_into_iter_own {
221    ($name:ident, $inner:ty) => {
222        impl IntoIterator for $name {
223            type Item = $inner;
224            type IntoIter = std::vec::IntoIter<Self::Item>;
225
226            fn into_iter(self) -> Self::IntoIter {
227                self.0.into_iter()
228            }
229        }
230    };
231}
232
233#[macro_export]
234macro_rules! impl_into_iter_ref {
235    ($name:ident, $inner:ty) => {
236        impl<'a> IntoIterator for &'a $name {
237            type Item = &'a $inner;
238            type IntoIter = std::slice::Iter<'a, $inner>;
239
240            fn into_iter(self) -> Self::IntoIter {
241                self.0.iter()
242            }
243        }
244    };
245}
246
247#[macro_export]
248macro_rules! impl_deref {
249    ($name:ident, $inner:ty) => {
250        impl std::ops::Deref for $name {
251            type Target = Vec<$inner>;
252
253            fn deref(&self) -> &Self::Target {
254                &self.0
255            }
256        }
257    };
258}
259
260#[macro_export]
261macro_rules! impl_deref_mut {
262    ($name:ident, $inner:ty) => {
263        impl std::ops::DerefMut for $name {
264            fn deref_mut(&mut self) -> &mut Self::Target {
265                &mut self.0
266            }
267        }
268    };
269}
270
271#[macro_export]
272macro_rules! impl_from_vec {
273    ($name:ident, $inner:ty) => {
274        impl From<Vec<$inner>> for $name {
275            fn from(vec: Vec<$inner>) -> Self {
276                Self(vec)
277            }
278        }
279    };
280}
281
282#[macro_export]
283macro_rules! impl_from_value {
284    ($name:ident, [$($value_source:ty),+]) => {
285        $(
286            $crate::impl_from_value!($name, $value_source);
287        )+
288    };
289    ($name:ident, $value_source:ty) => {
290        impl From<$value_source> for $name {
291            fn from(source: $value_source) -> Self {
292                Self(vec![source.into()])
293            }
294        }
295    };
296}
297
298#[macro_export]
299macro_rules! impl_into_vec {
300    ($name:ident, $inner:ty) => {
301        impl From<$name> for Vec<$inner> {
302            fn from(value: $name) -> Self {
303                value.0
304            }
305        }
306    };
307}