mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
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`.
This commit is contained in:
parent
7bffede97c
commit
23715d344d
@ -670,6 +670,87 @@ macro_rules! float_sum_product {
|
||||
integer_sum_product! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }
|
||||
float_sum_product! { f32 f64 }
|
||||
|
||||
/// An iterator adapter that produces output as long as the underlying
|
||||
/// iterator produces `Result::Ok` values.
|
||||
///
|
||||
/// If an error is encountered, the iterator stops and the error is
|
||||
/// stored. The error may be recovered later via `reconstruct`.
|
||||
struct ResultShunt<I, E> {
|
||||
iter: I,
|
||||
error: Option<E>,
|
||||
}
|
||||
|
||||
impl<I, T, E> ResultShunt<I, E>
|
||||
where I: Iterator<Item = Result<T, E>>
|
||||
{
|
||||
/// Process the given iterator as if it yielded a `T` instead of a
|
||||
/// `Result<T, _>`. Any errors will stop the inner iterator and
|
||||
/// the overall result will be an error.
|
||||
pub fn process<F, U>(iter: I, mut f: F) -> Result<U, E>
|
||||
where F: FnMut(&mut Self) -> U
|
||||
{
|
||||
let mut shunt = ResultShunt::new(iter);
|
||||
let value = f(shunt.by_ref());
|
||||
shunt.reconstruct(value)
|
||||
}
|
||||
|
||||
fn new(iter: I) -> Self {
|
||||
ResultShunt {
|
||||
iter: iter,
|
||||
error: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Consume the adapter and rebuild a `Result` value. This should
|
||||
/// *always* be called, otherwise any potential error would be
|
||||
/// lost.
|
||||
fn reconstruct<U>(self, val: U) -> Result<U, E> {
|
||||
match self.error {
|
||||
None => Ok(val),
|
||||
Some(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T, E> Iterator for ResultShunt<I, E>
|
||||
where I: Iterator<Item = Result<T, E>>
|
||||
{
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.iter.next() {
|
||||
Some(Ok(v)) => Some(v),
|
||||
Some(Err(e)) => {
|
||||
self.error = Some(e);
|
||||
None
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "iter_arith_traits_result", since="1.16.0")]
|
||||
impl<T, U, E> Sum<Result<U, E>> for Result<T, E>
|
||||
where T: Sum<U>,
|
||||
{
|
||||
fn sum<I>(iter: I) -> Result<T, E>
|
||||
where I: Iterator<Item = Result<U, E>>,
|
||||
{
|
||||
ResultShunt::process(iter, |i| i.sum())
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "iter_arith_traits_result", since="1.16.0")]
|
||||
impl<T, U, E> Product<Result<U, E>> for Result<T, E>
|
||||
where T: Product<U>,
|
||||
{
|
||||
fn product<I>(iter: I) -> Result<T, E>
|
||||
where I: Iterator<Item = Result<U, E>>,
|
||||
{
|
||||
ResultShunt::process(iter, |i| i.product())
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator that always continues to yield `None` when exhausted.
|
||||
///
|
||||
/// Calling next on a fused iterator that has returned `None` once is guaranteed
|
||||
|
@ -614,6 +614,14 @@ fn test_iterator_sum() {
|
||||
assert_eq!(v[..0].iter().cloned().sum::<i32>(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_sum_result() {
|
||||
let v: &[Result<i32, ()>] = &[Ok(1), Ok(2), Ok(3), Ok(4)];
|
||||
assert_eq!(v.iter().cloned().sum::<Result<i32, _>>(), Ok(10));
|
||||
let v: &[Result<i32, ()>] = &[Ok(1), Err(()), Ok(3), Ok(4)];
|
||||
assert_eq!(v.iter().cloned().sum::<Result<i32, _>>(), Err(()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_product() {
|
||||
let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||
@ -622,6 +630,14 @@ fn test_iterator_product() {
|
||||
assert_eq!(v[..0].iter().cloned().product::<i32>(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_product_result() {
|
||||
let v: &[Result<i32, ()>] = &[Ok(1), Ok(2), Ok(3), Ok(4)];
|
||||
assert_eq!(v.iter().cloned().product::<Result<i32, _>>(), Ok(24));
|
||||
let v: &[Result<i32, ()>] = &[Ok(1), Err(()), Ok(3), Ok(4)];
|
||||
assert_eq!(v.iter().cloned().product::<Result<i32, _>>(), Err(()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_max() {
|
||||
let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||
|
Loading…
Reference in New Issue
Block a user