//! Parallel iterator types for [results][std::result] //! //! You will rarely need to interact with this module directly unless you need //! to name one of the iterator types. //! //! [std::result]: https://doc.rust-lang.org/stable/std/result/ use crate::iter::plumbing::*; use crate::iter::*; use std::sync::Mutex; use crate::option; /// Parallel iterator over a result #[derive(Debug, Clone)] pub struct IntoIter { inner: option::IntoIter, } impl IntoParallelIterator for Result { type Item = T; type Iter = IntoIter; fn into_par_iter(self) -> Self::Iter { IntoIter { inner: self.ok().into_par_iter(), } } } delegate_indexed_iterator! { IntoIter => T, impl } /// Parallel iterator over an immutable reference to a result #[derive(Debug)] pub struct Iter<'a, T: Sync> { inner: option::IntoIter<&'a T>, } impl<'a, T: Sync> Clone for Iter<'a, T> { fn clone(&self) -> Self { Iter { inner: self.inner.clone(), } } } impl<'a, T: Sync, E> IntoParallelIterator for &'a Result { type Item = &'a T; type Iter = Iter<'a, T>; fn into_par_iter(self) -> Self::Iter { Iter { inner: self.as_ref().ok().into_par_iter(), } } } delegate_indexed_iterator! { Iter<'a, T> => &'a T, impl<'a, T: Sync + 'a> } /// Parallel iterator over a mutable reference to a result #[derive(Debug)] pub struct IterMut<'a, T: Send> { inner: option::IntoIter<&'a mut T>, } impl<'a, T: Send, E> IntoParallelIterator for &'a mut Result { type Item = &'a mut T; type Iter = IterMut<'a, T>; fn into_par_iter(self) -> Self::Iter { IterMut { inner: self.as_mut().ok().into_par_iter(), } } } delegate_indexed_iterator! { IterMut<'a, T> => &'a mut T, impl<'a, T: Send + 'a> } /// Collect an arbitrary `Result`-wrapped collection. /// /// If any item is `Err`, then all previous `Ok` items collected are /// discarded, and it returns that error. If there are multiple errors, the /// one returned is not deterministic. impl FromParallelIterator> for Result where C: FromParallelIterator, T: Send, E: Send, { fn from_par_iter(par_iter: I) -> Self where I: IntoParallelIterator>, { fn ok(saved: &Mutex>) -> impl Fn(Result) -> Option + '_ { move |item| match item { Ok(item) => Some(item), Err(error) => { // We don't need a blocking `lock()`, as anybody // else holding the lock will also be writing // `Some(error)`, and then ours is irrelevant. if let Ok(mut guard) = saved.try_lock() { if guard.is_none() { *guard = Some(error); } } None } } } let saved_error = Mutex::new(None); let collection = par_iter .into_par_iter() .map(ok(&saved_error)) .while_some() .collect(); match saved_error.into_inner().unwrap() { Some(error) => Err(error), None => Ok(collection), } } }