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
126/// Mutable iterator over the errors of a [`Validation`].
127///
128/// This iterator yields mutable references to all accumulated errors in an invalid validation.
129/// For valid validations, it yields no items.
130///
131/// # Examples
132///
133/// ```
134/// use error_rail::validation::Validation;
135///
136/// let mut invalid: Validation<String, i32> = Validation::invalid_many([
137/// "error1".to_string(),
138/// "error2".to_string()
139/// ]);
140///
141/// for error in invalid.iter_errors_mut() {
142/// error.push_str(" [modified]");
143/// }
144/// ```
145pub enum ErrorsIterMut<'a, E> {
146 /// No errors present (valid validation)
147 Empty,
148 /// Multiple errors present (invalid validation)
149 Multi(SliceIterMut<'a, E>),
150}
151
152impl<'a, E> Iterator for ErrorsIterMut<'a, E> {
153 type Item = &'a mut E;
154
155 fn next(&mut self) -> Option<Self::Item> {
156 match self {
157 ErrorsIterMut::Empty => None,
158 ErrorsIterMut::Multi(it) => it.next(),
159 }
160 }
161
162 fn size_hint(&self) -> (usize, Option<usize>) {
163 match self {
164 ErrorsIterMut::Empty => (0, Some(0)),
165 ErrorsIterMut::Multi(it) => it.size_hint(),
166 }
167 }
168}
169
170impl<'a, E> ExactSizeIterator for ErrorsIterMut<'a, E> {
171 fn len(&self) -> usize {
172 match self {
173 ErrorsIterMut::Empty => 0,
174 ErrorsIterMut::Multi(it) => it.len(),
175 }
176 }
177}
178
179impl<'a, E> FusedIterator for ErrorsIterMut<'a, E> {}
180
181/// Converts a [`Validation`] into an iterator over its valid value.
182///
183/// This consumes the validation and yields at most one item.
184///
185/// # Examples
186///
187/// ```
188/// use error_rail::validation::Validation;
189///
190/// let valid: Validation<String, i32> = Validation::Valid(42);
191/// let values: Vec<_> = valid.into_iter().collect();
192/// assert_eq!(values, vec![42]);
193///
194/// let invalid: Validation<String, i32> = Validation::invalid("error".to_string());
195/// let values: Vec<_> = invalid.into_iter().collect();
196/// assert!(values.is_empty());
197/// ```
198impl<E, A> IntoIterator for Validation<E, A> {
199 type Item = A;
200 type IntoIter = IntoIter<A>;
201
202 fn into_iter(self) -> Self::IntoIter {
203 match self {
204 Validation::Valid(a) => IntoIter { inner: Some(a) },
205 _ => IntoIter { inner: None },
206 }
207 }
208}
209
210/// Owning iterator over the valid value of a [`Validation`].
211///
212/// This iterator takes ownership of the validation and yields at most one item.
213/// It is created by calling [`IntoIterator::into_iter`] on a [`Validation`].
214///
215/// # Examples
216///
217/// ```
218/// use error_rail::validation::Validation;
219///
220/// let valid: Validation<String, i32> = Validation::Valid(100);
221/// let mut iter = valid.into_iter();
222/// assert_eq!(iter.next(), Some(100));
223/// assert_eq!(iter.next(), None);
224/// ```
225pub struct IntoIter<A> {
226 inner: Option<A>,
227}
228
229impl<A> Iterator for IntoIter<A> {
230 type Item = A;
231
232 fn next(&mut self) -> Option<Self::Item> {
233 self.inner.take()
234 }
235}
236
237impl<A> ExactSizeIterator for IntoIter<A> {
238 fn len(&self) -> usize {
239 self.inner.is_some() as usize
240 }
241}
242
243impl<A> FusedIterator for IntoIter<A> {}
244
245/// Converts a reference to a [`Validation`] into an iterator.
246///
247/// This allows for convenient iteration over the valid value without consuming the validation.
248///
249/// # Examples
250///
251/// ```
252/// use error_rail::validation::Validation;
253///
254/// let valid: Validation<String, i32> = Validation::Valid(5);
255/// for value in &valid {
256/// assert_eq!(value, &5);
257/// }
258/// // valid is still usable here
259/// ```
260impl<'a, E, A> IntoIterator for &'a Validation<E, A> {
261 type Item = &'a A;
262 type IntoIter = Iter<'a, A>;
263
264 fn into_iter(self) -> Self::IntoIter {
265 self.iter()
266 }
267}
268
269/// Converts a mutable reference to a [`Validation`] into an iterator.
270///
271/// This allows for convenient mutable iteration over the valid value without consuming the validation.
272///
273/// # Examples
274///
275/// ```
276/// use error_rail::validation::Validation;
277///
278/// let mut valid: Validation<String, i32> = Validation::Valid(5);
279/// for value in &mut valid {
280/// *value *= 2;
281/// }
282/// assert_eq!(valid, Validation::Valid(10));
283/// ```
284impl<'a, E, A> IntoIterator for &'a mut Validation<E, A> {
285 type Item = &'a mut A;
286 type IntoIter = IterMut<'a, A>;
287
288 fn into_iter(self) -> Self::IntoIter {
289 self.iter_mut()
290 }
291}
292
293impl<E, A> Validation<E, A> {
294 /// Returns an iterator over the valid value.
295 ///
296 /// The iterator yields at most one item - the valid value if present.
297 /// For invalid validations, the iterator yields nothing.
298 ///
299 /// # Examples
300 ///
301 /// ```
302 /// use error_rail::validation::Validation;
303 ///
304 /// let valid: Validation<String, i32> = Validation::Valid(5);
305 /// assert_eq!(valid.iter().next(), Some(&5));
306 ///
307 /// let invalid: Validation<String, i32> = Validation::invalid("error".to_string());
308 /// assert_eq!(invalid.iter().next(), None);
309 /// ```
310 #[must_use]
311 pub fn iter(&self) -> Iter<'_, A> {
312 match self {
313 Validation::Valid(a) => Iter { inner: Some(a) },
314 _ => Iter { inner: None },
315 }
316 }
317
318 /// Returns a mutable iterator over the valid value.
319 ///
320 /// The iterator yields at most one mutable reference - to the valid value if present.
321 /// For invalid validations, the iterator yields nothing.
322 ///
323 /// # Examples
324 ///
325 /// ```
326 /// use error_rail::validation::Validation;
327 ///
328 /// let mut valid: Validation<String, i32> = Validation::Valid(5);
329 /// if let Some(value) = valid.iter_mut().next() {
330 /// *value = 10;
331 /// }
332 /// assert_eq!(valid, Validation::Valid(10));
333 /// ```
334 #[must_use]
335 pub fn iter_mut(&mut self) -> IterMut<'_, A> {
336 match self {
337 Validation::Valid(a) => IterMut { inner: Some(a) },
338 _ => IterMut { inner: None },
339 }
340 }
341
342 /// Returns an iterator over the errors.
343 ///
344 /// For invalid validations, yields references to all accumulated errors.
345 /// For valid validations, yields nothing.
346 ///
347 /// # Examples
348 ///
349 /// ```
350 /// use error_rail::validation::Validation;
351 ///
352 /// let valid: Validation<String, i32> = Validation::Valid(5);
353 /// assert_eq!(valid.iter_errors().next(), None);
354 ///
355 /// let invalid: Validation<String, i32> = Validation::invalid("error".to_string());
356 /// assert_eq!(invalid.iter_errors().next(), Some(&"error".to_string()));
357 ///
358 /// let multi_invalid: Validation<&str, i32> = Validation::invalid_many(["err1", "err2"]);
359 /// assert_eq!(multi_invalid.iter_errors().count(), 2);
360 /// ```
361 #[must_use]
362 pub fn iter_errors(&self) -> ErrorsIter<'_, E> {
363 match self {
364 Self::Valid(_) => ErrorsIter::Empty,
365 Self::Invalid(errors) => ErrorsIter::Multi(errors.iter()),
366 }
367 }
368
369 /// Returns a mutable iterator over the errors.
370 ///
371 /// For invalid validations, yields mutable references to all accumulated errors.
372 /// For valid validations, yields nothing.
373 ///
374 /// # Examples
375 ///
376 /// ```
377 /// use error_rail::validation::Validation;
378 ///
379 /// let mut invalid: Validation<String, i32> = Validation::invalid("error".to_string());
380 /// for error in invalid.iter_errors_mut() {
381 /// error.push_str(" [updated]");
382 /// }
383 /// assert_eq!(
384 /// invalid.iter_errors().next(),
385 /// Some(&"error [updated]".to_string())
386 /// );
387 /// ```
388 #[must_use]
389 pub fn iter_errors_mut(&mut self) -> ErrorsIterMut<'_, E> {
390 match self {
391 Validation::Invalid(es) => ErrorsIterMut::Multi(es.iter_mut()),
392 _ => ErrorsIterMut::Empty,
393 }
394 }
395}
396
397/// Collects an iterator of `Result`s into a single `Validation`, aggregating all errors.
398///
399/// If all results are `Ok`, returns `Valid` with a collection of all success values.
400/// If any results are `Err`, returns `Invalid` with all accumulated errors.
401///
402/// This is useful for validating multiple operations and collecting all failures
403/// instead of short-circuiting on the first error.
404///
405/// # Examples
406///
407/// ```
408/// use error_rail::validation::Validation;
409///
410/// let inputs = vec![Ok(1), Err("oops"), Ok(2)];
411/// let collected: Validation<&str, Vec<i32>> = inputs.into_iter().collect();
412/// assert!(collected.is_invalid());
413/// assert_eq!(collected.into_errors().unwrap()[0], "oops");
414///
415/// let all_ok = vec![Ok(1), Ok(2), Ok(3)];
416/// let collected: Validation<&str, Vec<i32>> = all_ok.into_iter().collect();
417/// assert_eq!(collected, Validation::Valid(vec![1, 2, 3]));
418/// ```
419impl<E, A, C> FromIterator<Result<A, E>> for Validation<E, C>
420where
421 C: FromIterator<A>,
422{
423 fn from_iter<T: IntoIterator<Item = Result<A, E>>>(iter: T) -> Self {
424 let mut values: smallvec::SmallVec<[A; 2]> = smallvec::SmallVec::new();
425 let mut errors = ErrorVec::new();
426
427 for item in iter {
428 match item {
429 Ok(v) => values.push(v),
430 Err(e) => errors.push(e),
431 }
432 }
433
434 if errors.is_empty() {
435 let collected: C = values.into_iter().collect();
436 Validation::Valid(collected)
437 } else {
438 Validation::Invalid(errors)
439 }
440 }
441}
442
443/// Collects an iterator of `Validation`s into a single `Validation`, aggregating all errors.
444///
445/// If all validations are valid, returns `Valid` with a collection of all success values.
446/// If any validations are invalid, returns `Invalid` with all accumulated errors from all
447/// invalid validations.
448///
449/// This is the primary way to combine multiple validations while preserving all error information.
450///
451/// # Examples
452///
453/// ```
454/// use error_rail::validation::Validation;
455///
456/// let items = vec![Validation::valid(1), Validation::invalid("bad")];
457/// let collected: Validation<&str, Vec<i32>> = items.into_iter().collect();
458/// assert!(collected.is_invalid());
459/// ```
460impl<E, A, C> FromIterator<Validation<E, A>> for Validation<E, C>
461where
462 C: FromIterator<A>,
463{
464 fn from_iter<T: IntoIterator<Item = Validation<E, A>>>(iter: T) -> Self {
465 let mut values: smallvec::SmallVec<[A; 2]> = smallvec::SmallVec::new();
466 let mut errors = ErrorVec::new();
467
468 for item in iter {
469 match item {
470 Validation::Valid(v) => values.push(v),
471 Validation::Invalid(es) => errors.extend(es),
472 }
473 }
474
475 if errors.is_empty() {
476 let collected: C = values.into_iter().collect();
477 Validation::Valid(collected)
478 } else {
479 Validation::Invalid(errors)
480 }
481 }
482}