├── .github └── workflows │ └── rust.yml ├── .gitignore ├── CHANGELOG.md ├── Cargo.toml ├── README.md └── src └── lib.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Tests 3 | 4 | on: 5 | push: 6 | branches: [master] 7 | pull_request: 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v2.3.4 18 | 19 | - name: Cache Dependencies 20 | uses: Swatinem/rust-cache@v1 21 | 22 | - name: Run tests 23 | run: cargo test --all-features 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # `validated` Changelog 2 | 3 | ### 0.5.0 (2025-05-02) 4 | 5 | #### Changed 6 | 7 | - Bump `nonempty-collections` to `0.3`, which had many breaking changes itself, 8 | so we bump here too. 9 | 10 | ### 0.4.1 (2024-04-09) 11 | 12 | #### Changed 13 | 14 | - Bumped dependencies. 15 | 16 | ### 0.4.0 (2023-05-09) 17 | 18 | #### Changed 19 | 20 | - Swap the underlying non-empty vector type to `NEVec` from `nonempty-collections`. 21 | 22 | ### 0.3.0 (2022-10-18) 23 | 24 | #### Added 25 | 26 | - `Sum` instances for collecting into summable-things. 27 | 28 | ### 0.2.0 (2022-08-13) 29 | 30 | #### Changed 31 | 32 | - Bumped `nonempty` dependency, which itself recently had a breaking change. 33 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "validated" 3 | version = "0.5.0" 4 | authors = ["Colin Woodbury ", "John Archer "] 5 | edition = "2021" 6 | description = "The cumulative sibling of `Result` and `Either`." 7 | homepage = "https://github.com/fosskers/validated" 8 | repository = "https://github.com/fosskers/validated" 9 | readme = "README.md" 10 | license = "MIT" 11 | keywords = ["validation", "errors"] 12 | categories = ["data-structures", "rust-patterns"] 13 | 14 | [dependencies] 15 | nonempty-collections = "0.3.0" 16 | rayon = { version = "1.10", optional = true } 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # validated 2 | 3 | 4 | 5 | The cumulative sibling of `Result` and `Either`. 6 | 7 | The `Validated` type has special `FromIterator` instances that enable 8 | _all_ errors in a sequence to be reported, not just the first one. 9 | 10 | ## Motivation 11 | 12 | We might think of `Iterator::collect` as being for consolidating the 13 | result of some chained iteration into a concrete container, like `Vec`. 14 | 15 | ```rust 16 | let v = vec![1,2,3]; 17 | assert_eq!(vec![2,4,6], v.into_iter().map(|n| n * 2).collect::>()); 18 | ``` 19 | 20 | But `collect` isn't limited to this; it can be used to "fold" down into any 21 | type you like, provided that it implements `FromIterator`. Consider the 22 | effects of such an `impl` for `Result`: 23 | 24 | ```rust 25 | let v: Vec = vec![1, 2, 3]; 26 | let r: Result, &str> = v 27 | .into_iter() 28 | .map(|n| if n % 2 == 0 { Err("Oh no!") } else { Ok(n * 2) }) 29 | .collect(); 30 | assert_eq!(Err("Oh no!"), r); 31 | ``` 32 | 33 | The `Result` has been "interweaved" and pulled back out. Critically, this 34 | `collect` call short-circuits; `n * 2` is never called for `3`, since the 35 | `map` "fails" at `2`. This is useful when we require a sequence of IO 36 | actions to all succeed and we wish to cancel remaining operations as soon 37 | as any error occurs. 38 | 39 | But what if we don't want to short circuit? What if we want a report of all 40 | the errors that occurred? 41 | 42 | ### Cumulative Errors and `Validated` 43 | 44 | Consider three cases where we'd want a report of all errors, not just the 45 | first one: 46 | 47 | 1. Form input validation. 48 | 2. Type checking. 49 | 3. Concurrent IO. 50 | 51 | In the first case, if a user makes several input mistakes, it's the best 52 | experience for them if all errors are reported at once so that they can make 53 | their corrections in a single pass. 54 | 55 | In the second case, knowing only the first detected type error might not 56 | actually be the site of the real issue. We need everything that's broken to 57 | be reported so we can make the best decision of what to fix. 58 | 59 | In the third case, it may be that halting your entire concurrent job upon 60 | detection of a single failure isn't appropriate. You might instead want 61 | everything to finish as it can, and then collect a bundle of errors at the 62 | end. 63 | 64 | The `Validated` type accomodates these use cases; it is a "cumulative `Result`". 65 | 66 | ```rust 67 | use validated::Validated::{self, Good, Fail}; 68 | use nonempty_collections::*; 69 | 70 | let v = vec![Good(1), Validated::fail("No!"), Good(3), Validated::fail("Ack!")]; 71 | let r: Validated, &str> = Fail(nev!["No!", "Ack!"]); 72 | assert_eq!(r, v.into_iter().collect()); 73 | ``` 74 | 75 | ### Use of non-empty Vectors (`NEVec`) 76 | 77 | In the spirit of "make illegal states unrepresentable", the `Fail` variant 78 | of `Validated` contains a `NEVec`, a non-empty `Vec`. `NEVec` can do 79 | everything that `Vec` can do, plus some additional benefits. In the case of 80 | this crate, this representation forbids the otherwise meaningless `Fail(vec![])`. 81 | 82 | In other words, if you have a `Validated`, you either have a concrete 83 | `T`, or **at least one** `E`. 84 | 85 | ## Features 86 | 87 | - `rayon`: Enable `FromParallelIterator` instances for `Validated`. 88 | 89 | ## Resources 90 | 91 | - [Haskell: Validation][haskell] 92 | - [Scala: Cats `Validated`][cats] 93 | 94 | [haskell]: https://hackage.haskell.org/package/validation 95 | [cats]: https://typelevel.org/cats/datatypes/validated.html 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! The cumulative sibling of `Result` and `Either`. 2 | //! 3 | //! The [`Validated`] type has special `FromIterator` instances that enable 4 | //! _all_ errors in a sequence to be reported, not just the first one. 5 | //! 6 | //! # Motivation 7 | //! 8 | //! We might think of [`Iterator::collect`] as being for consolidating the 9 | //! result of some chained iteration into a concrete container, like `Vec`. 10 | //! 11 | //! ``` 12 | //! let v = vec![1,2,3]; 13 | //! assert_eq!(vec![2,4,6], v.into_iter().map(|n| n * 2).collect::>()); 14 | //! ``` 15 | //! 16 | //! But `collect` isn't limited to this; it can be used to "fold" down into any 17 | //! type you like, provided that it implements [`FromIterator`]. Consider the 18 | //! effects of such an `impl` for `Result`: 19 | //! 20 | //! ``` 21 | //! let v: Vec = vec![1, 2, 3]; 22 | //! let r: Result, &str> = v 23 | //! .into_iter() 24 | //! .map(|n| if n % 2 == 0 { Err("Oh no!") } else { Ok(n * 2) }) 25 | //! .collect(); 26 | //! assert_eq!(Err("Oh no!"), r); 27 | //! ``` 28 | //! 29 | //! The `Result` has been "interweaved" and pulled back out. Critically, this 30 | //! `collect` call short-circuits; `n * 2` is never called for `3`, since the 31 | //! `map` "fails" at `2`. This is useful when we require a sequence of IO 32 | //! actions to all succeed and we wish to cancel remaining operations as soon 33 | //! as any error occurs. 34 | //! 35 | //! But what if we don't want to short circuit? What if we want a report of all 36 | //! the errors that occurred? 37 | //! 38 | //! ## Cumulative Errors and `Validated` 39 | //! 40 | //! Consider three cases where we'd want a report of all errors, not just the 41 | //! first one: 42 | //! 43 | //! 1. Form input validation. 44 | //! 2. Type checking. 45 | //! 3. Concurrent IO. 46 | //! 47 | //! In the first case, if a user makes several input mistakes, it's the best 48 | //! experience for them if all errors are reported at once so that they can make 49 | //! their corrections in a single pass. 50 | //! 51 | //! In the second case, knowing only the first detected type error might not 52 | //! actually be the site of the real issue. We need everything that's broken to 53 | //! be reported so we can make the best decision of what to fix. 54 | //! 55 | //! In the third case, it may be that halting your entire concurrent job upon 56 | //! detection of a single failure isn't appropriate. You might instead want 57 | //! everything to finish as it can, and then collect a bundle of errors at the 58 | //! end. 59 | //! 60 | //! The [`Validated`] type accomodates these use cases; it is a "cumulative `Result`". 61 | //! 62 | //! ``` 63 | //! use validated::Validated::{self, Good, Fail}; 64 | //! use nonempty_collections::*; 65 | //! 66 | //! let v = vec![Good(1), Validated::fail("No!"), Good(3), Validated::fail("Ack!")]; 67 | //! let r: Validated, &str> = Fail(nev!["No!", "Ack!"]); 68 | //! assert_eq!(r, v.into_iter().collect()); 69 | //! ``` 70 | //! 71 | //! ## Use of non-empty Vectors (`NEVec`) 72 | //! 73 | //! In the spirit of "make illegal states unrepresentable", the [`Fail`] variant 74 | //! of `Validated` contains a [`NEVec`], a non-empty `Vec`. `NEVec` can do 75 | //! everything that `Vec` can do, plus some additional benefits. In the case of 76 | //! this crate, this representation forbids the otherwise meaningless `Fail(vec![])`. 77 | //! 78 | //! In other words, if you have a `Validated`, you either have a concrete 79 | //! `T`, or **at least one** `E`. 80 | //! 81 | //! # Features 82 | //! 83 | //! - `rayon`: Enable `FromParallelIterator` instances for `Validated`. 84 | //! 85 | //! # Resources 86 | //! 87 | //! - [Haskell: Validation][haskell] 88 | //! - [Scala: Cats `Validated`][cats] 89 | //! 90 | //! [haskell]: https://hackage.haskell.org/package/validation 91 | //! [cats]: https://typelevel.org/cats/datatypes/validated.html 92 | 93 | #![warn(missing_docs)] 94 | #![doc(html_root_url = "https://docs.rs/validated/0.4.1")] 95 | 96 | use crate::Validated::{Fail, Good}; 97 | use std::iter::{FromIterator, Sum}; 98 | use std::ops::{Deref, DerefMut}; 99 | 100 | use nonempty_collections::{nev, NEVec, NonEmptyIterator}; 101 | #[cfg(feature = "rayon")] 102 | use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelIterator}; 103 | #[cfg(feature = "rayon")] 104 | use std::sync::Mutex; 105 | 106 | /// Similar to [`Result`], but cumulative in its error type. 107 | /// 108 | /// # Error weaving 109 | /// 110 | /// Consider that when using `collect` in a "Traversable" way to pull a single 111 | /// `Result` out of an `Iterator` containing many `Result`s, it will fail on the 112 | /// first `Err` and short-circuit the iteration. This is suboptimal if we wish 113 | /// to be made aware of every failure that (would have) occurred. 114 | /// 115 | /// ``` 116 | /// use validated::Validated::{self, Good, Fail}; 117 | /// use nonempty_collections::*; 118 | /// 119 | /// let v = vec![Ok(1), Ok(2), Ok(3)]; 120 | /// let r: Validated, &str> = Good(vec![1, 2, 3]); 121 | /// assert_eq!(r, v.into_iter().collect()); 122 | /// 123 | /// let v = vec![Ok(1), Err("Oh!"), Ok(2), Err("No!"), Ok(3)]; 124 | /// let r: Validated, &str> = Fail(nev!["Oh!", "No!"]); 125 | /// assert_eq!(r, v.into_iter().collect()); 126 | /// ``` 127 | /// 128 | /// Naturally iterators of `Validated` values can be collected in a similar way: 129 | /// 130 | /// ``` 131 | /// use validated::Validated::{self, Good, Fail}; 132 | /// use nonempty_collections::*; 133 | /// 134 | /// let v = vec![Good(1), Good(2), Good(3)]; 135 | /// let r: Validated, &str> = Good(vec![1, 2, 3]); 136 | /// assert_eq!(r, v.into_iter().collect()); 137 | /// 138 | /// let v = vec![Good(1), Validated::fail("No!"), Good(3), Validated::fail("Ack!")]; 139 | /// let r: Validated, &str> = Fail(nev!["No!", "Ack!"]); 140 | /// assert_eq!(r, v.into_iter().collect()); 141 | /// ``` 142 | /// 143 | /// # Mapping composite results 144 | /// 145 | /// This type also provides `mapN` methods, which are surprisingly missing on 146 | /// `Option` and `Result`. 147 | /// 148 | /// ``` 149 | /// use validated::Validated::{self, Good, Fail}; 150 | /// 151 | /// let v: Validated = Good(1).map3(Good(2), Good(3), |a, b, c| a + b + c); 152 | /// assert_eq!(v, Good(6)); 153 | /// ``` 154 | /// 155 | /// For `Validated` in particular these are quite useful, as a meaningful 156 | /// `and_then` cannot be written for it. 157 | /// 158 | /// Formally, `Validated` is not a Monad, but it is an Applicative Functor. 159 | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)] 160 | pub enum Validated { 161 | /// Analogous to [`Result::Ok`]. 162 | Good(T), 163 | /// Analogous to [`Result::Err`], except that the error type is cumulative. 164 | Fail(NEVec), 165 | } 166 | 167 | impl Validated { 168 | /// Fail with the given error. 169 | pub fn fail(e: E) -> Validated { 170 | Fail(nev![e]) 171 | } 172 | 173 | /// Converts from `&mut Validated` to `Validated<&mut T, &mut E>`. 174 | /// 175 | /// **Note:** In the case of [`Fail`], a new `Vec` of references is 176 | /// allocated. 177 | pub fn as_mut(&mut self) -> Validated<&mut T, &mut E> { 178 | match self { 179 | Good(ref mut t) => Good(t), 180 | Fail(ref mut e) => { 181 | let ne = e.nonempty_iter_mut().collect(); 182 | Fail(ne) 183 | } 184 | } 185 | } 186 | 187 | /// Converts from `&Validated` to `Validated<&T, &E>`. 188 | /// 189 | /// Produces a new `Validated`, containing references to the original, 190 | /// leaving the original in place. 191 | /// 192 | /// **Note:** In the case of [`Fail`], a new `Vec` of references is 193 | /// allocated. 194 | pub fn as_ref(&self) -> Validated<&T, &E> { 195 | match self { 196 | Good(ref t) => Good(t), 197 | Fail(e) => { 198 | let ne = e.nonempty_iter().collect(); 199 | Fail(ne) 200 | } 201 | } 202 | } 203 | 204 | /// Returns the contained [`Good`] value, consuming `self`. 205 | /// 206 | /// # Panics 207 | /// 208 | /// Panics with a custom message if `self` is actually the `Fail` 209 | /// variant. 210 | pub fn expect(self, msg: &str) -> T { 211 | match self { 212 | Good(t) => t, 213 | Fail(_) => panic!("{}", msg), 214 | } 215 | } 216 | 217 | /// Was a given `Validated` operation completely successful? 218 | pub fn is_good(&self) -> bool { 219 | matches!(self, Good(_)) 220 | } 221 | 222 | /// Did a given `Validated` operation have at least one failure? 223 | pub fn is_fail(&self) -> bool { 224 | matches!(self, Fail(_)) 225 | } 226 | 227 | /// Returns an iterator over the possibly contained value. 228 | /// 229 | /// The iterator yields one value if the result is [`Good`], otherwise 230 | /// nothing. 231 | pub fn iter(&self) -> Iter<'_, T> { 232 | Iter { 233 | inner: self.as_ref().ok().ok(), 234 | } 235 | } 236 | 237 | /// Returns a mutable iterator over the possibly contained value. 238 | /// 239 | /// The iterator yields one value if the result is [`Good`], otherwise 240 | /// nothing. 241 | pub fn iter_mut(&mut self) -> IterMut<'_, T> { 242 | IterMut { 243 | inner: self.as_mut().ok().ok(), 244 | } 245 | } 246 | 247 | /// Applies a function to the `T` value of a [`Good`] variant, or leaves 248 | /// a [`Fail`] variant untouched. 249 | /// 250 | /// ``` 251 | /// use validated::Validated::{self, Good, Fail}; 252 | /// 253 | /// let v: Validated = Good(1); 254 | /// let r = v.map(|n| n * 2); 255 | /// assert_eq!(r, Good(2)); 256 | /// 257 | /// let v: Validated = Validated::fail("No!"); 258 | /// let r = v.map(|n| n * 2); 259 | /// assert_eq!(r, Validated::fail("No!")); 260 | /// ``` 261 | pub fn map(self, op: F) -> Validated 262 | where 263 | F: FnOnce(T) -> U, 264 | { 265 | match self { 266 | Good(t) => Good(op(t)), 267 | Fail(e) => Fail(e), 268 | } 269 | } 270 | 271 | /// Applies a function to the `Vec` of a [`Fail`] variant, or leaves a 272 | /// [`Good`] variant untouched. 273 | pub fn map_err(self, op: F) -> Validated 274 | where 275 | F: FnOnce(NEVec) -> NEVec, 276 | { 277 | match self { 278 | Good(t) => Good(t), 279 | Fail(e) => Fail(op(e)), 280 | } 281 | } 282 | 283 | /// Maps a function over two `Validated`, but only if both are of the 284 | /// `Good` variant. If both failed, then their errors are concatenated. 285 | /// 286 | /// ``` 287 | /// use validated::Validated::{self, Good, Fail}; 288 | /// 289 | /// let v: Validated = Good(1).map2(Good(2), |a, b| a + b); 290 | /// assert_eq!(v, Good(3)); 291 | /// 292 | /// let v: Validated = Good(1).map2(Validated::fail("No!"), |a, b: u32| a + b); 293 | /// assert_eq!(v, Validated::fail("No!")); 294 | /// ``` 295 | pub fn map2(self, vu: Validated, f: F) -> Validated 296 | where 297 | F: FnOnce(T, U) -> Z, 298 | { 299 | match (self, vu) { 300 | (Good(t), Good(u)) => Good(f(t, u)), 301 | (Good(_), Fail(e)) => Fail(e), 302 | (Fail(e), Good(_)) => Fail(e), 303 | (Fail(mut e0), Fail(e1)) => { 304 | e0.extend(e1); 305 | Fail(e0) 306 | } 307 | } 308 | } 309 | 310 | /// Maps a function over three `Validated`, but only if all three are of the 311 | /// `Good` variant. If any failed, then their errors are concatenated. 312 | /// 313 | /// ``` 314 | /// use validated::Validated::{self, Good, Fail}; 315 | /// 316 | /// let v: Validated = Good(1).map3(Good(2), Good(3), |a, b, c| a + b + c); 317 | /// assert_eq!(v, Good(6)); 318 | /// 319 | /// let v: Validated = Good(1).map3(Good(2), Validated::fail("No!"), |a, b, c: u32| a + b + c); 320 | /// assert_eq!(v, Validated::fail("No!")); 321 | /// ``` 322 | pub fn map3(self, vu: Validated, vv: Validated, f: F) -> Validated 323 | where 324 | F: FnOnce(T, U, V) -> Z, 325 | { 326 | match (self, vu, vv) { 327 | (Good(t), Good(u), Good(v)) => Good(f(t, u, v)), 328 | (Good(_), Good(_), Fail(e)) => Fail(e), 329 | (Good(_), Fail(e), Good(_)) => Fail(e), 330 | (Fail(e), Good(_), Good(_)) => Fail(e), 331 | (Good(_), Fail(e0), Fail(e1)) => Fail(nons(e0, Some(e1).into_iter())), 332 | (Fail(e0), Good(_), Fail(e1)) => Fail(nons(e0, Some(e1).into_iter())), 333 | (Fail(e0), Fail(e1), Good(_)) => Fail(nons(e0, Some(e1).into_iter())), 334 | (Fail(e0), Fail(e1), Fail(e2)) => Fail(nons(e0, vec![e1, e2].into_iter())), 335 | } 336 | } 337 | 338 | /// Maps a function over four `Validated`, but only if all four are of the 339 | /// `Good` variant. If any failed, then their errors are concatenated. 340 | pub fn map4( 341 | self, 342 | vu: Validated, 343 | vv: Validated, 344 | vw: Validated, 345 | f: F, 346 | ) -> Validated 347 | where 348 | F: FnOnce(T, U, V, W) -> Z, 349 | { 350 | match (self, vu, vv, vw) { 351 | (Good(t), Good(u), Good(v), Good(w)) => Good(f(t, u, v, w)), 352 | (Good(_), Good(_), Good(_), Fail(e)) => Fail(e), 353 | (Good(_), Good(_), Fail(e), Good(_)) => Fail(e), 354 | (Good(_), Fail(e), Good(_), Good(_)) => Fail(e), 355 | (Fail(e), Good(_), Good(_), Good(_)) => Fail(e), 356 | (Good(_), Good(_), Fail(e0), Fail(e1)) => Fail(nons(e0, Some(e1).into_iter())), 357 | (Good(_), Fail(e0), Good(_), Fail(e1)) => Fail(nons(e0, Some(e1).into_iter())), 358 | (Good(_), Fail(e0), Fail(e1), Good(_)) => Fail(nons(e0, Some(e1).into_iter())), 359 | (Fail(e0), Good(_), Good(_), Fail(e1)) => Fail(nons(e0, Some(e1).into_iter())), 360 | (Fail(e0), Fail(e1), Good(_), Good(_)) => Fail(nons(e0, Some(e1).into_iter())), 361 | (Fail(e0), Good(_), Fail(e1), Good(_)) => Fail(nons(e0, Some(e1).into_iter())), 362 | (Good(_), Fail(e0), Fail(e1), Fail(e2)) => Fail(nons(e0, vec![e1, e2].into_iter())), 363 | (Fail(e0), Good(_), Fail(e1), Fail(e2)) => Fail(nons(e0, vec![e1, e2].into_iter())), 364 | (Fail(e0), Fail(e1), Good(_), Fail(e2)) => Fail(nons(e0, vec![e1, e2].into_iter())), 365 | (Fail(e0), Fail(e1), Fail(e2), Good(_)) => Fail(nons(e0, vec![e1, e2].into_iter())), 366 | (Fail(e0), Fail(e1), Fail(e2), Fail(e3)) => { 367 | Fail(nons(e0, vec![e1, e2, e3].into_iter())) 368 | } 369 | } 370 | } 371 | 372 | /// Converts `self` into a [`Result`]. 373 | pub fn ok(self) -> Result> { 374 | match self { 375 | Good(t) => Ok(t), 376 | Fail(e) => Err(e), 377 | } 378 | } 379 | 380 | /// Returns the contained [`Good`] value, consuming `self`. 381 | /// 382 | /// # Examples 383 | /// 384 | /// ``` 385 | /// use validated::Validated; 386 | /// 387 | /// let v: Validated = Validated::Good(1); 388 | /// assert_eq!(v.unwrap(), 1); 389 | /// ``` 390 | /// 391 | /// # Panics 392 | /// 393 | /// Panics if `self` is actually the `Fail` variant. 394 | pub fn unwrap(self) -> T { 395 | match self { 396 | Good(t) => t, 397 | Fail(_) => panic!("called `Validated::unwrap` on a `Fail` value"), 398 | } 399 | } 400 | 401 | /// Returns the contained [`Good`] value or a provided default. 402 | /// 403 | /// Arguments passed to `unwrap_or` are eagerly evaluated; if you are 404 | /// passing the result of a function call, it is recommended to use 405 | /// [`Validated::unwrap_or_else`] instead. 406 | /// 407 | /// # Examples 408 | /// 409 | /// ``` 410 | /// use validated::Validated; 411 | /// 412 | /// let v: Validated = Validated::Good(1); 413 | /// assert_eq!(v.unwrap_or(2), 1); 414 | /// 415 | /// let v: Validated = Validated::fail("Oh no!"); 416 | /// assert_eq!(v.unwrap_or(2), 2); 417 | /// ``` 418 | pub fn unwrap_or(self, default: T) -> T { 419 | match self { 420 | Good(t) => t, 421 | Fail(_) => default, 422 | } 423 | } 424 | 425 | /// Returns the contained [`Good`] value or computes it from a closure. 426 | pub fn unwrap_or_else(self, op: F) -> T 427 | where 428 | F: FnOnce(NEVec) -> T, 429 | { 430 | match self { 431 | Good(t) => t, 432 | Fail(e) => op(e), 433 | } 434 | } 435 | } 436 | 437 | impl Validated { 438 | /// Returns the contained [`Good`] value or the default for `T`. 439 | pub fn unwrap_or_default(self) -> T { 440 | match self { 441 | Good(t) => t, 442 | Fail(_) => Default::default(), 443 | } 444 | } 445 | } 446 | 447 | impl Validated { 448 | /// Like [`Result::as_deref`]. 449 | pub fn as_deref(&self) -> Validated<&T::Target, &E> { 450 | self.as_ref().map(|t| t.deref()) 451 | } 452 | } 453 | 454 | impl Validated { 455 | /// Like [`Result::as_deref_mut`]. 456 | pub fn as_deref_mut(&mut self) -> Validated<&mut T::Target, &mut E> { 457 | self.as_mut().map(|t| t.deref_mut()) 458 | } 459 | } 460 | 461 | impl From> for Validated { 462 | fn from(r: Result) -> Self { 463 | match r { 464 | Ok(t) => Good(t), 465 | Err(e) => Fail(NEVec::new(e)), 466 | } 467 | } 468 | } 469 | 470 | // FIXME Can't do it... 471 | // impl FromIterator> for Validated { 472 | // fn from_iter>>(iter: I) -> Self { 473 | // todo!() 474 | // } 475 | // } 476 | 477 | impl FromIterator> for Validated 478 | where 479 | U: FromIterator, 480 | { 481 | fn from_iter>>(iter: I) -> Self { 482 | let mut errors = Vec::new(); 483 | 484 | let result = iter 485 | .into_iter() 486 | .filter_map(|item| match item { 487 | Ok(t) => Some(t), 488 | Err(e) => { 489 | errors.push(e); 490 | None 491 | } 492 | }) 493 | .collect(); 494 | 495 | match NEVec::try_from_vec(errors) { 496 | None => Good(result), 497 | Some(e) => Fail(e), 498 | } 499 | } 500 | } 501 | 502 | impl FromIterator> for Validated 503 | where 504 | U: FromIterator, 505 | { 506 | fn from_iter>>(iter: I) -> Self { 507 | let mut errors = Vec::new(); 508 | 509 | let result = iter 510 | .into_iter() 511 | .filter_map(|item| match item { 512 | Good(t) => Some(t), 513 | Fail(e) => { 514 | errors.extend(e); 515 | None 516 | } 517 | }) 518 | .collect(); 519 | 520 | match NEVec::try_from_vec(errors) { 521 | None => Good(result), 522 | Some(e) => Fail(e), 523 | } 524 | } 525 | } 526 | 527 | #[cfg(feature = "rayon")] 528 | impl FromParallelIterator> for Validated 529 | where 530 | T: Send, 531 | E: Send, 532 | U: FromParallelIterator, 533 | { 534 | fn from_par_iter(par_iter: I) -> Validated 535 | where 536 | I: IntoParallelIterator>, 537 | { 538 | let errors = Mutex::new(Vec::new()); 539 | 540 | let result = par_iter 541 | .into_par_iter() 542 | .filter_map(|item| match item { 543 | Ok(t) => Some(t), 544 | Err(e) => { 545 | errors.lock().unwrap().push(e); 546 | None 547 | } 548 | }) 549 | .collect(); 550 | 551 | match NEVec::try_from_vec(errors.into_inner().unwrap()) { 552 | None => Good(result), 553 | Some(e) => Fail(e), 554 | } 555 | } 556 | } 557 | 558 | #[cfg(feature = "rayon")] 559 | impl FromParallelIterator> for Validated 560 | where 561 | T: Send, 562 | E: Send, 563 | U: FromParallelIterator, 564 | { 565 | fn from_par_iter(par_iter: I) -> Validated 566 | where 567 | I: IntoParallelIterator>, 568 | { 569 | let errors = Mutex::new(Vec::new()); 570 | 571 | let result = par_iter 572 | .into_par_iter() 573 | .filter_map(|item| match item { 574 | Good(t) => Some(t), 575 | Fail(e) => { 576 | errors.lock().unwrap().extend(e); 577 | None 578 | } 579 | }) 580 | .collect(); 581 | 582 | match NEVec::try_from_vec(errors.into_inner().unwrap()) { 583 | None => Good(result), 584 | Some(e) => Fail(e), 585 | } 586 | } 587 | } 588 | 589 | impl IntoIterator for Validated { 590 | type Item = T; 591 | type IntoIter = IntoIter; 592 | 593 | fn into_iter(self) -> Self::IntoIter { 594 | IntoIter { 595 | inner: self.ok().ok(), 596 | } 597 | } 598 | } 599 | 600 | impl<'a, T, E> IntoIterator for &'a Validated { 601 | type Item = &'a T; 602 | type IntoIter = Iter<'a, T>; 603 | 604 | fn into_iter(self) -> Iter<'a, T> { 605 | self.iter() 606 | } 607 | } 608 | 609 | impl<'a, T, E> IntoIterator for &'a mut Validated { 610 | type Item = &'a mut T; 611 | type IntoIter = IterMut<'a, T>; 612 | 613 | fn into_iter(self) -> IterMut<'a, T> { 614 | self.iter_mut() 615 | } 616 | } 617 | 618 | impl Sum> for Validated 619 | where 620 | T: Sum, 621 | { 622 | fn sum(iter: I) -> Self 623 | where 624 | I: Iterator>, 625 | { 626 | let mut errors = Vec::new(); 627 | 628 | let result = iter 629 | .filter_map(|item| match item { 630 | Good(n) => Some(n), 631 | Fail(e) => { 632 | errors.extend(e); 633 | None 634 | } 635 | }) 636 | .sum(); 637 | 638 | match NEVec::try_from_vec(errors) { 639 | None => Good(result), 640 | Some(e) => Fail(e), 641 | } 642 | } 643 | } 644 | 645 | /// ``` 646 | /// use validated::Validated; 647 | /// 648 | /// let ns: Validated = [Ok(1), Ok(2), Ok(3)].into_iter().sum(); 649 | /// assert_eq!(Validated::Good(6), ns); 650 | /// ``` 651 | impl Sum> for Validated 652 | where 653 | T: Sum, 654 | { 655 | fn sum(iter: I) -> Self 656 | where 657 | I: Iterator>, 658 | { 659 | let mut errors = Vec::new(); 660 | 661 | let result = iter 662 | .filter_map(|item| match item { 663 | Ok(n) => Some(n), 664 | Err(e) => { 665 | errors.push(e); 666 | None 667 | } 668 | }) 669 | .sum(); 670 | 671 | match NEVec::try_from_vec(errors) { 672 | None => Good(result), 673 | Some(e) => Fail(e), 674 | } 675 | } 676 | } 677 | 678 | /// An iterator over a reference to the [`Good`] variant of a [`Validated`]. 679 | /// 680 | /// The iterator yields one value if the result is [`Good`], otherwise nothing. 681 | /// 682 | /// Created by [`Validated::iter`]. 683 | #[derive(Debug)] 684 | pub struct Iter<'a, T: 'a> { 685 | inner: Option<&'a T>, 686 | } 687 | 688 | impl<'a, T> Iterator for Iter<'a, T> { 689 | type Item = &'a T; 690 | 691 | #[inline] 692 | fn next(&mut self) -> Option { 693 | self.inner.take() 694 | } 695 | 696 | #[inline] 697 | fn size_hint(&self) -> (usize, Option) { 698 | let n = if self.inner.is_some() { 1 } else { 0 }; 699 | (n, Some(n)) 700 | } 701 | } 702 | 703 | impl DoubleEndedIterator for Iter<'_, T> { 704 | #[inline] 705 | fn next_back(&mut self) -> Option { 706 | self.inner.take() 707 | } 708 | } 709 | 710 | impl ExactSizeIterator for Iter<'_, T> {} 711 | 712 | /// An iterator over a mutable reference to the [`Good`] variant of a [`Validated`]. 713 | /// 714 | /// Created by [`Validated::iter_mut`]. 715 | #[derive(Debug)] 716 | pub struct IterMut<'a, T: 'a> { 717 | inner: Option<&'a mut T>, 718 | } 719 | 720 | impl<'a, T> Iterator for IterMut<'a, T> { 721 | type Item = &'a mut T; 722 | 723 | #[inline] 724 | fn next(&mut self) -> Option<&'a mut T> { 725 | self.inner.take() 726 | } 727 | 728 | #[inline] 729 | fn size_hint(&self) -> (usize, Option) { 730 | let n = if self.inner.is_some() { 1 } else { 0 }; 731 | (n, Some(n)) 732 | } 733 | } 734 | 735 | impl DoubleEndedIterator for IterMut<'_, T> { 736 | #[inline] 737 | fn next_back(&mut self) -> Option { 738 | self.inner.take() 739 | } 740 | } 741 | 742 | impl ExactSizeIterator for IterMut<'_, T> {} 743 | 744 | /// An iterator over the value in a [`Good`] variant of a [`Validated`]. 745 | /// 746 | /// The iterator yields one value if the result is [`Good`], otherwise nothing. 747 | /// 748 | /// This struct is created by the [`into_iter`] method on 749 | /// [`Validated`] (provided by the [`IntoIterator`] trait). 750 | /// 751 | /// [`into_iter`]: IntoIterator::into_iter 752 | #[derive(Clone, Debug)] 753 | pub struct IntoIter { 754 | inner: Option, 755 | } 756 | 757 | impl Iterator for IntoIter { 758 | type Item = T; 759 | 760 | #[inline] 761 | fn next(&mut self) -> Option { 762 | self.inner.take() 763 | } 764 | 765 | #[inline] 766 | fn size_hint(&self) -> (usize, Option) { 767 | let n = if self.inner.is_some() { 1 } else { 0 }; 768 | (n, Some(n)) 769 | } 770 | } 771 | 772 | /// Fuse some `NEVec`s together. 773 | fn nons(mut a: NEVec, rest: I) -> NEVec 774 | where 775 | I: Iterator>, 776 | { 777 | for i in rest { 778 | a.extend(i); 779 | } 780 | 781 | a 782 | } 783 | --------------------------------------------------------------------------------