skp_validator_core/
result.rs1use crate::error::ValidationErrors;
4
5pub type ValidationResult<T> = Result<T, ValidationErrors>;
10
11pub trait ValidationResultExt<T> {
13 fn map_valid<U, F: FnOnce(T) -> U>(self, f: F) -> ValidationResult<U>;
15
16 fn and_also<U>(self, other: ValidationResult<U>) -> ValidationResult<(T, U)>;
18
19 fn with_errors(self, other: ValidationResult<()>) -> ValidationResult<T>;
21}
22
23impl<T> ValidationResultExt<T> for ValidationResult<T> {
24 fn map_valid<U, F: FnOnce(T) -> U>(self, f: F) -> ValidationResult<U> {
25 self.map(f)
26 }
27
28 fn and_also<U>(self, other: ValidationResult<U>) -> ValidationResult<(T, U)> {
29 match (self, other) {
30 (Ok(t), Ok(u)) => Ok((t, u)),
31 (Err(mut e1), Err(e2)) => {
32 e1.merge(e2);
33 Err(e1)
34 }
35 (Err(e), Ok(_)) | (Ok(_), Err(e)) => Err(e),
36 }
37 }
38
39 fn with_errors(self, other: ValidationResult<()>) -> ValidationResult<T> {
40 match (self, other) {
41 (Ok(t), Ok(())) => Ok(t),
42 (Err(mut e1), Err(e2)) => {
43 e1.merge(e2);
44 Err(e1)
45 }
46 (Err(e), Ok(())) => Err(e),
47 (Ok(_), Err(e)) => Err(e),
48 }
49 }
50}
51
52pub struct ValidationCollector {
54 errors: ValidationErrors,
55}
56
57impl ValidationCollector {
58 pub fn new() -> Self {
60 Self {
61 errors: ValidationErrors::new(),
62 }
63 }
64
65 pub fn collect<T>(&mut self, result: ValidationResult<T>) -> Option<T> {
67 match result {
68 Ok(v) => Some(v),
69 Err(e) => {
70 self.errors.merge(e);
71 None
72 }
73 }
74 }
75
76 pub fn collect_field<T>(
78 &mut self,
79 field: impl Into<String>,
80 result: ValidationResult<T>,
81 ) -> Option<T> {
82 match result {
83 Ok(v) => Some(v),
84 Err(e) => {
85 self.errors.add_nested_errors(field, e);
86 None
87 }
88 }
89 }
90
91 pub fn has_errors(&self) -> bool {
93 !self.errors.is_empty()
94 }
95
96 pub fn errors(&self) -> &ValidationErrors {
98 &self.errors
99 }
100
101 pub fn finish(self) -> ValidationResult<()> {
103 if self.errors.is_empty() {
104 Ok(())
105 } else {
106 Err(self.errors)
107 }
108 }
109
110 pub fn finish_with<T>(self, value: T) -> ValidationResult<T> {
112 if self.errors.is_empty() {
113 Ok(value)
114 } else {
115 Err(self.errors)
116 }
117 }
118}
119
120impl Default for ValidationCollector {
121 fn default() -> Self {
122 Self::new()
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129 use crate::ValidationError;
130
131 #[test]
132 fn test_and_also_both_ok() {
133 let r1: ValidationResult<i32> = Ok(1);
134 let r2: ValidationResult<&str> = Ok("test");
135 let combined = r1.and_also(r2);
136 assert_eq!(combined.unwrap(), (1, "test"));
137 }
138
139 #[test]
140 fn test_and_also_both_err() {
141 let mut e1 = ValidationErrors::new();
142 e1.add_field_error("a", ValidationError::new("a", "code", "Error A"));
143
144 let mut e2 = ValidationErrors::new();
145 e2.add_field_error("b", ValidationError::new("b", "code", "Error B"));
146
147 let r1: ValidationResult<i32> = Err(e1);
148 let r2: ValidationResult<&str> = Err(e2);
149 let combined = r1.and_also(r2);
150
151 let errors = combined.unwrap_err();
152 assert_eq!(errors.count(), 2);
153 }
154
155 #[test]
156 fn test_collector() {
157 let mut collector = ValidationCollector::new();
158
159 let r1: ValidationResult<i32> = Ok(42);
160 let v1 = collector.collect(r1);
161 assert_eq!(v1, Some(42));
162
163 let mut e = ValidationErrors::new();
164 e.add_field_error("x", ValidationError::new("x", "code", "Error"));
165 let r2: ValidationResult<i32> = Err(e);
166 let v2 = collector.collect(r2);
167 assert_eq!(v2, None);
168
169 assert!(collector.has_errors());
170 assert!(collector.finish().is_err());
171 }
172}