first-err
Find the first Err in Iterator<Result<T, E>> and allow continuous iteration.
This crate is specifically designed to replace the following pattern without allocation:
// iter: impl Iterator<Result<T, E>>
iter.collect::<Result<Vec<T>, E>>().map(|vec| vec.into_iter().foo() );
Features
- Find first
ErrinIterator<Result<T, E>>and allow to iterating continuously. - Speed: Roughly on par with a hand-written loop, using lazy evaluation and without allocation.
- Minimized: no
std, noalloc, no dependency.
Getting Started
use FirstErr;
// Everything is Ok.
let result =
.into_iter
.first_err_or_else;
assert_eq!;
// Contains some `Err` values.
let result =
.into_iter
.first_err_or_else;
assert_eq!;
Why
In Rust, I frequently encounter a pattern where I need to perform actions on all items within an iterator, and halt immediately if any error is detected in the layer I'm working on. But if no error found, the iterator should able to run continuously and allow me to do further transform.
The pattern typically looks as follows:
let array: = ;
let result = fallible_sum;
assert_eq!;
In theory, this allocation is not necessary. We can just write that code as an old good loop:
let array: = ;
let result = fallible_sum;
assert_eq!
Using a loop is not bad at all. However, in some situations, maintaining a chainable iterator is preferable.
Furthermore, some scenarios may not be as simple as the previous example. Consider this one:
// The second layer `Result` is usually created by further transform after the first layer
// `Result` be processed. But for the sake of simplicity, we've just use pre-defined values.
let array: = ;
let result = fallible_sum;
assert_eq!;
Implementing the above logic in a loop without allocation may be error-prone and complicated. This crate simplifies that for you:
let array: = ;
let result = fallible_sum;
assert_eq!;
Benchmark
The performance of this crate is designed to be roughly on par with hand-written loops. However, the compiler might apply different optimizations in various situations, and favoring one approach over the others.
If you want to to do a benchmark by yourself, use the following command:
Also, don't forget to check the actual code that is used for benchmarking, which is in the
benches folder.
Environment
- cpu: AMD Ryzen 5 3600 6-Core Processor
- os: Debian GNU/Linux 12 (bookworm)
- kernel: Linux 6.1.0-10-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.38-1 (2023-07-14)
- rustc: 1.72.0 (5680fa18f 2023-08-23)
- cargo: 1.72.0 (103a7ff2e 2023-08-15)
- first-err: v0.1.0
- date: 2023-10-21
Results
test bench_100000_err_at_0______/__collect ... bench: 13 ns/iter (+/- 0)
test bench_100000_err_at_0______/_____loop ... bench: 1 ns/iter (+/- 0)
test bench_100000_err_at_0______/first_err ... bench: 1 ns/iter (+/- 0)
test bench_100000_err_at_1______/__collect ... bench: 19 ns/iter (+/- 0)
test bench_100000_err_at_1______/_____loop ... bench: 2 ns/iter (+/- 0)
test bench_100000_err_at_1______/first_err ... bench: 2 ns/iter (+/- 0)
test bench_100000_err_at_10_____/__collect ... bench: 82 ns/iter (+/- 1)
test bench_100000_err_at_10_____/_____loop ... bench: 3 ns/iter (+/- 0)
test bench_100000_err_at_10_____/first_err ... bench: 3 ns/iter (+/- 0)
test bench_100000_err_at_100____/__collect ... bench: 276 ns/iter (+/- 3)
test bench_100000_err_at_100____/_____loop ... bench: 9 ns/iter (+/- 0)
test bench_100000_err_at_100____/first_err ... bench: 7 ns/iter (+/- 0)
test bench_100000_err_at_1000___/__collect ... bench: 1027 ns/iter (+/- 39)
test bench_100000_err_at_1000___/_____loop ... bench: 66 ns/iter (+/- 1)
test bench_100000_err_at_1000___/first_err ... bench: 60 ns/iter (+/- 0)
test bench_100000_err_at_10000__/__collect ... bench: 6168 ns/iter (+/- 149)
test bench_100000_err_at_10000__/_____loop ... bench: 604 ns/iter (+/- 10)
test bench_100000_err_at_10000__/first_err ... bench: 605 ns/iter (+/- 1)
test bench_100000_err_at_99999__/__collect ... bench: 57075 ns/iter (+/- 344)
test bench_100000_err_at_99999__/_____loop ... bench: 5985 ns/iter (+/- 19)
test bench_100000_err_at_99999__/first_err ... bench: 5980 ns/iter (+/- 11)
test bench_100000_err_at_100000_/__collect ... bench: 60171 ns/iter (+/- 4611)
test bench_100000_err_at_100000_/_____loop ... bench: 5982 ns/iter (+/- 8)
test bench_100000_err_at_100000_/first_err ... bench: 5987 ns/iter (+/- 33)
test bench_100000_err_not_exists/__collect ... bench: 58460 ns/iter (+/- 343)
test bench_100000_err_not_exists/_____loop ... bench: 1 ns/iter (+/- 0)
test bench_100000_err_not_exists/first_err ... bench: 1 ns/iter (+/- 0)
test bench_100000_l1_err_at_0_______l2_err_at_1000___/__collect ... bench: 14 ns/iter (+/- 0)
test bench_100000_l1_err_at_0_______l2_err_at_1000___/_____loop ... bench: 3 ns/iter (+/- 0)
test bench_100000_l1_err_at_0_______l2_err_at_1000___/first_err ... bench: 6 ns/iter (+/- 0)
test bench_100000_l1_err_at_1_______l2_err_at_1000___/__collect ... bench: 21 ns/iter (+/- 0)
test bench_100000_l1_err_at_1_______l2_err_at_1000___/_____loop ... bench: 3 ns/iter (+/- 0)
test bench_100000_l1_err_at_1_______l2_err_at_1000___/first_err ... bench: 6 ns/iter (+/- 0)
test bench_100000_l1_err_at_10______l2_err_at_1000___/__collect ... bench: 95 ns/iter (+/- 1)
test bench_100000_l1_err_at_10______l2_err_at_1000___/_____loop ... bench: 13 ns/iter (+/- 0)
test bench_100000_l1_err_at_10______l2_err_at_1000___/first_err ... bench: 10 ns/iter (+/- 0)
test bench_100000_l1_err_at_100_____l2_err_at_1000___/__collect ... bench: 362 ns/iter (+/- 3)
test bench_100000_l1_err_at_100_____l2_err_at_1000___/_____loop ... bench: 110 ns/iter (+/- 2)
test bench_100000_l1_err_at_100_____l2_err_at_1000___/first_err ... bench: 72 ns/iter (+/- 0)
test bench_100000_l1_err_at_1000____l2_err_at_1000___/__collect ... bench: 1319 ns/iter (+/- 14)
test bench_100000_l1_err_at_1000____l2_err_at_1000___/_____loop ... bench: 1020 ns/iter (+/- 15)
test bench_100000_l1_err_at_1000____l2_err_at_1000___/first_err ... bench: 626 ns/iter (+/- 6)
test bench_100000_l1_err_at_10000___l2_err_at_1000___/__collect ... bench: 9883 ns/iter (+/- 633)
test bench_100000_l1_err_at_10000___l2_err_at_1000___/_____loop ... bench: 1115 ns/iter (+/- 5)
test bench_100000_l1_err_at_10000___l2_err_at_1000___/first_err ... bench: 774 ns/iter (+/- 52)
test bench_100000_l1_err_at_99999___l2_err_at_1000___/__collect ... bench: 94787 ns/iter (+/- 330)
test bench_100000_l1_err_at_99999___l2_err_at_1000___/_____loop ... bench: 1780 ns/iter (+/- 4)
test bench_100000_l1_err_at_99999___l2_err_at_1000___/first_err ... bench: 2123 ns/iter (+/- 5)
test bench_100000_l1_err_at_100000__l2_err_at_1000___/__collect ... bench: 96160 ns/iter (+/- 161)
test bench_100000_l1_err_at_100000__l2_err_at_1000___/_____loop ... bench: 1787 ns/iter (+/- 3)
test bench_100000_l1_err_at_100000__l2_err_at_1000___/first_err ... bench: 2118 ns/iter (+/- 123)
test bench_100000_l1_err_at_none____l2_err_at_0______/__collect ... bench: 89359 ns/iter (+/- 309)
test bench_100000_l1_err_at_none____l2_err_at_0______/_____loop ... bench: 3 ns/iter (+/- 0)
test bench_100000_l1_err_at_none____l2_err_at_0______/first_err ... bench: 6 ns/iter (+/- 0)
test bench_100000_l1_err_at_none____l2_err_at_1______/__collect ... bench: 89247 ns/iter (+/- 211)
test bench_100000_l1_err_at_none____l2_err_at_1______/_____loop ... bench: 4 ns/iter (+/- 0)
test bench_100000_l1_err_at_none____l2_err_at_1______/first_err ... bench: 6 ns/iter (+/- 0)
test bench_100000_l1_err_at_none____l2_err_at_10_____/__collect ... bench: 89375 ns/iter (+/- 131)
test bench_100000_l1_err_at_none____l2_err_at_10_____/_____loop ... bench: 13 ns/iter (+/- 0)
test bench_100000_l1_err_at_none____l2_err_at_10_____/first_err ... bench: 11 ns/iter (+/- 0)
test bench_100000_l1_err_at_none____l2_err_at_100____/__collect ... bench: 89231 ns/iter (+/- 161)
test bench_100000_l1_err_at_none____l2_err_at_100____/_____loop ... bench: 106 ns/iter (+/- 0)
test bench_100000_l1_err_at_none____l2_err_at_100____/first_err ... bench: 73 ns/iter (+/- 2)
test bench_100000_l1_err_at_none____l2_err_at_1000___/__collect ... bench: 89982 ns/iter (+/- 84)
test bench_100000_l1_err_at_none____l2_err_at_1000___/_____loop ... bench: 966 ns/iter (+/- 0)
test bench_100000_l1_err_at_none____l2_err_at_1000___/first_err ... bench: 616 ns/iter (+/- 3)
test bench_100000_l1_err_at_none____l2_err_at_10000__/__collect ... bench: 96578 ns/iter (+/- 352)
test bench_100000_l1_err_at_none____l2_err_at_10000__/_____loop ... bench: 9569 ns/iter (+/- 47)
test bench_100000_l1_err_at_none____l2_err_at_10000__/first_err ... bench: 6058 ns/iter (+/- 8)
test bench_100000_l1_err_at_none____l2_err_at_99999__/__collect ... bench: 173763 ns/iter (+/- 646)
test bench_100000_l1_err_at_none____l2_err_at_99999__/_____loop ... bench: 95541 ns/iter (+/- 490)
test bench_100000_l1_err_at_none____l2_err_at_99999__/first_err ... bench: 60196 ns/iter (+/- 539)
test bench_100000_l1_err_at_none____l2_err_at_100000_/__collect ... bench: 167568 ns/iter (+/- 1418)
test bench_100000_l1_err_at_none____l2_err_at_100000_/_____loop ... bench: 95596 ns/iter (+/- 178)
test bench_100000_l1_err_at_none____l2_err_at_100000_/first_err ... bench: 50250 ns/iter (+/- 3401)
test bench_100000_err_not_exists_____________________/__collect ... bench: 182434 ns/iter (+/- 1666)
test bench_100000_err_not_exists_____________________/_____loop ... bench: 95634 ns/iter (+/- 82)
test bench_100000_err_not_exists_____________________/first_err ... bench: 5 ns/iter (+/- 0)
Licence
MIT