error_rail/validation/
traits.rs

1use crate::traits::ErrorCategory;
2use crate::traits::WithError;
3use crate::validation::core::Validation;
4use crate::ErrorVec;
5
6/// Implementation of [`ErrorCategory`] for [`Validation`] types.
7///
8/// This allows `Validation<E, ()>` to act as an error category, where:
9/// - `lift` creates `Valid` values
10/// - `handle_error` creates `Invalid` values with a single error
11///
12/// # Examples
13///
14/// ```
15/// use error_rail::traits::ErrorCategory;
16/// use error_rail::validation::Validation;
17///
18/// let valid: Validation<String, i32> = <Validation<String, ()>>::lift(42);
19/// assert!(valid.is_valid());
20///
21/// let invalid: Validation<String, i32> = <Validation<String, ()>>::handle_error("error".to_string());
22/// assert!(invalid.is_invalid());
23/// ```
24impl<E> ErrorCategory<E> for Validation<E, ()> {
25    type ErrorFunctor<T> = Validation<E, T>;
26
27    #[inline]
28    fn lift<T>(value: T) -> Validation<E, T> {
29        Validation::Valid(value)
30    }
31
32    #[inline]
33    fn handle_error<T>(error: E) -> Validation<E, T> {
34        Validation::invalid(error)
35    }
36}
37
38/// Implementation of `WithError` for `Validation` types.
39///
40/// This allows transforming the error type of a validation while preserving
41/// the success value and accumulating all errors through the transformation.
42///
43/// # Examples
44///
45/// ```
46/// use error_rail::traits::WithError;
47/// use error_rail::validation::Validation;
48///
49/// let validation: Validation<&str, i32> = Validation::invalid_many(vec!["err1", "err2"]);
50/// let mapped = validation.fmap_error(|e| format!("Error: {}", e));
51/// assert_eq!(mapped.iter_errors().count(), 2);
52///
53/// let valid: Validation<&str, i32> = Validation::valid(42);
54/// let result = valid.to_result();
55/// assert_eq!(result, Ok(42));
56/// ```
57impl<T, E> WithError<E> for Validation<E, T> {
58    type Success = T;
59    type ErrorOutput<G> = Validation<G, T>;
60
61    fn fmap_error<F, G>(self, f: F) -> Self::ErrorOutput<G>
62    where
63        F: Fn(E) -> G,
64    {
65        match self {
66            Validation::Valid(t) => Validation::Valid(t),
67            Validation::Invalid(e) => Validation::Invalid(e.into_iter().map(f).collect()),
68        }
69    }
70
71    /// Converts the validation to a result, taking only the first error if invalid.
72    ///
73    /// **⚠️ DEPRECATED**: Use [`to_result_first()`](Self::to_result_first) or
74    /// [`to_result_all()`](Self::to_result_all) for explicit error handling.
75    /// This method loses additional errors in multi-error scenarios.
76    ///
77    /// # Returns
78    ///
79    /// * `Ok(value)` if validation is valid
80    /// * `Err(first_error)` if validation is invalid (only the first error)
81    fn to_result(self) -> Result<Self::Success, E> {
82        self.to_result_first()
83    }
84
85    /// Converts the validation to a result, taking only the first error if invalid.
86    ///
87    /// This method explicitly indicates that only the first error will be returned,
88    /// potentially losing additional errors in multi-error scenarios.
89    ///
90    /// # Returns
91    ///
92    /// * `Ok(value)` if validation is valid
93    /// * `Err(first_error)` if validation is invalid (only the first error)
94    ///
95    /// # Examples
96    ///
97    /// ```
98    /// use error_rail::validation::Validation;
99    /// use error_rail::traits::WithError;
100    ///
101    /// let valid = Validation::<&str, i32>::valid(42);
102    /// assert_eq!(valid.to_result_first(), Ok(42));
103    ///
104    /// let invalid = Validation::<&str, i32>::invalid_many(vec!["error1", "error2"]);
105    /// assert_eq!(invalid.to_result_first(), Err("error1"));
106    /// ```
107    fn to_result_first(self) -> Result<Self::Success, E> {
108        match self {
109            Validation::Valid(t) => Ok(t),
110            Validation::Invalid(e) => Err(e.into_iter().next().unwrap()),
111        }
112    }
113
114    /// Converts the validation to a result, preserving all errors if invalid.
115    ///
116    /// This method returns all accumulated errors in a `Vec<E>`, ensuring no error
117    /// information is lost during the conversion.
118    ///
119    /// # Returns
120    ///
121    /// * `Ok(value)` if validation is valid
122    /// * `Err(all_errors)` if validation is invalid (all errors in a Vec)
123    ///
124    /// # Examples
125    ///
126    /// ```
127    /// use error_rail::validation::Validation;
128    /// use error_rail::traits::WithError;
129    ///
130    /// let valid = Validation::<&str, i32>::valid(42);
131    /// assert_eq!(valid.to_result_all(), Ok(42));
132    ///
133    /// let invalid = Validation::<&str, i32>::invalid_many(vec!["error1", "error2"]);
134    /// assert_eq!(invalid.to_result_all(), Err(vec!["error1", "error2"].into()));
135    /// ```
136    fn to_result_all(self) -> Result<Self::Success, ErrorVec<E>> {
137        match self {
138            Validation::Valid(t) => Ok(t),
139            Validation::Invalid(e) => Err(e),
140        }
141    }
142}