Skip to content

Commit 8dd5527

Browse files
committed
Add CollectVecResult, release 1.1.0
1 parent 1c58495 commit 8dd5527

File tree

6 files changed

+78
-13
lines changed

6 files changed

+78
-13
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ and this project adheres to
99

1010
## \[Unreleased]
1111

12+
## \[1.1.0] - 2024-04-08
13+
14+
### Added
15+
16+
- Iterator trait `CollectVecResult` with method `collect_vec_result`.
17+
1218
## \[1.0.0] - 2024-04-08
1319

1420
Initial release.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "multiple_errors"
3-
version = "1.0.0"
3+
version = "1.1.0"
44
edition = "2021"
55
authors = ["Dmitrii Aleksandrov <adk230@yandex.ru>"]
66
documentation = "https://docs.rs/multiple_errors/"

README.md

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,22 @@ pull request if you need this.
2424
## Example
2525

2626
```rust
27-
use multiple_errors::{fail_all_vec, return_multiple_errors};
27+
use multiple_errors::{fail_all_vec, return_multiple_errors, CollectVecResult};
2828
use multiple_errors::testing_prelude::*;
29-
30-
// fail_all_vec:
29+
30+
assert_eq!(
31+
[Err(ErrA), Ok(A), Err(ErrA)].into_iter().collect_vec_result(),
32+
// Collected all errors, not just the first one
33+
Err(vec![ErrA, ErrA])
34+
);
3135

3236
let err = fail_all_vec(
3337
vec![Ok(A), Err(ErrA), Ok(A)],
3438
|res| res.err().map(HighLevelErr::from).unwrap_or(HighLevelErr::B(ErrB))
3539
);
40+
// Same length as the original, each element turned into an error.
3641
assert_eq!(err, Err(vec![ErrB.into(), ErrA.into(), ErrB.into()]));
3742

38-
let ok = fail_all_vec(vec![Ok(A), Ok(A)], |_: Result<_, ErrA>| ErrC);
39-
assert_eq!(ok, Ok(vec![A, A]));
40-
41-
// return_multiple_errors:
42-
4343
fn a_b_c() -> Result<(A, B, C), Vec<HighLevelErr>> {
4444
return_multiple_errors!(
4545
let mut errors: Vec<HighLevelErr> = vec![];
@@ -74,7 +74,11 @@ fn a_b_c() -> Result<(A, B, C), Vec<HighLevelErr>> {
7474
> Partition a sequence of Results into one list of all the Ok elements and
7575
> another list of all the Err elements.
7676
77-
This is often useful, use `itertools` for this.
77+
If you need both lists, just use
78+
[itertools](https://github.com/rust-itertools/itertools). If you discard
79+
`Ok`s in case of errors, you can use
80+
`CollectVecResult::collect_vec_result()` that returns
81+
`Result<Vec<T>, Vec<E>>`. It's more precise and efficient.
7882

7983
## License
8084

src/collect.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/// Provides `collect_vec_result() -> Result<Vec<T>, Vec<E>>`
2+
pub trait CollectVecResult: Iterator<Item = Result<Self::T, Self::E>> {
3+
type T;
4+
type E;
5+
/// Like standard `Iterator::collect::<Result<Vec<T>, E>>`, but all errors
6+
/// instead of just the first one.
7+
///
8+
/// Doesn't short-circuit, always exhausts the iterator.
9+
///
10+
/// ## Examples
11+
///
12+
/// ```rust
13+
/// # use multiple_errors::testing_prelude::*;
14+
/// # use multiple_errors::CollectVecResult;
15+
/// #
16+
/// assert_eq!(
17+
/// [Err(ErrA), Ok(A), Err(ErrA)].into_iter().collect_vec_result(),
18+
/// // Collected all errors, not just the first one
19+
/// Err(vec![ErrA, ErrA])
20+
/// );
21+
/// ```
22+
fn collect_vec_result(self) -> Result<Vec<Self::T>, Vec<Self::E>>;
23+
}
24+
25+
impl<I, T, E> CollectVecResult for I
26+
where
27+
I: Iterator<Item = Result<T, E>>,
28+
{
29+
type T = T;
30+
type E = E;
31+
fn collect_vec_result(self) -> Result<Vec<Self::T>, Vec<Self::E>> {
32+
let mut oks = vec![];
33+
let mut errs = vec![];
34+
for elem in self {
35+
match elem {
36+
Err(err) => errs.push(err),
37+
Ok(ok) => {
38+
// Don't grow `oks` if we already know that we'll discard it.
39+
if errs.is_empty() {
40+
oks.push(ok)
41+
}
42+
}
43+
}
44+
}
45+
match errs.as_slice() {
46+
[] => Ok(oks),
47+
[_, ..] => Err(errs),
48+
}
49+
}
50+
}

src/fail_all.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
/// [Ok(A), Err(ErrA), Ok(A)],
3535
/// |res| res.err().map(HighLevelErr::from).unwrap_or(HighLevelErr::B(ErrB))
3636
/// );
37+
/// // Each element turned into an error.
3738
/// assert_eq!(err, Err([ErrB.into(), ErrA.into(), ErrB.into()]));
3839
/// ```
3940
pub fn fail_all<I, T, E1, E2, F>(
@@ -72,10 +73,11 @@ where
7273
/// vec![Ok(A), Err(ErrA), Ok(A)],
7374
/// |res| res.err().map(HighLevelErr::from).unwrap_or(HighLevelErr::B(ErrB))
7475
/// );
76+
/// // Same length as the original, each element turned into an error.
7577
/// assert_eq!(err, Err(vec![ErrB.into(), ErrA.into(), ErrB.into()]));
76-
///
77-
/// let ok = fail_all_vec(vec![Ok(A), Ok(A)], |_: Result<_, ErrA>| ErrC);
78-
/// assert_eq!(ok, Ok(vec![A, A]));
78+
/// #
79+
/// # let ok = fail_all_vec(vec![Ok(A), Ok(A)], |_: Result<_, ErrA>| ErrC);
80+
/// # assert_eq!(ok, Ok(vec![A, A]));
7981
/// ```
8082
pub fn fail_all_vec<T, E1, E2, F>(results: Vec<Result<T, E1>>, f: F) -> Result<Vec<T>, Vec<E2>>
8183
where

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
#[doc(hidden)]
44
pub mod testing_prelude;
55

6+
mod collect;
7+
pub use collect::CollectVecResult;
8+
69
mod fail_all;
710
pub use fail_all::{fail_all, fail_all_vec};
811

0 commit comments

Comments
 (0)