Skip to content

Commit 0500fbf

Browse files
committed
Auto merge of #38580 - shepmaster:result-sum, r=alexcrichton
Implement `iter::Sum` and `iter::Product` for `Result` This introduces a private iterator adapter `ResultShunt`, which allows treating an iterator of `Result<T, E>` as an iterator of `T`.
2 parents d6b927d + 23715d3 commit 0500fbf

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed

src/libcore/iter/traits.rs

+81
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,87 @@ macro_rules! float_sum_product {
670670
integer_sum_product! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }
671671
float_sum_product! { f32 f64 }
672672

673+
/// An iterator adapter that produces output as long as the underlying
674+
/// iterator produces `Result::Ok` values.
675+
///
676+
/// If an error is encountered, the iterator stops and the error is
677+
/// stored. The error may be recovered later via `reconstruct`.
678+
struct ResultShunt<I, E> {
679+
iter: I,
680+
error: Option<E>,
681+
}
682+
683+
impl<I, T, E> ResultShunt<I, E>
684+
where I: Iterator<Item = Result<T, E>>
685+
{
686+
/// Process the given iterator as if it yielded a `T` instead of a
687+
/// `Result<T, _>`. Any errors will stop the inner iterator and
688+
/// the overall result will be an error.
689+
pub fn process<F, U>(iter: I, mut f: F) -> Result<U, E>
690+
where F: FnMut(&mut Self) -> U
691+
{
692+
let mut shunt = ResultShunt::new(iter);
693+
let value = f(shunt.by_ref());
694+
shunt.reconstruct(value)
695+
}
696+
697+
fn new(iter: I) -> Self {
698+
ResultShunt {
699+
iter: iter,
700+
error: None,
701+
}
702+
}
703+
704+
/// Consume the adapter and rebuild a `Result` value. This should
705+
/// *always* be called, otherwise any potential error would be
706+
/// lost.
707+
fn reconstruct<U>(self, val: U) -> Result<U, E> {
708+
match self.error {
709+
None => Ok(val),
710+
Some(e) => Err(e),
711+
}
712+
}
713+
}
714+
715+
impl<I, T, E> Iterator for ResultShunt<I, E>
716+
where I: Iterator<Item = Result<T, E>>
717+
{
718+
type Item = T;
719+
720+
fn next(&mut self) -> Option<Self::Item> {
721+
match self.iter.next() {
722+
Some(Ok(v)) => Some(v),
723+
Some(Err(e)) => {
724+
self.error = Some(e);
725+
None
726+
}
727+
None => None,
728+
}
729+
}
730+
}
731+
732+
#[stable(feature = "iter_arith_traits_result", since="1.16.0")]
733+
impl<T, U, E> Sum<Result<U, E>> for Result<T, E>
734+
where T: Sum<U>,
735+
{
736+
fn sum<I>(iter: I) -> Result<T, E>
737+
where I: Iterator<Item = Result<U, E>>,
738+
{
739+
ResultShunt::process(iter, |i| i.sum())
740+
}
741+
}
742+
743+
#[stable(feature = "iter_arith_traits_result", since="1.16.0")]
744+
impl<T, U, E> Product<Result<U, E>> for Result<T, E>
745+
where T: Product<U>,
746+
{
747+
fn product<I>(iter: I) -> Result<T, E>
748+
where I: Iterator<Item = Result<U, E>>,
749+
{
750+
ResultShunt::process(iter, |i| i.product())
751+
}
752+
}
753+
673754
/// An iterator that always continues to yield `None` when exhausted.
674755
///
675756
/// Calling next on a fused iterator that has returned `None` once is guaranteed

src/libcoretest/iter.rs

+16
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,14 @@ fn test_iterator_sum() {
614614
assert_eq!(v[..0].iter().cloned().sum::<i32>(), 0);
615615
}
616616

617+
#[test]
618+
fn test_iterator_sum_result() {
619+
let v: &[Result<i32, ()>] = &[Ok(1), Ok(2), Ok(3), Ok(4)];
620+
assert_eq!(v.iter().cloned().sum::<Result<i32, _>>(), Ok(10));
621+
let v: &[Result<i32, ()>] = &[Ok(1), Err(()), Ok(3), Ok(4)];
622+
assert_eq!(v.iter().cloned().sum::<Result<i32, _>>(), Err(()));
623+
}
624+
617625
#[test]
618626
fn test_iterator_product() {
619627
let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
@@ -622,6 +630,14 @@ fn test_iterator_product() {
622630
assert_eq!(v[..0].iter().cloned().product::<i32>(), 1);
623631
}
624632

633+
#[test]
634+
fn test_iterator_product_result() {
635+
let v: &[Result<i32, ()>] = &[Ok(1), Ok(2), Ok(3), Ok(4)];
636+
assert_eq!(v.iter().cloned().product::<Result<i32, _>>(), Ok(24));
637+
let v: &[Result<i32, ()>] = &[Ok(1), Err(()), Ok(3), Ok(4)];
638+
assert_eq!(v.iter().cloned().product::<Result<i32, _>>(), Err(()));
639+
}
640+
625641
#[test]
626642
fn test_iterator_max() {
627643
let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

0 commit comments

Comments
 (0)