error_rail/validation/iter.rs
1use crate::{validation::core::Validation, ErrorVec};
2use std::slice::{Iter as SliceIter, IterMut as SliceIterMut};
3
4/// Iterator over the valid value of a [`Validation`].
5///
6/// This iterator yields at most one item (the valid value if present).
7/// It is created by the [`Validation::iter`] method.
8///
9/// # Examples
10///
11/// ```
12/// use error_rail::validation::Validation;
13///
14/// let valid: Validation<String, i32> = Validation::Valid(5);
15/// let mut iter = valid.iter();
16/// assert_eq!(iter.next(), Some(&5));
17/// assert_eq!(iter.next(), None);
18/// ```
19pub struct Iter<'a, A> {
20 inner: Option<&'a A>,
21}
22
23impl<'a, A> Iterator for Iter<'a, A> {
24 type Item = &'a A;
25
26 fn next(&mut self) -> Option<Self::Item> {
27 self.inner.take()
28 }
29}
30
31impl<'a, A> ExactSizeIterator for Iter<'a, A> {
32 fn len(&self) -> usize {
33 self.inner.is_some() as usize
34 }
35}
36
37/// Mutable iterator over the valid value of a [`Validation`].
38///
39/// This iterator yields at most one mutable reference to the valid value if present.
40/// It is created by the [`Validation::iter_mut`] method.
41///
42/// # Examples
43///
44/// ```
45/// use error_rail::validation::Validation;
46///
47/// let mut valid: Validation<String, i32> = Validation::Valid(5);
48/// for value in valid.iter_mut() {
49/// *value += 10;
50/// }
51/// assert_eq!(valid, Validation::Valid(15));
52/// ```
53pub struct IterMut<'a, A> {
54 inner: Option<&'a mut A>,
55}
56
57impl<'a, A> Iterator for IterMut<'a, A> {
58 type Item = &'a mut A;
59
60 fn next(&mut self) -> Option<Self::Item> {
61 self.inner.take()
62 }
63}
64
65impl<'a, A> ExactSizeIterator for IterMut<'a, A> {
66 fn len(&self) -> usize {
67 self.inner.is_some() as usize
68 }
69}
70
71/// Iterator over the errors of a [`Validation`].
72///
73/// This iterator yields references to all accumulated errors in an invalid validation.
74/// For valid validations, it yields no items.
75///
76/// # Examples
77///
78/// ```
79/// use error_rail::validation::Validation;
80///
81/// let invalid: Validation<&str, i32> = Validation::invalid_many(["error1", "error2"]);
82/// let errors: Vec<_> = invalid.iter_errors().collect();
83/// assert_eq!(errors, vec![&"error1", &"error2"]);
84/// ```
85pub enum ErrorsIter<'a, E> {
86 /// No errors present (valid validation)
87 Empty,
88 /// Multiple errors present (invalid validation)
89 Multi(SliceIter<'a, E>),
90}
91
92impl<'a, E> Iterator for ErrorsIter<'a, E> {
93 type Item = &'a E;
94
95 fn next(&mut self) -> Option<Self::Item> {
96 match self {
97 ErrorsIter::Empty => None,
98 ErrorsIter::Multi(it) => it.next(),
99 }
100 }
101
102 fn size_hint(&self) -> (usize, Option<usize>) {
103 match self {
104 ErrorsIter::Empty => (0, Some(0)),
105 ErrorsIter::Multi(it) => it.size_hint(),
106 }
107 }
108}
109
110impl<'a, E> ExactSizeIterator for ErrorsIter<'a, E> {
111 fn len(&self) -> usize {
112 match self {
113 ErrorsIter::Empty => 0,
114 ErrorsIter::Multi(it) => it.len(),
115 }
116 }
117}
118
119/// Mutable iterator over the errors of a [`Validation`].
120///
121/// This iterator yields mutable references to all accumulated errors in an invalid validation.
122/// For valid validations, it yields no items.
123///
124/// # Examples
125///
126/// ```
127/// use error_rail::validation::Validation;
128///
129/// let mut invalid: Validation<String, i32> = Validation::invalid_many([
130/// "error1".to_string(),
131/// "error2".to_string()
132/// ]);
133///
134/// for error in invalid.iter_errors_mut() {
135/// error.push_str(" [modified]");
136/// }
137/// ```
138pub enum ErrorsIterMut<'a, E> {
139 /// No errors present (valid validation)
140 Empty,
141 /// Multiple errors present (invalid validation)
142 Multi(SliceIterMut<'a, E>),
143}
144
145impl<'a, E> Iterator for ErrorsIterMut<'a, E> {
146 type Item = &'a mut E;
147
148 fn next(&mut self) -> Option<Self::Item> {
149 match self {
150 ErrorsIterMut::Empty => None,
151 ErrorsIterMut::Multi(it) => it.next(),
152 }
153 }
154
155 fn size_hint(&self) -> (usize, Option<usize>) {
156 match self {
157 ErrorsIterMut::Empty => (0, Some(0)),
158 ErrorsIterMut::Multi(it) => it.size_hint(),
159 }
160 }
161}
162
163impl<'a, E> ExactSizeIterator for ErrorsIterMut<'a, E> {
164 fn len(&self) -> usize {
165 match self {
166 ErrorsIterMut::Empty => 0,
167 ErrorsIterMut::Multi(it) => it.len(),
168 }
169 }
170}
171
172/// Converts a [`Validation`] into an iterator over its valid value.
173///
174/// This consumes the validation and yields at most one item.
175///
176/// # Examples
177///
178/// ```
179/// use error_rail::validation::Validation;
180///
181/// let valid: Validation<String, i32> = Validation::Valid(42);
182/// let values: Vec<_> = valid.into_iter().collect();
183/// assert_eq!(values, vec![42]);
184///
185/// let invalid: Validation<String, i32> = Validation::invalid("error".to_string());
186/// let values: Vec<_> = invalid.into_iter().collect();
187/// assert!(values.is_empty());
188/// ```
189impl<E, A> IntoIterator for Validation<E, A> {
190 type Item = A;
191 type IntoIter = IntoIter<A>;
192
193 fn into_iter(self) -> Self::IntoIter {
194 match self {
195 Validation::Valid(a) => IntoIter { inner: Some(a) },
196 _ => IntoIter { inner: None },
197 }
198 }
199}
200
201/// Owning iterator over the valid value of a [`Validation`].
202///
203/// This iterator takes ownership of the validation and yields at most one item.
204/// It is created by calling [`IntoIterator::into_iter`] on a [`Validation`].
205///
206/// # Examples
207///
208/// ```
209/// use error_rail::validation::Validation;
210///
211/// let valid: Validation<String, i32> = Validation::Valid(100);
212/// let mut iter = valid.into_iter();
213/// assert_eq!(iter.next(), Some(100));
214/// assert_eq!(iter.next(), None);
215/// ```
216pub struct IntoIter<A> {
217 inner: Option<A>,
218}
219
220impl<A> Iterator for IntoIter<A> {
221 type Item = A;
222
223 fn next(&mut self) -> Option<Self::Item> {
224 self.inner.take()
225 }
226}
227
228impl<A> ExactSizeIterator for IntoIter<A> {
229 fn len(&self) -> usize {
230 self.inner.is_some() as usize
231 }
232}
233
234/// Converts a reference to a [`Validation`] into an iterator.
235///
236/// This allows for convenient iteration over the valid value without consuming the validation.
237///
238/// # Examples
239///
240/// ```
241/// use error_rail::validation::Validation;
242///
243/// let valid: Validation<String, i32> = Validation::Valid(5);
244/// for value in &valid {
245/// assert_eq!(value, &5);
246/// }
247/// // valid is still usable here
248/// ```
249impl<'a, E, A> IntoIterator for &'a Validation<E, A> {
250 type Item = &'a A;
251 type IntoIter = Iter<'a, A>;
252
253 fn into_iter(self) -> Self::IntoIter {
254 self.iter()
255 }
256}
257
258/// Converts a mutable reference to a [`Validation`] into an iterator.
259///
260/// This allows for convenient mutable iteration over the valid value without consuming the validation.
261///
262/// # Examples
263///
264/// ```
265/// use error_rail::validation::Validation;
266///
267/// let mut valid: Validation<String, i32> = Validation::Valid(5);
268/// for value in &mut valid {
269/// *value *= 2;
270/// }
271/// assert_eq!(valid, Validation::Valid(10));
272/// ```
273impl<'a, E, A> IntoIterator for &'a mut Validation<E, A> {
274 type Item = &'a mut A;
275 type IntoIter = IterMut<'a, A>;
276
277 fn into_iter(self) -> Self::IntoIter {
278 self.iter_mut()
279 }
280}
281
282impl<E, A> Validation<E, A> {
283 /// Returns an iterator over the valid value.
284 ///
285 /// The iterator yields at most one item - the valid value if present.
286 /// For invalid validations, the iterator yields nothing.
287 ///
288 /// # Examples
289 ///
290 /// ```
291 /// use error_rail::validation::Validation;
292 ///
293 /// let valid: Validation<String, i32> = Validation::Valid(5);
294 /// assert_eq!(valid.iter().next(), Some(&5));
295 ///
296 /// let invalid: Validation<String, i32> = Validation::invalid("error".to_string());
297 /// assert_eq!(invalid.iter().next(), None);
298 /// ```
299 pub fn iter(&self) -> Iter<'_, A> {
300 match self {
301 Validation::Valid(a) => Iter { inner: Some(a) },
302 _ => Iter { inner: None },
303 }
304 }
305
306 /// Returns a mutable iterator over the valid value.
307 ///
308 /// The iterator yields at most one mutable reference - to the valid value if present.
309 /// For invalid validations, the iterator yields nothing.
310 ///
311 /// # Examples
312 ///
313 /// ```
314 /// use error_rail::validation::Validation;
315 ///
316 /// let mut valid: Validation<String, i32> = Validation::Valid(5);
317 /// if let Some(value) = valid.iter_mut().next() {
318 /// *value = 10;
319 /// }
320 /// assert_eq!(valid, Validation::Valid(10));
321 /// ```
322 pub fn iter_mut(&mut self) -> IterMut<'_, A> {
323 match self {
324 Validation::Valid(a) => IterMut { inner: Some(a) },
325 _ => IterMut { inner: None },
326 }
327 }
328
329 /// Returns an iterator over the errors.
330 ///
331 /// For invalid validations, yields references to all accumulated errors.
332 /// For valid validations, yields nothing.
333 ///
334 /// # Examples
335 ///
336 /// ```
337 /// use error_rail::validation::Validation;
338 ///
339 /// let valid: Validation<String, i32> = Validation::Valid(5);
340 /// assert_eq!(valid.iter_errors().next(), None);
341 ///
342 /// let invalid: Validation<String, i32> = Validation::invalid("error".to_string());
343 /// assert_eq!(invalid.iter_errors().next(), Some(&"error".to_string()));
344 ///
345 /// let multi_invalid: Validation<&str, i32> = Validation::invalid_many(["err1", "err2"]);
346 /// assert_eq!(multi_invalid.iter_errors().count(), 2);
347 /// ```
348 pub fn iter_errors(&self) -> ErrorsIter<'_, E> {
349 match self {
350 Self::Valid(_) => ErrorsIter::Empty,
351 Self::Invalid(errors) => ErrorsIter::Multi(errors.iter()),
352 }
353 }
354
355 /// Returns a mutable iterator over the errors.
356 ///
357 /// For invalid validations, yields mutable references to all accumulated errors.
358 /// For valid validations, yields nothing.
359 ///
360 /// # Examples
361 ///
362 /// ```
363 /// use error_rail::validation::Validation;
364 ///
365 /// let mut invalid: Validation<String, i32> = Validation::invalid("error".to_string());
366 /// for error in invalid.iter_errors_mut() {
367 /// error.push_str(" [updated]");
368 /// }
369 /// assert_eq!(
370 /// invalid.iter_errors().next(),
371 /// Some(&"error [updated]".to_string())
372 /// );
373 /// ```
374 pub fn iter_errors_mut(&mut self) -> ErrorsIterMut<'_, E> {
375 match self {
376 Validation::Invalid(es) => ErrorsIterMut::Multi(es.iter_mut()),
377 _ => ErrorsIterMut::Empty,
378 }
379 }
380}
381
382/// Collects an iterator of `Result`s into a single `Validation`, aggregating all errors.
383///
384/// If all results are `Ok`, returns `Valid` with a collection of all success values.
385/// If any results are `Err`, returns `Invalid` with all accumulated errors.
386///
387/// This is useful for validating multiple operations and collecting all failures
388/// instead of short-circuiting on the first error.
389///
390/// # Examples
391///
392/// ```
393/// use error_rail::validation::Validation;
394///
395/// let inputs = vec![Ok(1), Err("oops"), Ok(2)];
396/// let collected: Validation<&str, Vec<i32>> = inputs.into_iter().collect();
397/// assert!(collected.is_invalid());
398/// assert_eq!(collected.into_errors().unwrap()[0], "oops");
399///
400/// let all_ok = vec![Ok(1), Ok(2), Ok(3)];
401/// let collected: Validation<&str, Vec<i32>> = all_ok.into_iter().collect();
402/// assert_eq!(collected, Validation::Valid(vec![1, 2, 3]));
403/// ```
404impl<E, A, C> FromIterator<Result<A, E>> for Validation<E, C>
405where
406 C: FromIterator<A>,
407{
408 fn from_iter<T: IntoIterator<Item = Result<A, E>>>(iter: T) -> Self {
409 let mut values = Vec::new();
410 let mut errors = ErrorVec::new();
411
412 for item in iter {
413 match item {
414 Ok(v) => values.push(v),
415 Err(e) => errors.push(e),
416 }
417 }
418
419 if errors.is_empty() {
420 let collected: C = values.into_iter().collect();
421 Validation::Valid(collected)
422 } else {
423 Validation::Invalid(errors)
424 }
425 }
426}
427
428/// Collects an iterator of `Validation`s into a single `Validation`, aggregating all errors.
429///
430/// If all validations are valid, returns `Valid` with a collection of all success values.
431/// If any validations are invalid, returns `Invalid` with all accumulated errors from all
432/// invalid validations.
433///
434/// This is the primary way to combine multiple validations while preserving all error information.
435///
436/// # Examples
437///
438/// ```
439/// use error_rail::validation::Validation;
440///
441/// let items = vec![Validation::valid(1), Validation::invalid("bad")];
442/// let collected: Validation<&str, Vec<i32>> = items.into_iter().collect();
443/// assert!(collected.is_invalid());
444/// ```
445impl<E, A, C> FromIterator<Validation<E, A>> for Validation<E, C>
446where
447 C: FromIterator<A>,
448{
449 fn from_iter<T: IntoIterator<Item = Validation<E, A>>>(iter: T) -> Self {
450 let mut values = Vec::new();
451 let mut errors = ErrorVec::new();
452
453 for item in iter {
454 match item {
455 Validation::Valid(v) => values.push(v),
456 Validation::Invalid(es) => errors.extend(es),
457 }
458 }
459
460 if errors.is_empty() {
461 let collected: C = values.into_iter().collect();
462 Validation::Valid(collected)
463 } else {
464 Validation::Invalid(errors)
465 }
466 }
467}