aboutsummaryrefslogtreecommitdiff
path: root/src/result.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/result.rs')
-rw-r--r--src/result.rs132
1 files changed, 132 insertions, 0 deletions
diff --git a/src/result.rs b/src/result.rs
new file mode 100644
index 0000000..43685ca
--- /dev/null
+++ b/src/result.rs
@@ -0,0 +1,132 @@
+//! 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<T: Send> {
+ inner: option::IntoIter<T>,
+}
+
+impl<T: Send, E> IntoParallelIterator for Result<T, E> {
+ type Item = T;
+ type Iter = IntoIter<T>;
+
+ fn into_par_iter(self) -> Self::Iter {
+ IntoIter {
+ inner: self.ok().into_par_iter(),
+ }
+ }
+}
+
+delegate_indexed_iterator! {
+ IntoIter<T> => T,
+ impl<T: Send>
+}
+
+/// 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<T, E> {
+ 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<T, E> {
+ 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<C, T, E> FromParallelIterator<Result<T, E>> for Result<C, E>
+where
+ C: FromParallelIterator<T>,
+ T: Send,
+ E: Send,
+{
+ fn from_par_iter<I>(par_iter: I) -> Self
+ where
+ I: IntoParallelIterator<Item = Result<T, E>>,
+ {
+ fn ok<T, E>(saved: &Mutex<Option<E>>) -> impl Fn(Result<T, E>) -> Option<T> + '_ {
+ 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),
+ }
+ }
+}