error_rail/validation/
iter.rs

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