error_rail/traits/with_error.rs
1use crate::ErrorVec;
2
3/// Abstraction over types that carry an error variant which can be remapped.
4///
5/// This trait provides a generic interface for types that contain both success and error cases,
6/// allowing transformation of the error type while preserving the success value.
7///
8/// # Type Parameters
9///
10/// * `E` - The current error type contained in the implementor
11///
12/// # Associated Types
13///
14/// * `Success` - The success value type when no error is present
15/// * `ErrorOutput<G>` - The output type after mapping the error to type `G`
16///
17/// # Examples
18///
19/// ```
20/// use error_rail::traits::WithError;
21///
22/// let result: Result<i32, &str> = Err("original error");
23/// let mapped = result.fmap_error(|e| format!("Error: {}", e));
24/// assert_eq!(mapped, Err("Error: original error".to_string()));
25/// ```
26pub trait WithError<E> {
27 type Success;
28
29 type ErrorOutput<G>;
30
31 /// Maps the error value using `f`, producing a new container with error type `G`.
32 ///
33 /// This operation leaves the success case untouched and only transforms the error.
34 ///
35 /// # Arguments
36 ///
37 /// * `f` - A function that transforms the error from type `E` to type `G`
38 ///
39 /// # Examples
40 ///
41 /// ```
42 /// use error_rail::traits::WithError;
43 ///
44 /// let result: Result<i32, u32> = Err(404);
45 /// let mapped = result.fmap_error(|code| format!("HTTP {}", code));
46 /// assert_eq!(mapped, Err("HTTP 404".to_string()));
47 /// ```
48 fn fmap_error<F, G>(self, f: F) -> Self::ErrorOutput<G>
49 where
50 F: Fn(E) -> G;
51
52 /// Converts the container into a `Result`, taking only the first error if invalid.
53 ///
54 /// **⚠️ DEPRECATED**: Use [`to_result_first()`](Self::to_result_first) or
55 /// [`to_result_all()`](Self::to_result_all) for explicit error handling.
56 ///
57 /// For types that are already `Result`, this is a no-op.
58 /// For other types, this extracts the success/error into standard Result form.
59 ///
60 /// # Examples
61 ///
62 /// ```
63 /// use error_rail::traits::WithError;
64 ///
65 /// let result: Result<i32, &str> = Ok(42);
66 /// assert_eq!(result.to_result(), Ok(42));
67 /// ```
68 #[deprecated(
69 since = "0.6.0",
70 note = "Use to_result_first() or to_result_all() for explicit error handling"
71 )]
72 fn to_result(self) -> Result<Self::Success, E>;
73
74 /// Converts the container into a `Result`, taking only the first error if invalid.
75 ///
76 /// This method explicitly indicates that only the first error will be returned,
77 /// potentially losing additional errors in multi-error scenarios.
78 ///
79 /// # Examples
80 ///
81 /// ```
82 /// use error_rail::traits::WithError;
83 ///
84 /// let result: Result<i32, &str> = Ok(42);
85 /// assert_eq!(result.to_result_first(), Ok(42));
86 /// ```
87 fn to_result_first(self) -> Result<Self::Success, E>;
88
89 /// Converts the container into a `Result`, preserving all errors if invalid.
90 ///
91 /// This method returns all accumulated errors in a `Vec<E>`, ensuring no error
92 /// information is lost during the conversion.
93 ///
94 /// # Examples
95 ///
96 /// ```
97 /// use error_rail::traits::WithError;
98 ///
99 /// let result: Result<i32, &str> = Ok(42);
100 /// assert_eq!(result.to_result_all(), Ok(42));
101 /// ```
102 fn to_result_all(self) -> Result<Self::Success, ErrorVec<E>>;
103}
104
105impl<T, E> WithError<E> for Result<T, E> {
106 type Success = T;
107 type ErrorOutput<G> = Result<T, G>;
108
109 fn fmap_error<F, G>(self, f: F) -> Self::ErrorOutput<G>
110 where
111 F: FnOnce(E) -> G,
112 {
113 match self {
114 Ok(t) => Ok(t),
115 Err(e) => Err(f(e)),
116 }
117 }
118
119 fn to_result(self) -> Result<Self::Success, E> {
120 self.to_result_first()
121 }
122
123 fn to_result_first(self) -> Result<Self::Success, E> {
124 self
125 }
126
127 fn to_result_all(self) -> Result<Self::Success, ErrorVec<E>> {
128 match self {
129 Ok(t) => Ok(t),
130 Err(e) => {
131 let mut error_vec = ErrorVec::new();
132 error_vec.push(e);
133 Err(error_vec)
134 }
135 }
136 }
137}